목차

 

AWS Ingress Controller 설치

  • 서브넷에 태그달기
  • AWS loadBalancer Controller가 사용할 IAM 정책과 역할 만들기
  • EKS Cluster 반영
  • 확인해보기

ALB 생성 확인해보기

  • ALB 생성 트러블 슈팅
  • NLB를 생성해보자
  • 노드그룹과 fargate의 차이

 


AWS Ingress Controller 설치

AWS loadBalancer Controller 를 설치하면 pod 의 형태로 컨트롤러가 생성되는데, 얘가 설치되는 건 문제가 안되지만 LB 를 만드는 동작을 하는데 권한과 lb 가 올라갈 서브넷 등에 설정이 필요하기 때문에 선행작업으로 진행 후 eks 에 AWS loadBalancer Controller 를 설치하도록 한다.

설치 과정

  1. 서브넷에 태그달기
  2. AWS loadBalancer Controller가 사용할 IAM 정책과 역할 만들기
  3. EKS에 IAM 적용하고 컨트롤러 설치하기

AWS 공식 가이드

AWS Load Balancer Controller 추가 기능 설치 - Amazon EKS

 

AWS Load Balancer Controller 추가 기능 설치 - Amazon EKS

배포된 차트는 보안 업데이트를 자동으로 수신하지 않습니다. 새 차트가 사용 가능해지면 수동으로 업그레이드해야 합니다. 업그레이드 시 이전 명령에서 install을 upgrade로 변경하되, 이전 명령

docs.aws.amazon.com

서브넷에 태그달기

컨트롤러가 NLB 혹은 ALB 가 올라갈 서브넷을 확인할 수 있게 서브넷에 태그를 아래와 같이 달아주어야 한다.

 

