Study/Cloud

[AWS]AWS Load Balancer Controller(ALB, NLB)

seomj 2023. 11. 22. 15:01

프로젝트를 진행하면서 담당 파트에서 제일 이슈가 있었던 Load Balancer Controller에 대해 정리하고자 한다. 이 녀석 때문에 꽤나 애를 먹었다...


 

 

[Network]Load Balancing(로드밸런싱)

로드 밸런싱 애플리케이션을 지원하는 리소스 풀 전체에 네트워크 트래픽을 균등하게 배포하는 방법 네트워크 또는 서버에 가해지는 부하(로드)를 분산(밸런싱)해주는 기술 *로드 밸런서: 사용

seomj74.tistory.com


ELB(Elastic Load Balancing)

하나 이상의 가용 영역(AZ)에 있는 여러 대상 및 가상 어플라이언스에서 들어오는 애플리케이션 트래픽을 자동으로 분산한다. 

 

하나 이상의 리스너를 지정하여 들어오는 트래픽을 허용하도록 로드 밸런서를 구성합니다. 리스너는 연결 요청을 확인하는 프로세스입니다. 클라이언트와 로드 밸런서 간의 연결을 위한 프로토콜 및 포트 번호로 구성됩니다. 마찬가지로 로드 밸런서와 대상 간의 연결을 위한 프로토콜 및 포트 번호로 구성됩니다. _ AWS

 

이는 공홈에 나와있는 설명이다.

 

ELB는 AWS의 VPC에 탑재된다. 사용자의 요청을 받고 VPC 내의 리소스에 적절히 부하 분산한다. ELB는 외부의 요청을 받는 리스너(LIstener)와 요청을 분산/전달할 리소스의 집합인 대상 그룹(Target Group)으로 구성된다. 대상 그룹 내 리소스들은 헬스 체크(Health Check)를 통해 상태를 확인한다.

 

리스너는 프로토콜과 포트를 기반으로 요청을 받아 검사하고 이를 적절한 대상으로 전달하는 기능을 수행한다. 

리스너 룰(Rule)은 리스너와 대상 그룹 사이의 트래픽 분배를 위한 라우팅 규칙에 해당한다.

대상 그룹은 리스너가 전달한 요청을 처리하기 위한 부하 분산 대상들의 모임이다. 헬스 체크와 모니터링 기능이 있다.

헬스 체크는 직접 트래픽을 발생시켜 인스턴스가 살아있는지 체크하는 기능이다. 대상 그룹에 대한 헬스 체크를 통해 현재 정상적으로 작동하는 인스턴스로만 트래픽을 분배한다.

보안 그룹을 가질 수 있으며, 사용자가 전달하는 요청을 처리하기 위해서는 해당 요청의 포트를 보안 그룹에서 열어두어야 한다. 

 

 

요청 처리 과정

사용자는 로드 밸런서의 DNS 이름을 통해 ELB에 접속한다. DNS를 통해 접속하면 ELB는 요청을 대상 그룹에게 전달하고 대상 그룹의 EC2 등의 리소스가 요청을 처리하게 된다.

 

  1. 사용자가 LB에 접근하기 위해 Amazon의 DNS 서버에 LB의 도메인 해석 요청
  2. Amazon의 DNS 서버가 LB 노드 IP 리스트를 사용자에게 전달
  3. 사용자는 IP 중 하나를 선택하여 LB에 접근 + Port 입력
  4. 사용자는 LB의 리스너에게 접근하게 되고 리스너는 이 요청을 받아들여 적절한 대상 그룹으로 전달
  5. 리스너로부터 전달받은 요청을 리소스에서 처리한 후 다시 사용자에게 반환

 

유형

AWS에서는 4가지 유형을 지원을 하고 있다.

  • Application Load Balancer
  • Network Load Balancer
  • Gateway Load Balancer
  • Classic Load Balancer

위 3가지 유형은 대상을 대상 그룹에 등록하고 트래픽을 대상 그룹에 라우팅한다. 반면에, CLB는 로드 밸런서에 인스턴스를 등록한다.

 

그 중 ALB와 NLB에 대해서만 알아보자.

NLB( Network Load Balancer)

 

OSI 모델 4계층인 Transport 계층에서 작동하며, TCP/UDP를 사용하는 요청을 받아 부하 분산한다. TLS(SSL Offload)까지 가능하다.

