하이브리드 노드용 LoadBalancer 유형의 Service 구성하기

하이브리드 노드용 LoadBalancer 유형의 Service 구성하기 (Configure Services of type LoadBalancer for hybrid nodes)

이 주제는 Amazon EKS Hybrid Nodes에서 실행되는 애플리케이션에 대한 레이어 4(L4) 로드 밸런싱을 구성하는 방법을 설명해요. LoadBalancer 유형의 Kubernetes Service는 클러스터 외부로 Kubernetes 애플리케이션을 노출하는 데 사용돼요. LoadBalancer 유형의 Service는 일반적으로 클라우드나 온프레미스 환경의 물리적 로드 밸런서 인프라와 함께 사용되어 워크로드의 트래픽을 제공해요. 이러한 로드 밸런서 인프라는 일반적으로 환경별 컨트롤러로 프로비저닝돼요.

AWS는 EKS Hybrid Nodes에서 실행되는 LoadBalancer 유형의 Service에 대해 AWS Network Load Balancer(NLB)와 Cilium을 지원해요. NLB를 사용할지 Cilium을 사용할지는 애플리케이션 트래픽의 소스에 따라 결정돼요. 애플리케이션 트래픽이 AWS 리전에서 발생한다면 AWS NLB와 AWS Load Balancer Controller를 사용하는 것을 권장해요. 애플리케이션 트래픽이 로컬 온프레미스나 엣지 환경에서 발생한다면 환경의 로드 밸런서 인프라와 함께 또는 없이 사용할 수 있는 Cilium의 내장 로드 밸런싱 기능을 사용하는 것을 권장해요.

레이어 7(L7) 애플리케이션 트래픽 로드 밸런싱은 하이브리드 노드용 Kubernetes Ingress 구성하기를 참고하세요. EKS 로드 밸런싱에 대한 일반적인 정보는 로드 밸런싱 모범 사례를 참고하세요.

출처: 문서

본문

AWS Network Load Balancer

하이브리드 노드에서 실행되는 워크로드에 대상 유형(target type)이 ip인 AWS Load Balancer Controller와 NLB를 사용할 수 있어요. 대상 유형 ip를 사용하면 NLB가 Service 레이어 네트워크 경로를 우회해 Pod로 직접 트래픽을 전달해요. NLB가 하이브리드 노드의 Pod IP 대상에 도달하려면 온프레미스 Pod CIDR이 온프레미스 네트워크에서 라우팅 가능해야 해요. 또한 AWS Load Balancer Controller는 웹훅을 사용하며 EKS 컨트롤 플레인과의 직접 통신이 필요해요. 자세한 내용은 하이브리드 노드용 웹훅 구성하기를 참고하세요.

서브넷 구성 요구사항은 Network Load Balancer로 TCP 및 UDP 트래픽 라우팅하기를, AWS Network Load Balancer와 AWS Load Balancer Controller에 대한 추가 정보는 Helm으로 AWS Load Balancer Controller 설치하기 및 로드 밸런싱 모범 사례를 참고하세요.

AWS Network Load Balancer로 LoadBalancer 유형의 Service에 적용할 수 있는 구성은 AWS Load Balancer Controller NLB 구성을 참고하세요.

사전 요구 사항

  • 하이브리드 노드용 CNI 구성하기의 지침에 따라 Cilium이 설치되어 있어야 해요.
  • 하이브리드 노드용 Cilium BGP 구성하기의 지침에 따라 Cilium BGP Control Plane이 활성화되어 있어야 해요. BGP를 사용하지 않으려면 온프레미스 네트워크에서 온프레미스 Pod CIDR을 라우팅 가능하게 만드는 대체 방법을 사용해야 해요. 자세한 내용은 라우팅 가능한 원격 Pod CIDR을 참고하세요.
  • 명령줄 환경에 Helm이 설치되어 있어야 해요. Setup Helm 지침을 참고하세요.
  • 명령줄 환경에 eksctl이 설치되어 있어야 해요. Setup eksctl 지침을 참고하세요.

