Cloud/AWS

AWS EKS의 Ingress(ALB)의 Target Type에 따른 동작

지기(ZIGI) 2022. 3. 17. 18:02
Today Keys :   eks, ingress, target, iptables, type, load, balancer, ip, instance, aws, cloud
 

이번 포스팅에서는 AWS EKS의 Ingress로 Application Load Balancer 사용 시에, Target Type을 Instance 혹은 IP로 지정함에 따라서, iptables가 어떻게 적용되는지 확인해보는 포스팅입니다. Cluster 내의 복잡한 서비스 등록으로 인해 iptables가 늘어난 경우에 Target Type을 변경하는 것만으로 iptables에 대한 부하를 줄여줄 수 있기도 하기 때문에 알아두면 유용할 것 같습니다.

 
EKS에서 서비스 연결을 위해서 Load Balancer Type이나, Ingress를  AWS NLB와 ALB로 사용 하는 경우에
Target Type에 따른  iptables에 어떻게 적용되는 것들이 달라지는 지에 대해서 알아보려고 합니다.
 
먼저 Service를 아래와 같이 NodePort 타입으로 생성합니다.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: zigiweb
  labels:
    app: zigiweb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: zigiweb
  template:
    metadata:
      labels:
        app: zigiweb
    spec:
      containers:
      - name: zigiweb
        image: traefik/whoami
---
apiVersion: apps/v1
kind: Service
metadata:
   name: zigiweb
spec:
  selector:
    app: zigiweb
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  type: NodePort
 
정상적으로 Deployment와 NodePort Type의 Service가 생성된 것을 볼 수 있습니다.
그리고, NodePort를 통해서 EKS의 Woker Node로 접속을 시도하면 정상적으로 Cluster 외부에서 서비스가 호출되는 것을 볼 수 있습니다.

 

 
 
 
NodePort를 이용해서 Cluster 외부에서 서비스 요청이 Pod 까지 유입되기 위해서 iptables의 PREROUTING 체인의 정책을 시작으로 해서,
각 체인의 정책을 따라서, 트래픽이 흐르면서 pod의 서비스까지 접근하게 됩니다. 
 
 
 
kubeporxy를 통해서 이러한 iptables이 관리되게 되는 데,
만약 kubernetes 내의 서비스가 복잡하게 많아지는 경우에는 iptables의 정책도 매우 많이 늘어나게 됩니다.
그렇게 많은 정책이 있는 상태가 아니라면 성능 상에서도 큰 이슈가 없을 수 있지만,
지속적으로 iptables이 늘어나게 되면, iptables의 변경이 필요한 시점이나 iptables을 거치면서 서비스가 되는 시점에 성능 상의 이슈가 나올 수 있습니다.
 
그럼 어떻게 하면 그러한 이슈를 줄일 수 있을까?에 대한 관점으로
AWS EKS(VPC CNI)에서 서비스 연결을 위한 Ingress로  AWS ALB 사용 시 Target Port 지정 방식에 따라 어떻게 달라지는 보겠습니다.
 
 
먼저 Ingress(ALB)의 Target Type 방식을 Instance로 해서 Ingress를 생성합니다.
 
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: zigiingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: instance
spec:
  rules:
    - http:
        paths:
          - pathType: Prefix
            path: /
            backend:
              service:
                name: zigiweb
                port:
                  number: 80
 
생성된 ALB의 Target Group을 살펴 보겠습니다.
포트 정보를 보면, pod에 올린 서비스 포트는 80이지만, Target Group의 포트는 31462로 NodePort인 것을 볼 수 있습니다.
Ingress로 ALB 생성 시에, Target의 Type을 Instance 방식으로 하게 되는 경우로 ALB에서 각 Instance를 Target으로 DNAT을 하기 때문에
서비스 포트가 NodePort의 포트로 Target Group이 생성되게 됩니다.
NodePort로 등록된 Service의 경우 모든 Worker Node의 Listening 하면서,
각 Pod로 모두 분산할 수 있도록 iptables가 구성되기 때문에 대상 또한 현재 Worker Node가 모두 등록됩니다.
 
 
 