4계층에서 동작하기 때문에 HTTP와 같은 상위 Layer의 프로토콜을 처리하지 못한다. 이는 ALB에서 이해하고 처리할 수 있다. ALB에서는 더 많은 프로토콜을 이해하고 처리할 수 있는 만큼 많은 시스템 리소스를 소모해야 한다. 하지만 NLB는 Layer 4보다 상위에 있는 프로토콜을 처리할 필요 없이 TCP와 UDP만 이해하고 처리하면 되기 때문에 ALB에 비해 시스템 리소스 소모가 적다. 그렇기에 ALB보다 더 많은 트래픽 처리가 가능하며 성능이 더 뛰어나다.

 

ALB(Application Load Balancer)

OSI 모델 7계층인 Application 계층에서 작동하며, HTTP/HTTPS뿐만 아니라 FTP, DHCP 등 다양한 프로토콜이 존재한다.

이는 단순 부하 분산뿐 아니라 HTTP/HTTPS의 헤더 정보를 이용해 지능적으로 라우팅할 수 있다. 즉, HTTP 헤더의 값들을 보고 어느 대상 그룹으로 보낼지를 판단할 수 있다. 

path(경로)뿐만 아니라 port(포트)에 따라 다른 대상 그룹으로 맵핑할 수도 있다. 각각의 포트에 따라 다르게 구성할 수 있으며, 동일한 포트라도 path에 따라 다르게 분기할 수 있다.

SSL 인증서 탑재가 가능하여 대상 그룹의 EC2를 대신하여 SSL 암복호화를 대신 진행할 수 있다.

 


이를 AWS EKS 환경에 적용하기 위해 AWS Load Balancer Controller가 필요하다.

AWS Load Balancer Controller

Kubernetes 클러스터의 AWS Elastic Load Balancer를 관리한다.

 

EKS에서 Node Group은 프라이빗에 위치하게 된다. 그렇게 되면 외부에서 해당 Application에 접속이 불가능하다. 외부에서 서비스한 Application에 접속하기 위해 필요한 것이 AWS LBC이다. 

 

EKS에서는 주로 NLB와 ALB를 사용한다. (그래서 위에서 NLB와 ALB의 설명을 진행한 것이다)

 

본인의 경우는 NLB만 구성해 봤다.

NLB는 Ingress를 사용해야 하는 ALB와 달리 직접 서비스를 노출시킨다. 구현 또한 간단한다. 

 

AWS LBC 설치하기

helm과 eksctl 설치가 우선시 되어야 한다.

# helm install
$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 11715  100 11715    0     0  47048      0 --:--:-- --:--:-- --:--:-- 47048
$ chmod 700 get_helm.sh
$ ./get_helm.sh
Downloading https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm
$ helm version --short | cut -d + -f 1
v3.12.3

# eksctl install
$ ARCH=amd64
$ PLATFORM=$(uname -s)_$ARCH
$ curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
$ tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
$ sudo mv /tmp/eksctl /usr/local/bin
$ eksctl version
0.160.0

 

사용자 대신 AWS API를 호출할 수 있는 AWS Load Balancer Controller의 IAM 정책을 다운로드하자.

curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json

 

다운로드한 정책을 사용해 IAM 정책을 생성하자.

aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam_policy.json

정책 이름은 변경 가능하다.

 

IAM 역할을 생성하자.

IAM OIDC 공급자가 있는지 확인

