쿠버네티스 교육

AWS ALB & LoadBalancer Controller

Jerry_이정훈 2023. 4. 11. 09:01
728x90

우리 회사는 현재 EKS 환경의 NLB + Ingress-nginx controller를 사용하고 있다. 이를 AWS ALB + LoadBalancer로 변경을 고려하고 있다. ALB는 가시다님 스터디에서 배웠는데 이를 업무에 적용하기 위해서 검토하고 있는 내용을 포스팅한다.

 

현재 문제점

  • 외부에서 인그레스 접속 시 NLB - EKS Node(externalTrafficPolicy:cluster 사용 중) - Ingress-nginx controller - Target Pod 등 4개 Hop을 필요한다.

무려 4단계

  • 4개 Hop이나 거치니 성능 제약이 있겠다 수준으로 알고 있었지 큰 문제를 못 느끼지는 못했는데(장애만 나지 않으면 넘어가는 안일함 그리고 성능을 측정할 구체적인 방법도 없기도 하고) Node AutoScaler가 자주 발생하면서 node가 리스타트 되면 해당 노드와 관계없는 Ingress를 사용하는 다른 서비스도 끊어졌다. Retry를 하는 TCP 환경은 문제가 없을 것 같으나 WebSocket을 사용하는 우리 회사 서비스는 문제가 생긴 것이다.

 

해결 방안

  • AWS ALB + Load Balancer Controller 사용 

2단계로 줄일 수 있다.

  • 어떻게 보면 당연한데 기존 L4 스위치를 사용하는 것처럼 외부에서 접속하면 Load Balancer 거쳐서 Target Pod에 Direct로 연결한다. 4개의 홉에서 2개 홉으로 줄어드니 장애 포인트도 줄어들고 성능도 향상될 것이다. (물론 실제 성능 향상을 어떻게 측정할지는 난감하기는 하다.)

 

아이디어만 보면 참 간단한데 막상 적용을 하려니 이런저런 고려 사항이 있었다.

  • ingress annoation 문법 변경
    ingress-nginx 환경에서 ALB로 변경되니 당연히 문법도 변경된다.
  • NLB 인증서 to ALB 인증서, ingress host 설정
  • 아래와 같이 nginx의 annotation에서 적용한 rewrite 기능을 ALB에도 적용해야 한다. 아래는 /test/index.html로 접속하면 nginx rewrite하여 '/' 슬래시 앞의 /test를 때고 뒤의 /index.html 경로만 뒷단으로 넘겨준다.
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    
spec:
  ingressClassName: nginx
  rules:
  - host: XXXXX.test.com
    http:
      paths:
      - backend:
          service:
            name: test
            port:
              number: 8080
        path: /test(/|$)(.*)

해당 사항을 염두에 두고 aws load balancer controller 설치한다. 모든 쿠버네티스 리소스가 그렇듯이 헬름으로 설치한다. 전체 소스 파일은 필자의 깃헙에서 확인할 수 있다.

$ (⎈ |switch-oregon-stage:kube-system) helm repo add eks https://aws.github.io/eks-charts
$ (⎈ |switch-oregon-stage:kube-system) helm pull eks/aws-load-balancer-controller
$ (⎈ |switch-oregon-stage:kube-system) tar xvfz aws-load-balancer-controller-1.4.8.tgz
$ (⎈ |switch-oregon-stage:kube-system) cd aws-load-balancer-controller
$ (⎈ |switch-oregon-stage:kube-system) cp values.yaml my-values.yaml

헬름 설치 전 먼저 ServiceAccount가 필요하니 AWS 가이드에 따라 아래와 같이 작업한다.

 

IAM 정책 Download

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

IAM 정책 생성

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

Role & ServiceAccount 생성

  • cluster 이름과 Account ID(111122223333)는 본인 환경에 맞게 변경한다.
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

위 명령어로 생성된 aws-load-balancer-controller ServiceAccount를 확인하면 아래와 같이 AWS Role이 맵핑된 걸 확인할 수 있다.

$ (⎈ |switch-oregon-stage:kube-system) k get sa aws-load-balancer-controller -oyaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXX:role/AmazonEKSLoadBalancerControllerRole
  creationTimestamp: "2023-04-08T00:58:50Z"
  labels:
    app.kubernetes.io/managed-by: eksctl
  name: aws-load-balancer-controller
  namespace: kube-system

이제 aws load balancer controller 헬름을 설치한다.

$ (⎈ |switch-oregon-stage:kube-system) helm install aws-load-balancer-controller -f my-values.yaml .

 

정상으로 설치되면 파드를 확인할 수 있다.