절차

  1. AWS Load Balancer Controller가 여러분을 대신해 AWS API를 호출할 수 있게 하는 IAM 정책을 다운로드해요.
    curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/refs/heads/main/docs/install/iam_policy.json
    
  2. 이전 단계에서 다운로드한 정책으로 IAM 정책을 만들어요.
    aws iam create-policy \
        --policy-name AWSLoadBalancerControllerIAMPolicy \
        --policy-document file://iam_policy.json
    
  3. 클러스터 이름(CLUSTER_NAME), AWS 리전(AWS_REGION), AWS 계정 ID(AWS_ACCOUNT_ID) 값을 여러분의 설정으로 바꾸고 다음 명령을 실행해요.
    eksctl create iamserviceaccount \
        --cluster=CLUSTER_NAME \
        --namespace=kube-system \
        --name=aws-load-balancer-controller \
        --attach-policy-arn=arn:aws:iam::AWS_ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
        --override-existing-serviceaccounts \
        --region AWS_REGION \
        --approve
    
  4. eks-charts Helm 차트 저장소를 추가해요. AWS는 이 저장소를 GitHub에 유지해요.
    helm repo add eks https://aws.github.io/eks-charts
    
  5. 가장 최신 차트가 있는지 확인하도록 로컬 Helm 저장소를 업데이트해요.
    helm repo update eks
    
  6. AWS Load Balancer Controller를 설치해요. 클러스터 이름(CLUSTER_NAME), AWS 리전(AWS_REGION), VPC ID(VPC_ID), AWS Load Balancer Controller Helm 차트 버전(AWS_LBC_HELM_VERSION) 값을 여러분의 설정으로 바꾸세요. helm search repo eks/aws-load-balancer-controller --versions를 실행해 Helm 차트의 최신 버전을 찾을 수 있어요. 하이브리드 노드와 AWS Cloud의 노드가 모두 있는 혼합 모드 클러스터를 실행한다면 AWS Load Balancer Controller 안내에 따라 클라우드 노드에서 AWS Load Balancer Controller를 실행할 수 있어요.
    helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
      -n kube-system \
      --version AWS_LBC_HELM_VERSION \
      --set clusterName=CLUSTER_NAME \
      --set region=AWS_REGION \
      --set vpcId=VPC_ID \
      --set serviceAccount.create=false \
      --set serviceAccount.name=aws-load-balancer-controller
    
  7. AWS Load Balancer Controller가 성공적으로 설치되었는지 확인해요.
    kubectl get -n kube-system deployment aws-load-balancer-controller
    
    NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
    aws-load-balancer-controller   2/2     2            2           84s
    
  8. tcp-sample-app.yaml이라는 파일에 샘플 애플리케이션을 정의해요. 아래 예시는 TCP 포트가 있는 간단한 NGINX 배포를 사용해요.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tcp-sample-app
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: nginx
              image: public.ecr.aws/nginx/nginx:1.23
              ports:
                - name: tcp
                  containerPort: 80
    
  9. 배포를 클러스터에 적용해요.
    kubectl apply -f tcp-sample-app.yaml
    
  10. tcp-sample-service.yaml이라는 파일에 배포용 LoadBalancer 유형의 Service를 정의해요.
    apiVersion: v1
    kind: Service
    metadata:
      name: tcp-sample-service
      namespace: default
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-type: external
        service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
        service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    spec:
      ports:
        - port: 80
          targetPort: 80
          protocol: TCP
      type: LoadBalancer
      selector:
        app: nginx
    
  11. Service 구성을 클러스터에 적용해요.
    kubectl apply -f tcp-sample-service.yaml
    
    Service용 NLB 프로비저닝에 몇 분이 걸릴 수 있어요. NLB가 프로비저닝되면 Service에 NLB 배포의 DNS 이름에 해당하는 주소가 할당돼요.
    kubectl get svc tcp-sample-service
    
    NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)        AGE
    tcp-sample-service   LoadBalancer   172.16.115.212   k8s-default-tcpsampl-xxxxxxxxxx-xxxxxxxxxxxxxxxx.elb..amazonaws.com   80:30396/TCP   8s
    
  12. NLB의 주소를 사용해 Service에 접근해요.
    curl k8s-default-tcpsampl-xxxxxxxxxx-xxxxxxxxxxxxxxxx.elb..amazonaws.com
    
    예시 출력은 아래와 같아요.
    Welcome to nginx!
    [...]
    
  13. 만든 리소스를 정리해요.
    kubectl delete -f tcp-sample-service.yaml
    kubectl delete -f tcp-sample-app.yaml
    

Cilium 인클러스터 로드 밸런싱 (Cilium in-cluster load balancing)

Cilium은 EKS Hybrid Nodes에서 실행되는 워크로드의 인클러스터 로드 밸런서로 사용할 수 있으며, 이는 로드 밸런서 인프라가 없는 환경에 유용해요. Cilium의 로드 밸런싱 기능은 kube-proxy replacement, LB IPAM(Load Balancer IP 주소 관리), BGP Control Plane을 포함한 Cilium 기능의 조합으로 구축돼요. 이러한 기능의 역할은 아래에 자세히 설명돼요.

  • Cilium kube-proxy replacement: Service 트래픽을 백엔드 Pod로 라우팅하는 것을 처리.
  • Cilium Load Balancer IPAM: LoadBalancer 유형의 Service에 할당될 수 있는 IP 주소를 관리.
  • Cilium BGP Control Plane: Load Balancer IPAM이 할당한 IP 주소를 온프레미스 네트워크에 광고.