기본

  • 키 - kubernetes.io/cluster/*my-cluster*
  • 값 - shared 또는 owned

퍼블릭 서브넷

  • 키 - kubernetes.io/role/elb
  • 값 - 1

프라이빗 서브넷

  • 키 - kubernetes.io/role/internal-elb
  • 값 - 1

 

예시)

 

AWS loadBalancer Controller가 사용할 IAM 정책과 역할 만들기

AWS Loadbalancer Controller 정책 생성

아래 IAM 내용으로 정책을 만들어준다.
# 정책 이름 예시 : AWSLoadBalancerControllerIAMPolicy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAddresses",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeVpcs",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeInstances",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeTags",
                "ec2:GetCoipPoolUsage",
                "ec2:DescribeCoipPools",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeListenerCertificates",
                "elasticloadbalancing:DescribeSSLPolicies",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetGroupAttributes",
                "elasticloadbalancing:DescribeTargetHealth",
                "elasticloadbalancing:DescribeTags",
                "elasticloadbalancing:AddTags"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cognito-idp:DescribeUserPoolClient",
                "acm:ListCertificates",
                "acm:DescribeCertificate",
                "iam:ListServerCertificates",
                "iam:GetServerCertificate",
                "waf-regional:GetWebACL",
                "waf-regional:GetWebACLForResource",
                "waf-regional:AssociateWebACL",
                "waf-regional:DisassociateWebACL",
                "wafv2:GetWebACL",
                "wafv2:GetWebACLForResource",
                "wafv2:AssociateWebACL",
                "wafv2:DisassociateWebACL",
                "shield:GetSubscriptionState",
                "shield:DescribeProtection",
                "shield:CreateProtection",
                "shield:DeleteProtection"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateSecurityGroup"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": "arn:aws:ec2:*:*:security-group/*",
            "Condition": {
                "StringEquals": {
                    "ec2:CreateAction": "CreateSecurityGroup"
                },
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTags",
                "ec2:DeleteTags"
            ],
            "Resource": "arn:aws:ec2:*:*:security-group/*",
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "true",
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:DeleteSecurityGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:CreateTargetGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:CreateListener",
                "elasticloadbalancing:DeleteListener",
                "elasticloadbalancing:CreateRule",
                "elasticloadbalancing:DeleteRule"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:RemoveTags"
            ],
            "Resource": [
                "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*",
                "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*",
                "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
            ],
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "true",
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:ModifyLoadBalancerAttributes",
                "elasticloadbalancing:SetIpAddressType",
                "elasticloadbalancing:SetSecurityGroups",
                "elasticloadbalancing:SetSubnets",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:ModifyTargetGroup",
                "elasticloadbalancing:ModifyTargetGroupAttributes",
                "elasticloadbalancing:DeleteTargetGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets"
            ],
            "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:SetWebAcl",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:AddListenerCertificates",
                "elasticloadbalancing:RemoveListenerCertificates",
                "elasticloadbalancing:ModifyRule"
            ],
            "Resource": "*"
        }
    ]
}

 

alb 를 생성하고 태그를 조절하는 등의 권한이 포함되어 있다.

AWS 에서 제안하는 정책을 다운받는 경우, 가끔 ec2:DescribeAvailabilityZones 권한이나 elasticloadbalancing:AddTags 권한이 없다고 에러가 날 수 있다. 그런 경우 IAM 정책에서 슬쩍 추가해주면 문제가 해결된다.

 

만약 콘솔에서 만들기가 귀찮다면, 위 내용을 파일명 iam_policy.json로 만들고, 아래 명령어로 생성가능하다.

 

생성 명령어

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

 

 

AWS Loadbalancer Controller 역할 생성

이제 클러스터가 aws 에 접근해서 동작할 때 적용될 역할을 생성할 차례이다.

클러스터 콘솔에 가서 oidc를 확인한다.

 

 

그리고 IAM 콘솔에서 role 생성을 진행하는데, Web Identity → 에서 위에서 확인한 oidc 를 체크한다.

 

 

아까 생성한 정책을 가지고 role 을 생성하면 된다.

 

 

 

신뢰관계에서 내용을 조금 수정한다.

 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
                }
            }
        }
    ]
}

 

 

신뢰관계에서 보면, aud와 sub 이 있다.

  • aud (audience) : 토큰이 발급된 대상이다. 여기선 aws 가 토큰을 발급한 대상이며, 이 토큰은 aws sts에 대한 요청을 인증하는 데 사용된다.
  • sub (subject) : 토큰의 주체이다. k8s 시스템의 ns= kube-system 이며, 이름이 aws-load-balancer-controller 인 serviceaccount 가 접근하는 경우에 허용한다.

IAM Role ARN 복사

serviceaccount 에 적용하기 위하여 생성이 완료된 역할의 arn 을 복사해 둔다.

 

 

EKS Cluster 반영

service account 생성

이제 클러스터에 접근해서 만들어둔 role 이 클러스터에서 사용되는 계정으로 적용되게끔 serviceaccount 를 생성해 준다. 이때 위에서 복사했던 arn 을 붙여준다.

 

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/AmazonEKSLoadBalancerControllerRole

 

 

Helm 으로 컨트롤러 설치

만약 헬름이 설치 되어 있지 않다면 먼저 설치 해준다.

아래 명령어로 생성할 수 있다.

 

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 ls

helm delete aws-load-balancer-controller



확인해보기

 

kubectl get deployment -n kube-system aws-load-balancer-controller

kubectl get ingressclass -A  # ingressclass 가 alb 로 생성되어 있다.

 

 

ALB 생성 확인해보기

위에서 컨트롤러를 설치했다면, 이제 ingress 를 생성하면, 컨트롤러가 alb 를 aws 에 생성해 줄 것이다. 맞게 설정이 되어 있는지 한번 생성해서 테스트 해보자.

 

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/examples/2048/2048_full.yaml

 

위 경로의 상세 내용은 아래와 같다.

 

---
apiVersion: v1
kind: Namespace
metadata:
  name: game-2048
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: game-2048
  name: deployment-2048
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: app-2048
  replicas: 5
  template:
    metadata:
      labels:
        app.kubernetes.io/name: app-2048
    spec:
      containers:
      - image: public.ecr.aws/l6m2t8p7/docker-2048:latest
        imagePullPolicy: Always
        name: app-2048
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: game-2048
  name: service-2048
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: NodePort
  selector:
    app.kubernetes.io/name: app-2048
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: game-2048
  name: ingress-2048
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-2048
              port:
                number: 80kubectl apply -f 2048_full.yaml

 

이 내용에서 포인트를 몇개 집어보자면,

  1. Namespace 생성 → Deployment가 생성한 Namespace에 생성된다. → Service는 Deployment에서 작성한 Pod의 label를 선택한다. → Ingress 는 생성한 Service로 보낸다.
  2. 컨트롤러가 Ingress 의 내용을 읽어 ALB 로 만든다. Ingress 의 내용이 http, paths 등으로 룰을 만들어 L7과 같이 분기를 한다.
  3. service의 내용은 간단.
  4. Ingress 개수로 alb 가 생성된다.
  5. Ingress의 타겟타입이 ip인데 service의 타입이 노드포트다. → 생성은 되지만, 사실상 clusterip 와 동일한 구성으로 생성된다.

 

** 다양한 옵션으로 ALB와 NLB 를 조절할 수 있는데, 그걸 어노테이션으로 조절한다. 어노테이션은 아래 링크에서 자세히 확인할 수 있다.

Annotations - AWS Load Balancer Controller

 

Annotations - AWS Load Balancer Controller

Ingress annotations You can add annotations to kubernetes Ingress and Service objects to customize their behavior. Annotation keys and values can only be strings. Advanced format should be encoded as below: boolean: 'true' integer: '42' stringList: s1,s2,s

kubernetes-sigs.github.io

** 샘플 예제 출처 :

Amazon EKS 애플리케이션 로드 밸런싱 - Amazon EKS

 

Amazon EKS 애플리케이션 로드 밸런싱 - Amazon EKS

IPv6 Pods로 로드 밸런싱하는 경우, 인그레스 사양에 다음 주석을 추가합니다. IPv6를 통해서는 인스턴스 대상이 아닌 IP 대상으로만 로드 밸런싱할 수 있습니다. 이 주석이 없으면 로드 밸런싱은 IPv

docs.aws.amazon.com

 

 

ALB 생성 트러블슈팅

AWS LBC 로 LB 생성 이슈가 있을 때, 아래 4가지 경우를 먼저 살펴보자(겪어본 이슈들)

  • 권한 문제 → iam
  • 서브넷을 찾지 못함 → 태그
  • 타겟 매핑을 못함 → 포트
  • 맞는 서브넷을 사용하지 못함 → helm 설치시 이름 잘못 기입

NLB 를 생성해보자

NLB를 생성하는 경우에는 Ingress 를 참고하지 않고 service 의 loadbalancer 타입으로 자체적으로 동작해서 service의 어노테이션이 화려해진다.

---
apiVersion: v1
kind: Namespace
metadata:
  name: game-2048
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: game-2048
  name: deployment-2048
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: app-2048
  replicas: 5
  template:
    metadata:
      labels:
        app.kubernetes.io/name: app-2048
    spec:
      containers:
      - image: public.ecr.aws/l6m2t8p7/docker-2048:latest
        imagePullPolicy: Always
        name: app-2048
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: game-2048
  name: service-2048
  annotations:
    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.kubernetes.io/name: app-2048

 

노드그룹과 fargate 의 차이

fargate는 인스턴스 타입이 불가능하다. 따라서 IP 타입만 선택할 수 있다

반면, 노드그룹은 인스턴스 타입과 ip 타입을 모두 선택할 수 있다. 다만, 인스턴스 타입을 선택할 경우 무조건 nodeport 를 사용해야 한다.

목차

 

AWS VPC CNI

 - L-IPAM이란?

 - k8s cni 와 비교

노드의 기본 네트워크

노드 간 파드 통신

파드에서 외부 통신

노드에서 파드 생성 개수 제한

Service 와  AWS LBC

Ingress

Network Policies with VPC CNI

 


 

AWS VPC CNI

EKS 클러스터는 VPC 내부에 구현되어 AWS 네트워크 환경에 영향을 받는다. 따라서, 파드가 클러스터가 구현된 서브넷 대역에 해당하는 IP를 할당받는다. 이걸 가능하게 만드는 것이 AWS VPC CNI(Container Networking Interface)로, AWS VPC 네트워크와 EKS 네트워크 간 인터페이스 역할을 수행해준다.

 

파드의 IP 네트워크 대역과 노드(워커)의 IP 대역이 같아서 직접 통신이 가능하다

 

L-IPAM이란?

L-IPAM(Local IP Address Manager)은 네트워크 내의 IP 주소를 관리, 할당 및 추적하는 소프트웨어 도구이다. 이 시스템은 네트워크 관리자가 IP 주소 공간을 효율적으로 사용하고 중복을 방지할 수 있도록 지원한다. 또한, 네트워크 장치 및 사용자에 대한 IP 할당 내역을 시각적으로 표시하고, IP 주소 변경이나 업데이트를 쉽게 관리할 수 있게 해 준다.

 

AWS VPC CNI는 EKS Addon 으로 제공되며, aws_node 라는 DaemonSet으로 모든 노드에 배포되는데, aws-node의 일부로 L-IPAM(Local IP Address Manager)을 설치하여 이를 통해 파드의 IP를 할당받는 방식을 사용한다.

 

각 노드에서 사용 가능한 보조 IP 주소의 warm-pool을 유지하기 위해 L-IPAM을 실행하며, Kubelet에서 파드를 추가하라는 요청을 받을 때마다 L-IPAM이 warm-pool에서 즉시 사용 가능한 보조 IP 주소 하나를 가져와서 파드에 할당한다.

 

 

L-IPAM은 노드(인스턴스)의 관련 정보인 메타데이터를 통해 사용 가능한 ENI와 보조 IP 주소를 파악하고, DaemonSet이 재시작될 때마다 Kubelet을 통해 파드 이름, 네임스페이스, IP 주소와 같은 현재 실행 중인 파드의 정보를 가져와서 warm-pool을 구축한다.

 

실제 동작으로 예시를 들자면, 최초 노드 생성 후 파드를 배포하지 않은 경우 특정 파드(kube-proxy, aws-node)를 제외한 나머지(coredns와 같은) 파드가 새로 배포되면 L-IPAM은 Secondary ENI를 생성한다.

L-IPAM은 Secodary ENI의 보조 Private IPv4 주소를 관리하는 warm-pool에서 즉시 사용 가능한 IP 주소를 가져와서 새로 배포된 파드에 할당한다.

k8s cni 와 비교

AWS VPC CNI의 경우 네트워크 통신의 최적화(성능, 지연)를 위해서 노드와 파드의 네트워크 대역을 동일하게 설정한다. 

 

파드간 통신 시 일반적으로 K8S CNI는 오버레이(VXLAN, IP-IP 등) 통신을 하고, AWS VPC CNI는 동일 대역으로 직접 통신을 한다. 즉, K8S 기반 CNI의 경우 Overlay를 통한 패킷의 캡슐화 과정을 필요로 하여 통신을 위한 자원이 소모되며, AWS VPC CNI의 경우 캡슐화에 필요한 자원의 소모를 줄일 수 있고, 지연시간이 짧아지므로 네트워크 성능이 향상된다. 

 

 

 

노드의 기본 네트워크

 

  • 네트워크 네임스페이스는 호스트(Root)와 파드 별(Per Pod)로 구분된다. 호스트의 경우 호스트 ip 를 그대로 사용하지만, 파드별 ip는 보조 프라이빗 ip 가 할당된다.
  • kube-proxy, aws-node 는 호스트의 ip 를 그대로 사용한다. 
  • ENI0, ENI1 으로 2개의 ENI는 자신의 IP 이외에 추가적으로 5개의 보조 프라이빗 IP를 가질수 있다
  • coredns 파드는 veth 으로 호스트에는 eniY@ifN 인터페이스와 파드에 eth0 과 연결되어 있다.

파드의 Host Network 옵션 확인 :

https://xn--vj5b11biyw.kr/306

노드 간 파드 통신

파드간 통신 시 tcpdump 내용을 확인해보면, 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능한 것을 확인할 수 있다. 같은 VPC 내의 통신이여서 별도의 Nat를 타지도 않는다. 

Pod-2 -> Pod-1 로 통신될때에는 워커노드1의 ip 가 확인된다.

# 파드 IP 변수 지정
PODIP1=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[0].status.podIP})
PODIP2=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[1].status.podIP})
PODIP3=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[2].status.podIP})

# 파드1 Shell 에서 파드2로 ping 테스트
kubectl exec -it $PODNAME1 -- ping -c 2 $PODIP2

# 파드2 Shell 에서 파드3로 ping 테스트
kubectl exec -it $PODNAME2 -- ping -c 2 $PODIP3

# 파드3 Shell 에서 파드1로 ping 테스트
kubectl exec -it $PODNAME3 -- ping -c 2 $PODIP1

# 워커 노드 EC2 : TCPDUMP 확인
sudo tcpdump -i any -nn icmp
sudo tcpdump -i eth1 -nn icmp
sudo tcpdump -i eth0 -nn icmp
sudo tcpdump -i eniYYYYYYYY -nn icmp

[워커 노드1]
# routing policy database management 확인
ip rule

# routing table management 확인
ip route show table local

# 디폴트 네트워크 정보를 eth0 을 통해서 빠져나간다
ip route show table main
default via 192.168.1.1 dev eth0
...

 

파드간 통신 시 과정 참고

 

파드에서 외부 통신

파드에서 외부 통신 흐름은 iptable 에 SNAT 을 통하여 노드의 eth0 IP로 변경되어서 외부와 통신된다.

* SNAT(Source Network Address Translation) : 내부 네트워크의 프라이빗 IP를 공용 IP로 변환해 외부와 통신 가능하게 하며, 내부 주소를 숨기는 네트워크 주소 변환 기술

VPC CNI 의 External source network address translation (SNAT) 설정에 따라, 외부(인터넷) 통신 시 SNAT 하거나 혹은 SNAT 없이 통신을 할 수 있다

노드에서 파드 생성 개수 제한

인스턴스 유형에 최대 ENI 갯수와 할당 가능 IP 수를 조합하여 Secondary IPv4 addresses에 맞추어 제한된다. 단, aws-node 와 kube-proxy 파드는 호스트의 IP를 사용함으로 최대 갯수에서 제외한다. 

 

t3.medium은 ENI가 총 3개 가능하며, 각 ENI당 5개씩 Secondary IP 를 가질 수 있어, 총 15개의 파드가 가능하다. (aws-node 와 kube-proxy 제외)

 

계산 식은 아래와 같다.

 

최대 파드 생성 갯수 : (Number of network interfaces for the instance type × (the number of IP addressess per network interface - 1)) + 2

 

이걸 늘리는 방법은 Prefix Delegation, WARM & MIN IP/Prefix Targets, Custom Network 으로 가능하다.

Service 

ClusterIP 타입

 

NodePort 타입

 

LoadBalancer 타입 (기본 모드) : NLB 인스턴스 유형

Service (LoadBalancer Controller) : AWS Load Balancer Controller + NLB IP 모드 동작 with AWS VPC CNI

NLB 모드 전체 정리

  1. 인스턴스 유형
    1. externalTrafficPolicy : ClusterIP ⇒ 2번 분산 및 SNAT으로 Client IP 확인 불가능 ← LoadBalancer 타입 (기본 모드) 동작
    2. externalTrafficPolicy : Local ⇒ 1번 분산 및 ClientIP 유지, 워커 노드의 iptables 사용함
  2. IP 유형 ⇒ 반드시 AWS LoadBalancer 컨트롤러 파드 및 정책 설정이 필요함!
    1. Proxy Protocol v2 비활성화 ⇒ NLB에서 바로 파드로 인입, 단 ClientIP가 NLB로 SNAT 되어 Client IP 확인 불가능
    2. Proxy Protocol v2 활성화 ⇒ NLB에서 바로 파드로 인입 및 ClientIP 확인 가능(→ 단 PPv2 를 애플리케이션이 인지할 수 있게 설정 필요)

Ingress

클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) 시킨다. L7 의 역할

AWS Load Balancer Controller + Ingress (ALB) IP 모드 동작 with AWS VPC CNI

Network Policies with VPC CNI

Network Policy 는 클러스터 내의 포드 간 통신을 제어하고 관리하는 데 사용되는 규칙 세트이다. 이를 통해 사용자는 특정 포드가 다른 포드, 네트워크 세그먼트 또는 IP 주소 범위와 통신할 수 있는지 여부를 세밀하게 제어할 수 있다. EKS 에서는 꽤 최근에 적용되었는데, 사용하기 위한 조건은 아래와 같다.

  • EKS 1.25 버전 이상
  • AWS VPC CNI 1.14 이상
  • OS 커널 5.10 이상 EKS 최적화 AMI(AL2, Bottlerocket, Ubuntu)

EKS 에서 Network Policy 는 크게 3가지를 통해 동작한다.

  • Network Policy Controller : EKS 버전 1.25 이상에서는 Network Policy Controller가 자동으로 설치된다. 이 컨트롤러는 네트워크 통제 정책을 모니터링하고, 해당 정책에 따라 필요한 eBPF 프로그램을 생성하거나 업데이트하도록 Node Agent에 지시한다.
  • Node Agent : AWS VPC CNI와 함께 번들로 제공되는 ipamd 플러그인과 함께 설치되며, aws-node 데몬셋 형태로 존재한다. Node Agent의 주된 역할은 eBPF 프로그램을 관리하는 것이다. 이러한 관리 작업에는 프로그램의 설치, 업데이트 및 삭제가 포함된다.
  • eBPF SDK : AWS VPC CNI에 포함된 eBPF SDK는 노드에서 eBPF 프로그램과 상호 작용할 수 있는 기능을 제공한다. 이 SDK를 통해 개발자는 eBPF 실행을 런타임에서 검사, 추적 및 분석할 수 있다. 이는 네트워크 정책의 효과를 모니터링하고 최적화하는 데 유용하다.

* eBPF : Linux 커널에서 직접 실행되는 안전하고 효율적인 프로그램을 개발할 수 있는 기술로, 네트워킹, 보안, 성능 모니터링 등 다양한 시스템 레벨 작업을 가능하게 합니다. 이를 통해 사용자 공간에서 커널 공간의 동작을 프로그래밍적으로 확장하고 제어할 수 있습니다​

목차

 

1. 전제 조건

2. fargate 배포 시 고려 사항

3. 샘플 사용하기


1. 전제 조건

아래 내용들을 고려하여 작성한다.

  • private endpoint 사용
  • private ecr 사용
  • private 환경에 접근하여 작업할 수 있는 작업 인스턴스 생성 (기본 세팅 완)
  • vpc endpoint 생성
  • NAT gw 사용
  • namespace와 접근할 iam 을 한번에 관리
  • AWS LBC를 위한 서브넷 태그

2. fargate only 배포 시 고려 사항

2-1. VPC

VPC의 아래 두 옵션은 활성화를 확인해야 한다.

  # Enable DNS resolution
  enable_dns_support   = true

  # Enable DNS hostnames 
  enable_dns_hostnames = true

 

두 옵션은 프라이빗 호스팅 영역에서 DNS 쿼리를 위해 설정하는 값이다. DNS hostname 은 인스턴스에 DNS name 을 부여한다. 이를 통해 인스턴스를 쉽게 찾고 통신할 수 있다. 도메인 이름을 사용하여 VPC 내 리소스를 참조할 수도 있다. DNS resolution은 managed service의 엔드포인트 도메인의 프라이빗 ip 주소를 확인할 때 사용된다.

2-2. fargate profile 과 namespace

Fargate 프로파일은 EKS 클러스터에서 Fargate를 사용하여 파드를 실행하기 위해 필요한 것으로, 파드가 Fargate에서 실행될 수 있게 지정하는 네임스페이스(namespace)와 선택기(selector)를 정의한다.

한마디로, fargate only 환경에서는 생성하고자 하는 namespace의 fargate profile 이 먼저 존재해야 pod 가 올라간다는 의미다.

만약 구성이 되어 있지 않은 상황에서 pod 를 올리게 된다면, fargate 스케쥴러가 fargate profile 확인을 실패하고, 노드 스케쥴러가 재시도하지만, 일반 노드그룹이 없어 계속 pending 상태로 대기한다.

 

2-3. vpc endpoint

일반적으로 private endpoint cluster 를 생성하면, 아래의 vpc endpoint 들을 생성해야 한다.

  • com.amazonaws.ap-northeast-2.s3 (gw)
  • com.amazonaws.ap-northeast-2.ecr.api
  • com.amazonaws.ap-northeast-2.ec2
  • com.amazonaws.ap-northeast-2.ecr.dkr

fargate의 경우 한가지를 더 추가해 주어야 한다. 

  • com.amazonaws.ap-northeast-2.sts

단, ap-northeast-2b에는 vpc endpoint 가 지원되지 않는 경우가 있어, 에러가 날 수 있다. 이 점을 고려해서 코드를 짜야한다.

 

2-4. coreDNS

기본적으로 coreDNS는 워커 노드에 생성된다. eks 를 배포하고 나면 coreDNS의 deployment 는 존재하지만, fargate 위에 생성되지 않는다. 따라서 클러스터에 접근해, deployment 의 설정을 조금 변경해 주어야 한다.

kubectl patch deployment coredns \
    -n kube-system \
    --type json \
    -p='[{"op": "remove", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1compute-type"}]'

 

그러나 테라폼으로 배포하기 때문에 아래 코드로 바로 적용 시킬 수 있다.

module "eks_cluster" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.5.1"

  cluster_addons = {
    kube-proxy = {}
    vpc-cni = {
      resolve_conflicts = "OVERWRITE"
    }
    # coreDNS 는 fargate 위에 올라가지 않으므로 설정이 필요함
    coredns = {
      configuration_values = jsonencode({
        computeType = "Fargate"
      })
    }
  }
  
  ... #생략
  
}

2-5. kube-proxy

당연하게도, fargate 에는 daemonset이 올라가지 않는다. (올라가게 된다면 미친듯이 생성되는 roof에 걸릴지도..)

kube-proxy는 daemonset이기 때문에 해당 환경에서는 올라가지 않는다. 그럼 fargate의 네트워크는 어떻게 통신될까? kube-proxy가 아닌 컨트롤 플레인의 fargate 컨트롤러가 맞춰준다고 한다.

3. 샘플 사용하기

위 내용의 샘플 코드를 작성해서 올려두었다.

git clone https://github.com/o-dev-lab/eks-terraform-sample.git

 

권한이 있는 iam 을 가지고 아래 경로에서 배포할 수 있다.

cd samples/private_fargate

aws configure

terraform init 
terraform plan 
terraform apply

 

배포 전, samples/private_fargate/terraform.auto.tfvars 내용을 변경하여 배포 해야 한다.

+ Recent posts