Loadbalancer 타입 서비스와 AWS Load Balancer Controller의 동작 원리

Jaden Kim·2025년 5월 21일
post-thumbnail

LoadBalancer 타입의 서비스란?

LoadBalancer 타입의 서비스는 클러스터 외부에서 내부 애플리케이션에 접근할 수 있게 하기 위한 서비스 타입입니다.
NodePort 타입의 서비스의 경우 파드가 위치한 노드의 IP 주소와 포트를 직접적으로 사용해야 합니다.
반면 LoadBalancer 타입의 서비스는 고정된 로드 밸런서의 Public IP로 요청을 보내면, 부하 분산과 내부 NAT를 통해 목적지 파드로 트래픽이 전달되기 때문에 안정적으로 트래픽 전달이 가능합니다.

일반적인 Loadbalancer 타입 서비스의 동작 방식

LoadBalancer 타입의 서비스는 일반적으로 노드에 대한 부하 분산을 수행합니다.
각 노드들에서 서비스에 대한 NodePort가 열려있는 상황에서, Loadbalancer는 먼저 이들 중 하나의 노드에 트래픽을 전달하게 됩니다.
트래픽을 전달받은 노드는 iptables 규칙에 따라 트래픽을 적절한 파드로 DNAT 시킵니다.
이 과정에서 다른 노드로의 요청 전달이 이루어져야 하는데, 응답 트래픽에서 동일한 네트워크 경로를 따라가기 위해 출발지 IP에 대한 masquerade가 이루어집니다.

[Client] → [NodeIP:NodePort]
         → PREROUTING
         → KUBE-SERVICES
         → KUBE-NODEPORTS (NodePort로 들어온 트래픽 처리)
         → KUBE-EXT-XXXX (MASQUERADE를 통해 출발지 IP 변경)
         → KUBE-SVC-XXXX (서비스에 연결된 파드 중 로드밸런싱)
         → KUBE-SEP-YYYY (DNAT to PodIP:Port)
         ← Response
         ← POSTROUTING (MASQUERADE를 통해 출발지 IP 변경)
[Client] ←

언뜻 봐도 비효율적인 부분이 있는 동작 방식입니다.
로드밸런서는 파드가 정확히 어느 노드에 있는지 모르기 때문에 모든 노드에 트래픽을 분산시키고 있고, 노드에서는 파드에 요청을 전달하기 위해 복잡한 iptables 체이닝을 거쳐야 합니다.
또한 파드에 트래픽이 도달한 시점에는 클라이언트의 원본 IP가 SNAT 되어 유실된다는 문제도 있습니다.

요청에 대한 응답 시 네트워크 경로를 유지하기 위해 iptable 체이닝은 출발지 IP를 노드의 IP로 masquerade 합니다.

AWS Load balancer Controller의 동작 방식

클라우드 환경에 기본으로 설치되는 Cloud Controller Manager를 사용하면 위와 같이 클러스터의 노드 IP로 타겟 그룹이 구성됩니다.
이와 달리 AWS Loadbalancer Controller를 사용할 경우, Loadbalancer의 타겟 그룹은 파드의 IP로 구성됩니다.
이것이 가능한 이유는, VPC CNI 플러그인을 사용할 경우 파드의 IP가 VPC IP 대역에 바로 생성되어, 로드밸런서에서 직접 파드로 트래픽을 전달할 수 있기 때문입니다.

VPC CNI의 동작 원리

Target Group 업데이트 과정

AWS Load Balancer Controller는 리소스를 기반으로 Loadbalancer의 target group을 동적으로 업데이트합니다.
사용자가 Loadbalancer 타입의 Service를 생성하면, AWS Load Balancer Controller는 이를 감지하여 커스텀 리소스인 TargetGroupBinding을 생성합니다.
예를 들어 다음의 서비스 리소스를 생성했다고 합시다.

apiVersion: v1
kind: Service
metadata:
  name: example-http-svc
  namespace: default
  annotations:
    # NLB(IP mode) 사용 설정
    service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP

Controller는 해당 서비스가 LoadBalancer 타입이며 LoadBalancer이며, service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip 로 어노테이션이 붙어 있는 것을 확인한 뒤, 이를 기준으로 매칭되는 TargetGroupBinding 커스텀 리소스를 생성합니다.

apiVersion: elbv2.k8s.aws/v1
kind: TargetGroupBinding
metadata:
  name: example-http-tgb
  namespace: default
spec:
  # 연동할 Service 참조
  serviceRef:
    name: example-http-svc
    port: 80
  # AWS에서 생성된 Target Group ARN
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/example-tg/abcdef0123456789
  targetType: ip
  vpcID: vpc-0123456789

이제 Controller는 Service에 연결된 Endpoints를 감시하여 현재 실행 중인 Pod의 IP 주소를 확인합니다.

$ kubectl get endpoints example-http-svc -n default
NAME                  ENDPOINTS                     AGE
example-http-svc      10.244.1.12:8080,10.244.1.15:8080   10m

Controller는 확인된 Pod IP를 기반으로 AWS SDK를 사용하여 Target Group에 대상 등록(RegisterTargets) 또는 제거(DeregisterTargets)를 수행합니다.
다음과 같이 aws CLI를 이용해서 Target Group에 Pod IP 및 Port로 대상이 등록되었음을 확인 가능합니다.

$ aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/example-tg/abcdef0123456789 \
  --query 'TargetHealthDescriptions[].Target.[Id,Port]' \
  --output text
10.244.1.12   8080
10.244.1.15   8080

작업 결과는 TargetGroupBinding 리소스의 status 필드에 반영됩니다.

apiVersion: elbv2.k8s.aws/v1
kind: TargetGroupBinding
metadata:
  name: example-http-tgb
  namespace: default
spec:
  serviceRef:
    name: example-http-svc
    port: 80
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/example-tg/abcdef0123456789
  targetType: ip
  vpcID: vpc-0123456789
# 추가된 정보
status:
  conditions:
    - type: Active
      status: "True"
      lastTransitionTime: "2025-05-21T08:00:00Z"
      reason: TargetsRegistered
      message: "2 targets registered, 2 healthy"

Controller는 Endpoint 리소스를 watch 하여, 파드 생성/삭제 시 Target Group 을 수시로 업데이트합니다.

0개의 댓글