쿠버네티스에서 애플리케이션을 운영하다 보면 결국 외부 트래픽을 어떻게 Pod까지 전달할지 고민하게 됩니다. Pod는 여러 개로 늘어날 수 있고, 장애가 나면 다시 생성되며, 배포 과정에서도 계속 바뀝니다. 이런 환경에서 특정 Pod 하나를 직접 바라보는 방식은 안정적이지 않습니다.

그래서 쿠버네티스에서는 Service를 통해 Pod 앞에 고정된 진입점을 만들고, 필요에 따라 LoadBalancer나 Ingress를 붙여 외부 트래픽을 받아들입니다. 이 글에서는 쿠버네티스 환경에서 부하분산이 어떤 흐름으로 동작하는지, 특히 클라우드 환경에서 LoadBalancer 타입 Service가 어떻게 사용되는지 정리해보겠습니다.

핵심은 단순합니다. 사용자는 고정된 주소로 접근하고, 쿠버네티스는 그 요청을 현재 살아있는 Pod 중 하나로 전달합니다.

왜 부하분산이 필요한가

쿠버네티스에서 Pod는 고정된 서버라기보다 언제든 교체될 수 있는 실행 단위에 가깝습니다. 새로운 버전을 배포하면 기존 Pod가 내려가고 새 Pod가 올라옵니다. 장애가 발생해도 Pod는 다시 생성됩니다. 이때 Pod IP도 함께 바뀔 수 있습니다.

만약 사용자가 특정 Pod IP로 직접 접근하고 있었다면, Pod가 재시작되는 순간 연결이 깨질 수 있습니다. 그래서 쿠버네티스는 Pod 앞단에 Service라는 추상 계층을 둡니다. Service는 여러 Pod를 하나의 고정된 접점으로 묶어주고, 요청을 적절한 Pod로 전달합니다.

쿠버네티스 부하분산의 기본 흐름

가장 기본적인 흐름은 다음과 같습니다.

  1. 사용자가 애플리케이션 주소로 요청을 보냅니다.
  2. 외부 로드밸런서 또는 Ingress가 요청을 받습니다.
  3. 요청은 쿠버네티스 Service로 전달됩니다.
  4. Service는 연결된 Pod 목록 중 하나로 트래픽을 보냅니다.
  5. Pod가 요청을 처리하고 응답을 반환합니다.

이 흐름에서 중요한 점은 사용자가 Pod를 직접 알 필요가 없다는 것입니다. 사용자는 외부 주소만 알고 있으면 되고, Pod가 몇 개든, 어떤 Node 위에 떠 있든, 중간의 Service와 로드밸런싱 계층이 알아서 연결해줍니다.

Service가 먼저입니다

쿠버네티스 부하분산을 이해할 때 가장 먼저 봐야 하는 것은 Service입니다. LoadBalancer나 Ingress도 결국 내부적으로는 Service를 바라보는 경우가 많습니다.

개념 역할 접근 범위
ClusterIP 클러스터 내부에서 사용할 고정 IP를 제공합니다. 클러스터 내부
NodePort 각 Node의 특정 포트를 열어 외부 접근을 가능하게 합니다. Node IP와 NodePort
LoadBalancer 클라우드 로드밸런서를 생성해 외부 트래픽을 받습니다. 외부 IP 또는 DNS
Ingress HTTP/HTTPS 요청을 도메인과 경로 기준으로 라우팅합니다. 외부 HTTP/HTTPS

여기서 ClusterIP는 기본값입니다. 별도로 타입을 지정하지 않으면 Service는 ClusterIP로 만들어집니다. 이 경우 클러스터 내부에서는 접근할 수 있지만 외부 사용자는 직접 접근할 수 없습니다.

LoadBalancer 타입 Service

외부 사용자가 직접 접근해야 하는 서비스라면 LoadBalancer 타입을 사용할 수 있습니다. 클라우드 환경에서는 이 타입을 만들면 클라우드 제공자의 로드밸런서가 자동으로 생성됩니다. AWS라면 ELB 계열 리소스가 생성되는 식입니다.

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