Cilium의 kube-proxy replacement를 사용하지 않더라도 Cilium Load Balancer IPAM과 BGP Control Plane을 사용해 LoadBalancer 유형의 Service에 IP 주소를 할당하고 지정할 수 있어요. kube-proxy replacement를 사용하지 않는다면 Service에서 백엔드 Pod로의 로드 밸런싱은 EKS에서 기본적으로 kube-proxy와 iptables 규칙이 처리해요.

사전 요구 사항

  • kube-proxy replacement 활성화 여부와 관계없이 하이브리드 노드용 CNI 구성하기의 지침에 따라 Cilium이 설치되어 있어야 해요. Cilium의 kube-proxy replacement는 v4.19.57, v5.1.16, v5.2.0 이상만큼 최신인 Linux 커널을 가진 운영 체제를 실행해야 해요. 하이브리드 노드와 함께 사용할 수 있도록 지원되는 운영 체제의 모든 최신 버전은 RHEL(Red Hat Enterprise Linux) 8.x를 제외하고 이 기준을 충족해요.
  • 하이브리드 노드용 Cilium BGP 구성하기의 지침에 따라 Cilium BGP Control Plane이 활성화되어 있어야 해요. BGP를 사용하지 않으려면 온프레미스 네트워크에서 온프레미스 Pod CIDR을 라우팅 가능하게 만드는 대체 방법을 사용해야 해요. 자세한 내용은 라우팅 가능한 원격 Pod CIDR을 참고하세요.
  • 명령줄 환경에 Helm이 설치되어 있어야 해요. Setup Helm 지침을 참고하세요.