$ (⎈ |switch-singapore-test:kube-system) k get pod
NAME                                            READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-7654f65466-hjtc5   1/1     Running   0          50s
aws-load-balancer-controller-7654f65466-mmd98   1/1     Running   0          50s

이제 준비가 되었다. 새롭게 만든 ALB를 이용할 애플리케이션을 설치한다. 테스트에 사용한 echoservice 애플리케이션의 deployment, service, namespace 예제 코드는 필자의 깃헙에서 확인할 수 있다. 기본 설정이라 설명은 생략한다. 기존과 달라지는 테스트 echoservice Ingress 매니페스트는 아래와 같다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: echoserver
  namespace: echoserver
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: my-alb-group
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-2:XXXXXXXXXX:certificate/XXXXXXXX
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/actions.rule-echoserver: >
      {"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"200","messageBody":"Path is /"}}
spec:
  ingressClassName: alb
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /echo-server
            pathType: Prefix
            backend:
              service:
                name: echoserver
                port:
                  number: 80

 기존 NLB와 annotation 설정이 달라지는데, annotation 설정은 공식 가이드에 따라 수정을 한다.

  • alb.ingress.kubernetes.io/target-type: ip
    target-type으로 instance or ip을 선택할 수 있다. instance를 지정하면 전체 노드의 NodePort를 target으로 지정한다. 기존과 같은 설정이다. 이를 IP 타입으로 변경하면 load balancer에서 POD IP를 직접 바라본다. (제약 사항은 CNI로 aws vpc cni를 사용해야 한다. 아마도 eks 환경이면 대부분 aws vpc cni 사용할 것 같다.)
  • alb.ingress.kubernetes.io/group.name: my-alb-group
    ingress마다 alb를 따로 만들지 않고 alb group.name을 지정하면 같은 ALB로 여러 개의 Ingress에서 사용할 수 있다. 실무에서는 ingress를 여러 개 만드니 꼭 필요하다.
  • alb.ingress.kubernetes.io/certificate-arn
    기존 ingress-nginx controller에 지정한 TLS 인증서를 이제 개별 애플리케이션의 ingress마다 지정한다.
  • (metadata.annotations)
    alb.ingress.kubernetes.io/actions.rule-echoserver: >
          {"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"200","messageBody":"Path is /"}}
    (spec.rules.http.paths.path)
    path: /echo-server
    rewrite 옵션 설정인데, path: /echo-server 사용자 요청을 echo-server 빼고 '/' root로 패스를 변경하여 전달한다.

    (수정) aws lb controller + alb 환경에서 re-write 가 안되는 것 같다. (https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/835) 깃헙에 19년 이슈가 올라왔는데 아직 안되고 있다.
  • spec.rules.host: www.example.com
    여러개의 ingress를 같이 사용하면 host 기준으로 구분할 수 있다. 예제에 사용할 host 주소를 입력한다.

이제 준비한 manifest 기준으로 echoservice를 배포한다.

# echoservice 디렉토리 전체의 manifest를 실행한다.
$ (⎈ |switch-oregon-stage:echoserver) k apply -f echoservice/

별다른 이슈가 없다면 아래와 같이 리소스를 확인할 수 있다.

$ (⎈ |switch-oregon-stage:echoserver) k get ing,pod,svc
NAME                                   CLASS   HOSTS                                 ADDRESS                                                                 PORTS   AGE
ingress.networking.k8s.io/echoserver   alb     www.example.com                       k8s-xxxxxx.us-west-2.elb.amazonaws.com   80      3d13h

NAME                              READY   STATUS    RESTARTS   AGE
pod/echoserver-7757d5ff4d-7m2fp   1/1     Running   0          3d13h

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/echoserver   ClusterIP   172.20.198.114   <none>        80/TCP    3d13h

이제 ingress-host에 등록한 주소로 접속한다.

 

위와 같이 정상으로 접속된다. 빨간색 밑줄 친 client_address IP를 확인하면 ALB Load Balancer IP임을 알 수 있다. 그리고 주소 창 자물쇠 모양의 인증서를 확인하면 역시 정상이다.

 

아마도 추가 검증이 필요하겠지만 기본적인 검증을 완료해서 운영 환경에 사용할 수 있을 것 같다.

 

참조

https://github.com/kubernetes-sigs/aws-load-balancer-controller/tree/main/helm/aws-load-balancer-controller

반응형

'쿠버네티스 교육' 카테고리의 다른 글

Tracing - OpenTelemetry + Tempo  (2) 2023.05.31
Github Action Self-hosted 세팅  (4) 2023.04.06
파일시스템 기반 Loki 설치  (8) 2023.04.01
원격 EKS 접속 환경 설정  (0) 2022.11.08
EKS OJT 교육 실습 목차  (2) 2022.11.08