위 예시에서 외부 사용자는 로드밸런서의 주소로 접근합니다. Service는 80번 포트로 요청을 받고, 실제 Pod의 8080번 포트로 트래픽을 전달합니다. 사용자는 Pod가 몇 개인지, 어떤 Node에 떠 있는지 알 필요가 없습니다.

AWS 기준으로 보는 요청 흐름

AWS 환경에서 LoadBalancer 타입 Service를 만들면 대략 다음과 같은 흐름으로 트래픽이 이동합니다.

사용자 → AWS Load Balancer → Kubernetes Node → Service → Pod

조금 더 풀어보면 다음과 같습니다.

  1. 사용자가 로드밸런서 DNS로 요청을 보냅니다.
  2. AWS Load Balancer가 요청을 받을 Node를 선택합니다.
  3. Node로 들어온 요청은 kube-proxy 규칙을 통해 Service로 연결됩니다.
  4. Service는 selector에 매칭되는 Pod 중 하나를 선택합니다.
  5. 선택된 Pod가 요청을 처리합니다.

여기서 kube-proxy는 Service IP와 실제 Pod IP 사이의 연결 규칙을 관리합니다. 구현 방식은 iptables, IPVS 등으로 달라질 수 있지만, 큰 흐름은 Service로 들어온 트래픽을 실제 Pod로 보내는 것입니다.

port, targetPort, nodePort 차이

Service를 처음 볼 때 가장 헷갈리는 부분이 포트 이름입니다. 비슷해 보이지만 각각 바라보는 위치가 다릅니다.

이름 의미 예시
port Service가 노출하는 포트입니다. Service의 80번 포트
targetPort Pod 내부 컨테이너가 실제로 사용하는 포트입니다. 컨테이너의 8080번 포트
nodePort Node 외부에서 접근할 수 있도록 열리는 포트입니다. 30080번 포트

예를 들어 port: 80, targetPort: 8080이라면 Service는 80번 포트로 요청을 받고, 뒤쪽 Pod의 8080번 포트로 전달합니다. 실제 애플리케이션이 8080번에서 떠 있더라도 외부에서는 80번으로 접근할 수 있게 되는 것입니다.

NodePort와 LoadBalancer의 관계

LoadBalancer 타입을 사용하면 내부적으로 NodePort가 함께 만들어지는 경우가 많습니다. 클라우드 로드밸런서는 각 Node의 NodePort로 트래픽을 전달하고, 쿠버네티스는 그 요청을 다시 적절한 Pod로 보냅니다.

다만 사용자가 직접 NodePort를 기억해서 접근하는 구조는 운영 환경에서 관리가 불편합니다. Node가 바뀔 수 있고, 포트도 사람이 보기 좋은 형태가 아니기 때문입니다. 그래서 운영 환경에서는 보통 LoadBalancer의 DNS나 Ingress의 도메인을 앞단에 둡니다.

Ingress는 언제 사용할까

LoadBalancer Service는 외부 트래픽을 받기에는 편하지만, 서비스가 많아질수록 로드밸런서도 계속 늘어날 수 있습니다. 예를 들어 API 서버, 관리자 페이지, 웹 프론트엔드를 각각 LoadBalancer로 열면 관리할 외부 진입점이 많아집니다.

이때 Ingress를 사용하면 하나의 진입점에서 도메인이나 경로를 기준으로 여러 Service에 트래픽을 나눠 보낼 수 있습니다.

example.com/        → frontend-service
example.com/api     → api-service
admin.example.com   → admin-service

Ingress는 규칙이고, 실제로 그 규칙을 처리하는 것은 Ingress Controller입니다. NGINX Ingress Controller, AWS Load Balancer Controller, Traefik 등이 여기에 해당합니다.

L4와 L7 부하분산

로드밸런싱을 보다 보면 L4, L7이라는 표현도 자주 나옵니다. 어렵게 느껴질 수 있지만, 기준은 단순합니다. 어떤 정보를 보고 트래픽을 나눌 수 있는지가 다릅니다.