oidc_id=$(aws eks describe-cluster --name my-cluster --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4

출력이 반환되면 이미 존재하는 것. 반환되지 않는다면 생성해주어야 한다.

 

클러스터의 IAM OIDC ID 공급자를 생성

eksctl utils associate-iam-oidc-provider --cluster $cluster_name --approve

클러스터에 OIDC 공급자를 등록하고 IAM에 이를 연결하여 kubernetes 클러스터에서 IAM 역할을 통해 AWS 자원에 액세스할 수 있도록 하는 작업을 수행한다.

 

이후 eksctl을 사용하는 방법과 aws cli와 kubectl을 사용하는 방법이 있다.

직접 구축하는 것이라면 eksctl이 편리하다. 자동화로 스크립트를 짤 때는 eksctl로 애를 꽤나 먹어 aws cli와 kubectl 방식이 더 직관적이고 좋았다.

eksctl create iamserviceaccount \
  --cluster=my-cluster \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --attach-policy-arn=arn:aws:iam::111122223333:policy/AWSLoadBalancerControllerIAMPolicy \
  --approve

 

아래와 같은 결과들이 출력될 것이다.

2023-09-30 08:27:35 [ℹ]  1 iamserviceaccount (kube-system/aws-load-balancer-controller) was included (based on the include/exclude rules)
2023-09-30 08:27:35 [!]  serviceaccounts that exist in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
2023-09-30 08:27:35 [ℹ]  1 task: {
    2 sequential sub-tasks: {
        create IAM role for serviceaccount "kube-system/aws-load-balancer-controller",
        create serviceaccount "kube-system/aws-load-balancer-controller",
    } }2023-09-30 08:27:35 [ℹ]  building iamserviceaccount stack "eksctl-nba-eks-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2023-09-30 08:27:35 [ℹ]  deploying stack "eksctl-nba-eks-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2023-09-30 08:27:35 [ℹ]  waiting for CloudFormation stack "eksctl-nba-eks-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2023-09-30 08:28:05 [ℹ]  waiting for CloudFormation stack "eksctl-nba-eks-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2023-09-30 08:28:05 [ℹ]  created serviceaccount "kube-system/aws-load-balancer-controller"

 

이제 helm으로 eks-charts 리포지토리를 추가하자.

helm repo add eks https://aws.github.io/eks-charts
helm repo update eks

 

이제 설치를 진행한다.

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller

 

아래와 같은 결과를 얻을 수 있다.

$ helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=my-cluster --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller
NAME: aws-load-balancer-controller
LAST DEPLOYED: Sat Sep 30 08:32:53 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
AWS Load Balancer controller installed!

$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   2/2     2            2           85s

정상적으로 잘 동작하는 것까지 확인 완료

 

Service

노출시킬 서비스를 배포하자.

apiVersion: v1
kind: Service
metadata:
  name: $SVC_NAME
  namespace: $NAMESPACE_NAME
  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
  labels:
    quest: $TITLE
spec:
  selector:
    quest: $TITLE
  ports:
    - protocol: TCP
      port: $PORT
      targetPort: $PORT
  type: LoadBalancer

 

주의해서 봐야할 부분은 annotations이다.

  • service.beta.kubernetes.io/aws-load-balancer-type
    • LB 유형을 지정
    • external or nlb-ip
  • service.beta.kubernetes.io/aws-load-balancer-nlb-target-type
    • NLB에 대해 구성할 대상 유형
    • instance(EC2) or ip(Pod IP)
  • service.beta.kubernetes.io/aws-load-balancer-scheme
    • NLB 외부 or 내부 연결
    • interne-facing or internal

 

결과

$ kubectl get all -n eks-test
NAME                               READY   STATUS    RESTARTS   AGE
pod/test-deploy-6d8bdcb87b-6kgf7   1/1     Running   0          18s
pod/test-deploy-6d8bdcb87b-72xjb   1/1     Running   0          18s
pod/test-deploy-6d8bdcb87b-b62wx   1/1     Running   0          18s

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP                                                                        PORT(S)        AGE
service/test-svc   LoadBalancer   172.20.154.64   k8s-ekstest-testsvc-6046b22044-01a602ae099efa68.elb.ap-northeast-1.amazonaws.com   80:31682/TCP   19s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/test-deploy   3/3     3            3           18s

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/test-deploy-6d8bdcb87b   3         3         3       18s

 

LB 주소로 접속하면 nginx가 잘 실행되는 것을 확인했다.

 

 

 

참고

https://aws.amazon.com/ko/elasticloadbalancing/

https://velog.io/@yange/%EB%82%B4%EB%B6%80%EB%A7%9D%ED%8F%90%EC%87%84%EB%A7%9D%EC%97%90%EC%84%9C-repository-%EA%B5%AC%EC%84%B1

https://aws-hyoh.tistory.com/128

https://aws-hyoh.tistory.com/133

NLB: https://aws-hyoh.tistory.com/135

ALB: https://aws-hyoh.tistory.com/134, https://aws-hyoh.tistory.com/147

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/aws-load-balancer-controller.html

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.6/

https://umi0410.github.io/blog/aws/aws_eks_elb/