절차

  1. LoadBalancer 유형의 Service에 대한 Load Balancer IP 주소 범위를 구성하는 CiliumLoadBalancerIPPool 리소스가 있는 cilium-lbip-pool-loadbalancer.yaml이라는 파일을 만들어요. LB_IP_CIDR을 Load Balancer IP 주소에 사용할 IP 주소 범위로 바꾸세요. 단일 IP 주소를 선택하려면 /32 CIDR을 사용하세요. 자세한 내용은 Cilium 문서의 LoadBalancer IP 주소 관리를 참고하세요. serviceSelector 필드는 후속 단계에서 만들 Service의 이름과 일치하도록 구성돼요. 이 구성으로 이 풀의 IP는 tcp-sample-service 이름을 가진 Service에만 할당돼요.
    apiVersion: cilium.io/v2alpha1
    kind: CiliumLoadBalancerIPPool
    metadata:
      name: tcp-service-pool
    spec:
      blocks:
      - cidr: "LB_IP_CIDR"
      serviceSelector:
        matchLabels:
          io.kubernetes.service.name: tcp-sample-service
    
  2. CiliumLoadBalancerIPPool 리소스를 클러스터에 적용해요.
    kubectl apply -f cilium-lbip-pool-loadbalancer.yaml
    
  3. 풀에 사용 가능한 IP 주소가 하나 이상 있는지 확인해요.
    kubectl get ciliumloadbalancerippools.cilium.io
    
    NAME               DISABLED   CONFLICTING   IPS AVAILABLE   AGE
    tcp-service-pool   false      False         1               24m
    
  4. 다음 단계에서 만들 Service의 로드 밸런서 IP 주소를 광고하는 CiliumBGPAdvertisement 리소스가 있는 cilium-bgp-advertisement-loadbalancer.yaml이라는 파일을 만들어요. Cilium BGP를 사용하지 않는다면 이 단계를 건너뛸 수 있어요. Service에 사용된 로드 밸런서 IP 주소는 마지막 단계에서 서비스를 쿼리할 수 있으려면 온프레미스 네트워크에서 라우팅 가능해야 해요. advertisementType 필드는 Service로, service.addresses는 LoadBalancerIP로 설정되어 LoadBalancer 유형의 Service에 대해 LoadBalancerIP만 광고해요. selector 필드는 후속 단계에서 만들 Service의 이름과 일치하도록 구성돼요. 이 구성으로 tcp-sample-service 이름을 가진 Service의 LoadBalancerIP만 광고돼요.
    apiVersion: cilium.io/v2alpha1
    kind: CiliumBGPAdvertisement
    metadata:
      name: bgp-advertisement-tcp-service
      labels:
        advertise: bgp
    spec:
      advertisements:
        - advertisementType: "Service"
          service:
            addresses:
              - LoadBalancerIP
          selector:
            matchLabels:
              io.kubernetes.service.name: tcp-sample-service
    
  5. CiliumBGPAdvertisement 리소스를 클러스터에 적용해요. Cilium BGP를 사용하지 않는다면 이 단계를 건너뛸 수 있어요.
    kubectl apply -f cilium-bgp-advertisement-loadbalancer.yaml
    
  6. tcp-sample-app.yaml이라는 파일에 샘플 애플리케이션을 정의해요. 아래 예시는 TCP 포트가 있는 간단한 NGINX 배포를 사용해요.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tcp-sample-app
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: nginx
              image: public.ecr.aws/nginx/nginx:1.23
              ports:
                - name: tcp
                  containerPort: 80
    
  7. 배포를 클러스터에 적용해요.
    kubectl apply -f tcp-sample-app.yaml
    
  8. tcp-sample-service.yaml이라는 파일에 배포용 LoadBalancer 유형의 Service를 정의해요. Service 객체의 lbipam.cilium.io/ips 어노테이션으로 로드 밸런서 IP 풀에서 특정 IP 주소를 요청할 수 있어요. Service에 특정 IP 주소를 요청하지 않으려면 이 어노테이션을 제거할 수 있어요. 레거시 AWS Cloud Provider가 Service에 대해 Classic Load Balancer를 만들지 못하게 하려면 loadBalancerClass spec 필드가 필요해요. 아래 예시에서 이는 Cilium의 BGP Control Plane을 로드 밸런서 클래스로 사용하도록 io.cilium/bgp-control-plane로 구성돼요. 이 필드는 Cilium의 L2 Announcements 기능(현재 베타이며 AWS에서 공식 지원하지 않음)을 사용하도록 io.cilium/l2-announcer로 구성할 수도 있어요.
    apiVersion: v1
    kind: Service
    metadata:
      name: tcp-sample-service
      namespace: default
      annotations:
        lbipam.cilium.io/ips: "LB_IP_ADDRESS"
    spec:
      loadBalancerClass: io.cilium/bgp-control-plane
      ports:
        - port: 80
          targetPort: 80
          protocol: TCP
      type: LoadBalancer
      selector:
        app: nginx
    
  9. Service를 클러스터에 적용해요. Service는 애플리케이션에 접근하는 데 사용할 수 있는 외부 IP 주소와 함께 생성돼요.
    kubectl apply -f tcp-sample-service.yaml
    
  10. Service가 성공적으로 생성되었고 이전 단계에서 만든 CiliumLoadBalancerIPPool에서 IP가 할당되었는지 확인해요.
    kubectl get svc tcp-sample-service
    
    NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    tcp-sample-service   LoadBalancer   172.16.117.76   LB_IP_ADDRESS   80:31129/TCP   14m
    
  11. kube-proxy replacement 모드에서 Cilium을 사용한다면 다음 명령으로 Cilium이 Service의 로드 밸런싱을 처리하고 있는지 확인할 수 있어요. 아래 출력에서 10.86.2.x 주소는 Service의 백엔드 Pod의 Pod IP 주소예요.
    kubectl -n kube-system exec ds/cilium -- cilium-dbg service list
    
    ID   Frontend               Service Type   Backend
    ...
    41   LB_IP_ADDRESS:80/TCP   LoadBalancer   1 => 10.86.2.76:80/TCP (active)
                                              2 => 10.86.2.130:80/TCP (active)
                                              3 => 10.86.2.141:80/TCP (active)
    
  12. Cilium이 BGP를 통해 온프레미스 네트워크에 IP 주소를 광고하고 있는지 확인해요. 아래 예시에는 5개의 하이브리드 노드가 있으며, 각 노드가 tcp-sample-service Service의 LB_IP_ADDRESS를 온프레미스 네트워크에 광고해요.
    Node                   VRouter      Prefix             NextHop   Age     Attrs
    mi-026d6a261e355fba7   NODES_ASN
                  LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
    mi-082f73826a163626e   NODES_ASN
                  LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
    ...
    
  13. 할당된 load balancer IP 주소를 사용해 Service에 접근해요.
    curl LB_IP_ADDRESS
    
    예시 출력은 아래와 같아요.
    Welcome to nginx!
    [...]
    
  14. 만든 리소스를 정리해요.
    kubectl delete -f tcp-sample-service.yaml
    kubectl delete -f tcp-sample-app.yaml
    

더 알아보기 (Learn more)