그럼 ALB Ingress의 Target을 Instance Type으로 한 경우에 iptables 정책을 어떻게 통과하는지 테스트 해보겠습니다.
좀 쉽게 보기 위해서, Deployment에서 replica를 1개로 수정하고 나서 테스트를 진행합니다.
 
 
 
외부에서 AWS EKS에 연결된 Ingress(ALB)로 서비스 요청을 해서, 정상적으로 응답을 받은 것을 이미지 하단에서 볼 수 있으며,
서비스가 유입되는 시점에 iptables의 각 체인의 정책을 통과하면서 pod까지 연결된 것을 볼 수 있습니다.
기존의 Woker Node의 IP와 NodePort로 서비스 요청을 한 것과 동일합니다.
당연하게도, ALB의 Target Type이 Instance의 경우에 Worker Node와 NodePort가 Target으로 등록되기 때문에
실제 iptables를 통한 적용에서는 달라지는 것은 없습니다.
 
 
 
전체적인 Flow를 정리하면 다음과 같습니다.
 
 
 
그럼 이번에는 Ingress(ALB)의 Target Type 방식을 IP로 해서 Ingress를 생성합니다.
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: zigiingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  rules:
    - http:
        paths:
          - pathType: Prefix
            path: /
            backend:
              service:
                name: zigiweb
                port:
                  number: 80
 
생성된 ALB의 Target Group을 살펴 보겠습니다.
포트 정보를 보면, Instance Type으로 생성 시에는 Target Group의 포트가 NodePort였지만,
이번에는 실제 pod에 올린 서비스 포트인 80인 것을 볼 수 있습니다.
Ingress로 ALB 생성 시에, Target의 Type을 ip 방식으로 하는 경우에는 각 Target이 pod 자체가 되기 때문에 실제 서비스 포트로 등록이 됩니다.
 
이는 EKS에서 VPC CNI를 쓰는 경우에 pod도 VPC와 동일한 CIDR을 사용해서 생성되기 때문에 별도의 NAT를 하지 않아도 바로 통신이 되기 때문입니다.
하단의 등록된 대상을 보면, 실제 pod의 IP 주소로 등록된 것을 볼 수 있고,
Worknode 수와 상관없이, pod의 수만큼 Target(대상)으로 등록됩니다.
현재는 앞선 테스트를 위해서 replica를 1로 해 놓았기 때문에 1개의 pod IP만 등록되어 있습니다.
 
 
 
 
그럼 이제 다시 외부에서 AWS EKS에 연결된 Ingress(ALB)로 서비스 요청을 해보겠습니다.
기존의 Instance Type으로 했던 것과 동일하게  정상적으로 응답을 받은 것을 이미지 하단에서 볼 수 있습니다.
하지만, 이번에는 서비스가 유입되는 시점에 iptables의 체인에 적용되지 않는 것을 볼 수 있습니다.
왜냐면, ALB의 Target이 pod IP로 되어 있기 때문에 iptables 정책을 통한 별도 NAT 과정이 없이 직접 서비스 호출이 가능하기 때문입니다.
 
 
 
즉, EKS에서 Ingress로서 ALB 사용 시에 IP Type의 Target을 사용하게 되면, iptables에 대한 부하를 줄여 줄 수 있다는 것을 알 수 있습니다.
 
Target Type을 IP로 한 경우의 전체 Flow는 다음과 같습니다.
 
 
 
 
물론, 아예 Kube-proxy mode 자체를 iptables에서 IPVS로 변경하거나,
CNI 자체를 ebpf를 사용하는 cilium이나 calico를 사용하는 것도 이러한 부하를 좀 더 원천적으로 줄일 수 있는 방안일 것입니다.
 
하지만, 기본 AWS EKS 환경을 그대로 사용하는 경우에 별다른 변경 없이,
ALB의 Target Type 지정 만으로도 부하를 줄일 수 있기 때문에 유용하게 사용할 수 있습니다.
 
또한 Ingress로서, ALB 사용 뿐 아니라 Service를 NodePort가 아닌 Load Balancer로 해서 NLB를 사용하는 경우의
Target Type 지정 시에도 동일한 방식으로 동작하기 때문에 Ingress 이외에 Load Balancer 지정 시에도 적용이 가능합니다.