구분 기준 예시
L4 IP, 포트 같은 네트워크 정보 TCP 80번 포트로 들어온 요청 분산
L7 HTTP Host, Path, Header 같은 애플리케이션 정보 /api 요청은 API 서버로 전달

LoadBalancer 타입 Service는 보통 L4 부하분산에 가깝게 이해하면 됩니다. 반면 Ingress는 HTTP 경로와 도메인을 기준으로 라우팅하므로 L7 영역에 가깝습니다.

부하분산이 항상 균등하다는 뜻은 아닙니다

부하분산이라고 하면 모든 Pod에 요청이 정확히 같은 비율로 들어갈 것처럼 느껴질 수 있습니다. 하지만 실제 환경에서는 그렇지 않을 수 있습니다. 연결 유지 시간, 클라이언트 수, keep-alive, 세션 설정, 로드밸런서 알고리즘 등에 따라 특정 Pod에 요청이 더 많이 갈 수 있습니다.

그래서 운영 환경에서는 단순히 Pod 개수만 늘리는 것이 아니라, 애플리케이션이 수평 확장에 적합한지도 같이 확인해야 합니다. 특정 Pod의 메모리 사용량만 높거나, 일부 Pod에 요청이 몰린다면 부하분산 구조와 애플리케이션 동작을 함께 봐야 합니다.

확인할 때 자주 쓰는 명령어

문제가 생겼을 때는 먼저 Service와 Endpoint가 제대로 연결되어 있는지 확인하는 것이 좋습니다.

kubectl get svc
kubectl describe svc web-service
kubectl get endpoints web-service
kubectl get pods -l app=web -o wide

Service는 있는데 Endpoint가 비어 있다면, selector가 Pod label과 맞지 않는 경우가 많습니다. 이 경우 Service가 트래픽을 보낼 Pod를 찾지 못합니다.

자주 만나는 문제

증상 확인할 부분 설명
외부 IP가 계속 Pending 상태입니다. 클라우드 로드밸런서 연동 로컬 클러스터이거나 클라우드 컨트롤러 설정이 없을 수 있습니다.
Service는 있는데 접속이 안 됩니다. Endpoint selector와 Pod label이 맞는지 확인해야 합니다.
일부 Pod로만 요청이 갑니다. 세션, keep-alive, 로드밸런서 알고리즘 요청 단위가 아니라 연결 단위로 분산되는 상황일 수 있습니다.
Ingress 규칙이 동작하지 않습니다. Ingress Controller Ingress 리소스만 만들고 Controller가 없으면 실제 라우팅이 되지 않습니다.

정리

쿠버네티스에서 부하분산을 이해할 때는 먼저 Service를 중심에 두고 보는 것이 좋습니다. Pod는 계속 바뀔 수 있지만, Service는 그 앞에서 고정된 진입점 역할을 합니다. 그리고 외부 트래픽이 필요하면 NodePort, LoadBalancer, Ingress 같은 방식으로 그 진입점을 외부에 열어줍니다.

운영 환경에서는 보통 단순한 테스트에는 NodePort, 클라우드 환경의 외부 노출에는 LoadBalancer, 여러 HTTP 서비스를 도메인과 경로로 나눠야 할 때는 Ingress를 사용합니다. 각각의 역할을 분리해서 보면 전체 구조가 훨씬 명확해집니다.

결국 흐름은 하나입니다. 외부 요청이 들어오고, Service가 안정적인 진입점이 되며, 실제 처리는 현재 살아있는 Pod가 담당합니다. 이 흐름만 잡고 있으면 쿠버네티스 로드밸런싱은 훨씬 이해하기 쉬워집니다.

'Kubernetes' 카테고리의 다른 글

쿠버네티스 네트워크  (0) 2025.12.12
쿠버네티스 볼륨  (0) 2025.12.10
쿠버네티스 아키텍처  (0) 2025.12.09
쿠버네티스 명령어 정리 (kubectl) 및 yaml  (0) 2025.12.08
쿠버네티스 개념 및 용어 정리  (0) 2025.12.08