ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [AWS] EKS - Network(스터디 2주차)
    Infra/Cloud 2023. 5. 2. 10:13

    2주차는 AWS Network관련 내용이다.

    EKS를 공부하면 할 때 뭔가 On-premise 환경에서의 Kubernetes와의 차이점이 신기한 것 같다.

     

    물론 그러한 차이점 때문에 사람들이 EKS를 많이 사용하는 것이 아닐까? 싶다ㅎㅎ

     


     

    < 관리용 인스턴스 자동 접속  스크립트>

     

    GitHub - k8s-ho/eks-tools: I made a useful tool while doing eks study:)

    I made a useful tool while doing eks study:). Contribute to k8s-ho/eks-tools development by creating an account on GitHub.

    github.com

    git clone https://github.com/k8s-ho/eks-tools
    cd eks-tools
    chmod +x enter-eks-2.sh
    ./enter-eks-2.sh [key pair file]

    => aws configure을 등록해주었다면 자동으로 본인의 public ip으로 Security Group을 inboud 정책을 변경하고 생성된 관리용 인스턴스에 접속할 수 있게 해주는 스크립트를 간단하게 만들어 보았다(사실 만들었다기보단 그냥 명령어 모음이다)

     

     


     

    AWS VPC(Virtual Private Cloud):

    - AWS의 ENI를 이해하기 앞서 VPC가 무엇인줄 알아야한다. VPC는 가상의 격리된 네트워크 공간을 구성하는 기술을 의미한다. 사용자는 이 VPC에 자신이 원하는 라우팅, subnet, 게이트웨이 등의 네트워크 구성을 생성할 수 있다. 보통은 이렇게 구성한 VPC로 묶어서 리소스들을 관리하며 원하는 IP대역을 할당해서 사용한다. 오른쪽그림은 스터디에서 제공해준 관리용 인스턴스의 VPC 설정이다. VPC에 원하는 대역을 할당한 것을 볼 수 있으며 아래에 subnet을 나눠놓은 것도 확인이 가능하다.

     

     

    Amazon VPC CNI

    - Amazon VPC CNI Plugin은 Node의 ENI를 관리한다.

    - Amazon VPC CNI는 2가지로 이루어져있으며 다음과 같다.

    • Pod간의 통신이 가능하도록하는 Pod Network 설정관련 CNI Binary(Node의 root filesystem에서 실행되며 Pod가 추가되거나 제거될 때 kubelet에 의해 호출됨)
    • Node의 ENI를 관리하며 사용가능한 IP 또는 Prefix의 warm-pool을 유지하는 ipamd

     

    Amazon VPC CNI Workflow

     

    * ipamd: IP Address Management Daemon

    * Slot: IP 또는 Prefix를 의미함

     

    Amazon VPC CNI Plugin은 Node의 ENI를 관리하며, Node가 Provisioning되면 자동으로 Node의 Subnet에서 Primary ENI에 Slot Pool(CNI 설정에 따라 Slot은 IP주소 또는 Prefix가 될 수 있다)을 할당한다. 이 Pool을 Warm-pool이라고 하며 Node의 instance type의 유형에 따라 그 크기가 결정(이 부분은 뒤에서 설명)된다. Primary ENI에 Slot이 할당되면 Amazon VPC CNI plugin은 Warm-pool이 있는 추가 ENI를 Node에 연결하게되며 이를 Secondary ENI(Default 설정)라고한다.

    Pod 생성 시, Secondary IP Pool에 존재하는 IP를 Pod에 할당하는 방식이므로 Slot이 사전 할당되어있는 Secondary ENI로 인해 EKS는 더 빠르게 Pod를 실행할 수 있게된다. Secondary ENI의 Slot이 모두 소진되면 Amazon VPC CNI는 새로운 Primary ENI를 추가하게되며 Primary ENI의 추가를 통해 확보된 IP Pool과 관계없이 Secondary IP Pool은 순차적으로 소진하게된다(먼저생성된 IP Pool 먼저 소진).

     

    이와 관련이 있는 aws-node Daemonset은 충분한 수의 ENI가 연결되었는지 주기적으로 확인한다. 이러한 Process는 instance가 지원할 수 있는 최대 네트워크 인터페이스 수와 사용할 수 있는 최대 슬롯 수를 모두 사용할 때까지 진행된다. 때문에 instance의 리소스와 밀접한 관련이 있으므로 생성할 Pod 및 Cluster의 대략적인 규모를 생각해서 instance type을 선택하는 것이 좋다.(ENI의 각 첫 번째 IP는 Pod를 위해서 사용할 수 없다고 한다)

     


     

    - [참고] 사실 우리는 1주차 포스팅에서 이미 Amazon VPC CNI를 본적이 있다??

    구축된 EKS cluster object 현황

    => Amazon VPC CNI는 Worker node에 aws-node라는 Daemonset으로 배포된다.

     

     


     

    - Pod를 생성했을 때 Instance의 Interface에 어떤변화가 일어나는지 확인해보자

    192.168.3.0 대역을 사용하는 Node의 interface ENI IP pool 정보
    192.168.3.0 대역을 사용하는 Node의 interface 정보

    * 편의상 192.168.N 대역을 사용하는 node를 N번 node라고 하겠다.

    => 현재 EKS에 worker node가 3개로 구축된 환경이며 각각 node에는 Daemonset으로 배포된 Amazon VPC CNI plugin Pod(aws-node)와 kube-proxy pod가 존재한다. 이 Daemonset들은 Node에 Pod와 연결된 cni pair를 생성하지 않으며 Deployment로 배포된 coreDNS pod로 인해 cni pair가 생성되었다는 것을 추측할 수 있었다. 

     

     

     

    EKS Cluster Worker Node Group Instance들의 Interface 정보
    3번 node에 pod 생성 시, pod ip 확인
    Pod 생성 시, 3번 node에 추가로 생성된 ENI 정보

    => 현재 1번, 2번 node의 경우, coreDNS의 배포로 인해 두번째 Primary ENI가 생성된 상태이다(coreDNS가 2개만 배포되어있어 3번은 현재 두번째 Primary ENI 미존재). 추가적으로 알 수 있던 점은 Primary ENI가 처음 추가되는 시점은, 기존의 Primary ENI의 Secondary IP Pool을 사용하기 시작할 때이다.

     

     

     

    => 3번 node에 pod를 배포하게되면 새로운 primary ENI가 생성된다. 또한 당연히 Pod와 pair를 이루는 veth interface도 생성된다. 새로 생성된 Pod의 IP는 192.168.3.154이며 이는 추가로 생성된  eth1 interface 192.168.3.121의 secondary IP가 아닌 기존의 192.168.3.122의 secondary IP인 것으로 보아 ENI가 새로 생성된다고해서 새로생긴 Primary ENI의 Secondary IP Pool을 가져다 사용하는 것은 아니라는 것을 알 수 있었다. 

     

     

     

     

     

     

    * 하나의 Node에 순차적으로 pod의 숫자를 늘려보면서 알게된 사실은  다음과 같다.

    1. Amazon VPC CNI Plugin은 처음 node에 존재하는 eth0의 secondary Pool을 모두 소진하지 않더라도 미리 추가적으로 Primary ENI eth1을 생성한다.

    2. 추가로 Primary ENI가 생성되었더라도 기존의 eth0의 secondary의 IP pool을 먼저 소진한다.

     

    3. eth0의 secondary IP Pool을 모두 소진하여 eth1의 secondary IP pool을 사용할 차례가오면 추가로 eth2의 Primary ENI를 생성한다. Amazon VPC CNI Plugin은 이러한 process를 instance의 자원이 허락하는한 반복된다(instance의 type:성능에 따라 갯수 상이)

     

    4. 이를 통해 Amazon VPC CNI는 필요 하기전에 미리 Primary ENI를 생성하고 Secondary IP Pool을 할당받아 Pod 생성을 좀더 빠르게 진행한다는 것을 알 수 있었다. 또한 미리 Pod에 할당될 IP를 알 수 있으므로 IP 충돌도 방지할 수 있었다.

     

     

     

    - 그렇다면 Pod들은 Node의 어떤 ENI를 사용해서 통신할까?? tcpdump를 해보자

    * 당연한 것 같지만 실제로 그런지 확인해보자.

    Primary, Secondary IP 정보
    tcpdump 테스트

    => 3번 node에 배포한 pod의 ip는 192.168.3.62로 192.168.3.10의 primary ENI에 할당된 secondary IP Pool에 존재하는 ip이다. 192.168.3.10은 현재 3번 node의 eth1에 해당하는 IP이며 tcpdump 시, 해당 pod는 eth0이 아닌 eth1을 통해서 나가는 것을 확인할 수 있었다.

     

     

    - 혹시모르니 다른 ip로도 진행해보았다.

    => 192.168.3.113의 IP를 가진 Pod의 primary ENI는 192.168.3.122로 3번 node의 eth0 interface에 해당한다. 이 역시, tcpdump를 통해 primary ENI인 eth0 interface를 통해 통신하는 것을 확인할 수 있었다.

     

     

    결과적으로 트래픽이 통신할때, secondary IP Pool에 Binding되어있는 Primary ENI를 통해 나간다는 것을 알 수 있었다. 

     

     


     

    AWS ENI(Elastic Network Interface)

    - 위에서 이미 ENI를 만났지만 한번 더 정리하였다.

    - EKS에서는 VPC의 ENI를 통해 Pod와 Node간의 통신을 진행한다.

     

    Amazon VPC CNI - EKS Best Practices Guides

    Amazon VPC CNI Amazon EKS implements cluster networking through the Amazon VPC Container Network Interface(VPC CNI) plugin. The CNI plugin allows Kubernetes Pods to have the same IP address as they do on the VPC network. More specifically, all containers i

    aws.github.io

    aws ec2 describe-vpcs --filters "Name=isDefault,Values=false" \
    --query 'Vpcs[*].{id:VpcId,cidr:CidrBlock}';kubectl get node,pod -o wide

    Amazon EKS는 Amazon VPC Container Network Interface(VPC CNI) Plugin 통해 Cluster Networking을 구성한다. 이는 마치 kubernetes에서 CNI Plugin을 이용하여 Cluster Network를 구성하는 것과 비슷하다. 특이한 것은 AWS VPC CNI를 사용하면 VPC 네트워크와 Pod가 동일한 네트워크 대역을 가질 수 있다는 점이다. 실제로 확인해보면 VPC의 네트워크 대역내에 Pod와 Node의 ip들이 포함되는 것을 볼 수 있었다.

     

     

    * On-premise kubernetes와 비교

    => Weave-net Plugin을 사용하는 Kubernetes cluster network 정보이다. Pod와 Node의 IP 대역이 전혀 다른 것을 볼 수 있었다. On-premise Kubernetes의 경우, Pod에 할당되는 IP 대역은 기본설정인 경우 CNI Plugin에 따라 조금씩 상이하다(변경 가능)

     

     

     

    - Pod to Pod 통신 비교

    CloudNet AEWS 1기 Gasida study 2주차 자료(왼쪽) / Calico CNI를 사용하는 Overlay(IP-IP) 패킷 캡쳐(오른쪽)

    => EKS에서 Pod와 Node의 네트워크 대역이 같은 이유는 네트워크 최적화 때문이다. On-premise Kubernetes의 네트워크에서는 타 Node의 Pod끼리 통신 시, Overlay Networking(IP-IP, VxLan)을 통해 Encapsulation과 Decapsulation이 진행된다. 이 부분은 당연히 Node의 리소스를 사용할 수 밖에 없다. 반면에 ENI에서는 이러한 과정이 진행되지 않기 때문에 좀 더 자원의 효율을 챙길 수 있고 경로최적화가되며 Overlay Networking 같이 패킷이 변화되는 것이 없기 때문에 장애처리에 수월할 수 있다.

     

    => 다만 Amazon VPC CNI는 Pod와 Node가 같은 대역을 사용하기 때문에 사용할 수 있는 네트워크 범위가 기존 CNI Plugin에 비해 한정적일 수 있다. 예를 들어 같은 범위의 네트워크가 할당되고 자원이 무제한이라 가정한다면 On-premise 대비 더 적은 수의 Pod를 배포할 수 밖에 없다(물론 네트워크 이슈로 대역이 부족하다면 VPC의 할당 CIDR을 늘리는 등의 방법으로 해결이 가능하다)

     

     

     

    - 각각 다른 Worker Node에 존재하는 Pod간 통신 흐름

    테스트할 Pod 정보
    192.168.2.208 node의 ENI 정보 - secondary IP Pool
    192.168.2.208 node에 배포된 해당 Pod와 관련 interface의 tcpdump 결과

    => 이번에는 Pod가 어떤 interface들을 거쳐 통신이 진행되는지 확인해보자. 위의 그림과 테스트 결과에서 보다시피 Pod -> Veth(Pod와 pair) -> eth1 -> eth0 -> Veth(Pod와 pair) -> Pod로 진행되는 것을 볼 수 있으며(어떤 인터페이스를 사용하여 통신하는지는 Node의 ENI 정보 확인하면됨) Calico CNI Plugin 같이 별도의 Virtual Router가 없으니 Overlay된 패킷이 아닌 Native한 직접통신이 진행된다. 결과적으로 각각 다른 Node에 배포된 Pod간의 통신은 해당 Pod의 Secondary IP Pool이 binding되어있는 ENI의 인터페이스로 통신한다는것을 알 수 있었다.

     

     

    - Pod의 외부 통신 흐름(SNAT)

    192.168.2.193 pod에서 www.goolge.com으로 ping 진행 후 tcpdump
    iptables에서 관련 rule 확인
    curl 요청 진행시, rule count가 올라가는 것을 확인

     

    => Pod의 외부 통신의 경우에는 iptables에 의해 SNAT가 진행된다. 192.168.2.193(Pod)에서 www.google.com으로 icmp 패킷이 진행될 때, 192.168.2.193 Pod는 Pod가 배포되어있는 Node의 ip 192.168.2.208로 SNAT되어 전송되는 것을 확인할 수 있었다.

    특이하다고 느낀점은 Node가 다른 Pod간의 통신에서는 해당 Pod의 Secondary IP와 매핑되는 ENI의 interface로 통신이 진행되었으나 외부와의 통신에서는 그런것과 상관없이 해당 node의 eth0 interface로 통신을 한다는 것이다(iptables rule도 그렇게 되어있다)

    Rule 설명은 GPT한테 부탁해보았따!

    => iptables의 rule을 확인해보면 AWS-SNAT-CHAIN-0: EKS Cluster 대역이 아닌 통신에 대해서는 AWS-SNAT-CHAIN-1로 점프하여 진행하라는 rule이 존재하고 AWS-SNAT-CHAIN-1 rule을 통해 외부 통신 시, SNAT(최초의 Node의 ENI)가 진행된다는 것을 알 수 있었다. 

     

     


     

    Node내 Pod 생성 갯수제한(feat. instance type)

    - 최대 파드 생성 갯수

     (Number of network interfaces for the instance type × (number of IP addressess per network interface - 1)) + 2
    # t3 타입의 정보(필터) 확인
    aws ec2 describe-instance-types --filters Name=instance-type,Values=t3.* \
     --query "InstanceTypes[].{Type: InstanceType, MaxENI: NetworkInfo.MaximumNetworkInterfaces, IPv4addr: NetworkInfo.Ipv4AddressesPerInterface}" \
     --output table

    t3, c5관련 갯수

    => 위의 명령에서 Value 값만 원하는 것으로 바꿔주면 instance별 최대 ENI와 IPv4addr 갯수를 볼 수 있다. 참고로 IPv4addr의 갯수가 t3.medium의 경우 6개지만 1개는 ENI에 할당되는 IP로 사용가능한 IP는 5개라고 보면된다. 그래서 총 15개의 IP를 할당할 수 있다.

     

     

     

    - 실제로 Pod 생성 갯수제한이 있나 확인해 보자

    EKS cluster 생성시, 기본적으로 배포되어있던 Pod 갯수

    => node(t3.medium type) 3개인 EKS를 생성하였을 때 존재하는 Pod의 갯수는 총 8개이다. 하지만 위에서 설명했다시피 기존에 배포된 Daemonset(kube-proxy, Amazon VPC CNI plugin)들은 node의 ENI ip를 사용하고 있어 제외되므로 최대 45개를 생성할 수 있는 갯수 중 2개만 사용중이므로 43개까지는 무리없이 생성이 가능할 것이다.

     

     

     

    - Pod 생성 진행

    kubectl create deployment count-test --image=nginx --replicas=43

    => Pod 갯수는 총 51개이며 Daemonset으로 배포된 Pod 6개를 빼면 현재 총 45개의 Pod가 배포된 셈이다. 

     

     

    - Max 갯수인 45개인 상태에서 Pod 하나를 더 생성한다면??

    pending 상태가 되어있는 Pod
    last-pod의 describe

    => 역시 예상했던대로 Pod가 생성되지 않았으며 내용을 보니scheduler를 통해 Pod를 사용할 수 있는 node가 없다는 message를 출력해주고 있었다. 이러한 부분들은 Prefix Delegation, WARM & MIN IP/Prefix Targets, Custom Network 등으로 해결할 수 있다고 하는데 이부분은 나중에 확인해봐야겠다..

     

     


     

    Pod간 접근제어

    Pod와 Pod간의 통신에 대한 내용을 위에서 작성했기에 한번 생각해보았다.

    On-premise Kubernetes Cluster: NetworkPolicy 사용

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: test-network-policy
      namespace: default
    spec:
      podSelector:
        matchLabels:
          test: one
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  test: two

    => Networkpolicy object를 사용하면 방화벽 정책처럼 IP, Port를 설정하던가 아니면 Label을 이용하여 특정 Pod간의 접근이나 Namespace를 selecting한 pod간의 접근제어가 가능하다. 따라서 위처럼 test=two label을 가진 Pod만이 test=one label을 가진 pod에 ping이 가능했고 그외의 pod는 ping loss가 나는 것을 볼 수 있었다. 또한 보다시피 같은 node에 배포된 Pod이던 아니던 상관없이 제어가 가능한 것으로 보여졌다.

     

     

     

    EKS Pod간 접근제어

    EKS에서도 동일하게 NetworkPolicy를 이용해서 Pod간 접근제어를 시도해보았다.

    => 동일한 NetworkPolicy 정책으로 진행하였고 적용되었지만 예상과 달리 ping loss는 일어나지 않고 너무나 원활하게 통신이 되었다.. 왜지...???

     

     

    - Kubernetes CNI plugin Calico

     

    Network Policies

    If you want to control traffic flow at the IP address or port level (OSI layer 3 or 4), NetworkPolicies allow you to specify rules for traffic flow within your cluster, and also between Pods and the outside world. Your cluster must use a network plugin tha

    kubernetes.io

     

    Calico 네트워크 정책 엔진 추가 기능 설치 - Amazon EKS

    Calico 네트워크 정책 엔진 추가 기능 설치 Project Calico는 Kubernetes에 대한 네트워크 정책 엔진입니다. Calico 네트워크 정책 집행을 통해 네트워크 세분화 및 테넌트 격리를 구현할 수 있습니다. 이는

    docs.aws.amazon.com

    helm repo add projectcalico https://docs.tigera.io/calico/charts
    
    echo '{ installation: {kubernetesProvider: EKS }}' > values.yaml
    
    helm show values projectcalico/tigera-operator --version v3.25.1
    
    kubectl create namespace tigera-operator
    
    helm install calico projectcalico/tigera-operator --version v3.25.1 -f values.yaml --namespace tigera-operator
    
    watch kubectl get pods -n calico-system

    EKS에 calico 설치완료
    NetworkPolicy 정상작동 확인

    => Kubernetes 공식홈페이지에 따르면 NetworkPolicy는 Kubernetes 자체에서 제공하는 기능이 아닌 Network Plugin을 통해 제공되는 기능이기 때문이다. 따라서 EKS에서 NetworkPolicy를 통한 Pod간 접근제어를 사용하기 위해서는 NetwokrPolicy를 제공하는 plugin을 설치해줘야 한다(나는 calico를 설치해서 진행했다).

     

     


     

    Kubernetes Service Object

    Service는 동일한 목적을 수행하는 어플리케이션에 단일진입점을 생성하여 균등하게 작업(통신)을 주는 역할을 한다.

     

    Service

    Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.

    kubernetes.io

    => kubernetes의 service type에는 Default로 제공하는 ClusterIP가 있으며 이외에 NodePort, LoadBalancer, ExternalName이 존재한다. 또한 service들은 기본적으로LoadBalancing 기능을 가지고 있다.

     

     

    참고로 pod의 sevice 생성 시에 아래와 같은 명령어로 진행하면 Pod와 함께 Service type: ClusterIP가 같이 생성된다.

    kubectl run testpod --image=nginx --port=80 --expose

     

     

     

     그렇다면 clusterIP가 정말 LB가 되는지 확인하기위해 deployment를 생성하여 알아보자.

    cat <<EOF | kubectl create -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deploy-test
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - name: deploy-container
            image: nginx
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: service-test
    spec:
      selector:
        app: web
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
    EOF

    다음과 같이 Deployment와 service를 배포하였다.

    ⇒ targetPort: Endpoint의 Port를 의미
    ⇒ Port: Service가 사용하는 Port를 의미
    ⇒ type이 NodePort인 경우의 nodePort: Node에서 사용하는 Port를 의미

     

     

     

    LoadBalance 확인을 위해 nginx의 index.html 파일을 수정

    => 각각의 Pod의 nginx index.html을 수정해주고 clusterIP에 curl을 시도하게되면  LoadBalancing하게 통신이 되는 것을 확인할 수 있었다.

     

     

    - LoadBalancing이 가능한 이유??

    service object의 endpoint 정보
    service endpoint 관련 iptables rule

     

    Virtual IPs and Service Proxies

    Every node in a Kubernetes cluster runs a kube-proxy (unless you have deployed your own alternative component in place of kube-proxy). The kube-proxy component is responsible for implementing a virtual IP mechanism for Services of type other than ExternalN

    kubernetes.io

    CloudNet AEWS 1기 Gasida study 2주차 자료 - ClusetrIP

    => 이것이 가능한 이유는 service object 생성시, serivce에서 selector된 Pod들이 존재하는 각각 Node의 kube-proxy에서 생성해내는 iptables rule로 인해 LoadBalancing이 이루어지게 되는 것이다. 때문에 iptables Rule을 보게되면 특정 확률(Selecotr에 연결된 Pod 갯수의 기준)로 패킷을 다른 rule로 jmp시켜 LoadBalancing을 구현한 rule이라는 것을 알 수 있다.

    => 이러한 iptables 기반은 다른 kubernetes Service object type에도 사용된다.

     

     

    - NodePort

    CloudNet AEWS 1기 Gasida study 2주차 자료 - NodePort type

    => Kubernets Cluster를 외부에서 접근할 때 사용한다. 단점이 있다면 외부에 해당 Node에 대한 정보를 노출해야한다는 단점이 있다. 때문에 사용시에는 Node에 접근하는 Security Rule도 확인해주어야한다.

     

     

     

    - LoadBalancer

    CloudNet AEWS 1기 Gasida study 2주차 자료 - LoadBalancer Type (Network LB)

     

    AWS GUI에서도 확인이 가능하다.
    CLB LoadBalancer 확인 시, node 정보가 매핑되어있는 것을 확인할 수 있음
    LoadBalancer DNS로 접근해보기

    => Kubernetes Cluster를 외부에서 접근할 때 사용하며 위의 NodePort와 다르게 Node정보를 노출하지 않는다는 장점이 있다. 생성시, EXTERNAL-IP 값이 생겨나고(생성 이후에도 조금 기다려야함) 이를 이용하여 k8s Cluster외부에 존재하는 LoadBalancer와 NodePort -> iptables rule을 통해 binding된 서비스(Pod)에 접근할 수 있게된다. 이 때 연결되는 외부 LoadBalancer는 Kubernetes Cluster 외부에 존재하는 Amazon ELB(Elastic Load Balancer)이며 type은 Default 값은 classic이다(CLB, NLB, ALB, GLB 등이 있다.)

     

     

    - Network LB로 변경하려면??

     

    Service

    Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.

    kubernetes.io

    apiVersion: v1
    kind: Service
    metadata:
      annotations:       									   # <- 추가
        service.beta.kubernetes.io/aws-load-balancer-type: nlb # <- 추가
      name: test
      namespace: default
    spec:
      allocateLoadBalancerNodePorts: true
      clusterIP: 10.100.220.206
      clusterIPs:
      - 10.100.220.206
      externalTrafficPolicy: Cluster
      internalTrafficPolicy: Cluster
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - nodePort: 32284
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: test
      sessionAffinity: None
      type: LoadBalancer
    status:
    ...

    추가된 Network ELB와 target으로 instance의 nodePort가 확인됨

    => Amazon LoadBalancer Network LB type의 경우 kubernetes service object 설정 내의 metadata.annotation 값 service.beta.kubernetes.io/aws-load-balancer-type: nlb통해 지정이 가능하다. 또한 변경시 Network ELB가 추가로 생성되며 targetGroup에서 binding된 Node 정보를 확인할 수 있다.

     

     


     

    - LoadBalancer Controller + AWS VPC CNI 

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
        service.beta.kubernetes.io/aws-load-balancer-type: nlb
    ...

    => 위에서 target-type관련 annotations가 존재해야 실습에서의 controller의 제 기능이 동작한다.

     

     

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

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

    docs.aws.amazon.com

    CloudNet AEWS 1기 Gasida study 2주차 자료(좌) - LoadBalancer Controller + NLB IP mode(AWS VPC CNI) /  LoadBalancer Controller Role(우)

    위의 구성에서는 외부에 Aws LoadBalancer의 Domain으로 접근하게되고 Service(NodePort)와 iptables 없이 바로 목적지 Pod에 접근이 가능하다.

     

     

    - Network LB로 kubernetes service object를 배포해서 좀더 자세히 확인해보면..

    Aws LoadBalancer -> TargetGroup
    배포되어있는 Pod IP 확인

    기본적인 Amazon LoadBalancer의 경우 TargetGroup이 NodePort이지만 현재 Pod로 바로 연결된 것을 볼 수 있다. 이것이 가능한 이유는 각각의 역할을 이해해야한다. 

     

    -------(내용수정중)-------

    * Amazon VPC CNI의 역할:
    기본적으로 Node에 ENI를 할당하며 secondary IP Pool을 통해 Pod IP도 할당함. 또한 VPC Routing table을 관리함.

     

    * Amazon LoadBalancer의 역할:
    Kubernetes cluster 외부에 존재하지만 AWS에서는 VPC내에 존재함. VPC CNI가 관리하는 VPC routing table을 참고하기 때문에 Pod와 Node ip를 인식하게됨

     

     

    * LoadBalancer Controller의 역할:
    LoadBalancer Controller의 clusterrole binding에 의해 Kubernetes API Server와 연결되어 cluster 내의 service 및 endpoint에 대한 정보를 받아알고 있게되며 Kubernetes의 LoadBalancer 타입 서비스를 감지하고, AWS API를 사용하여 해당 서비스를 대상으로 하는 Classic Load Balancer, Application Load Balancer 또는 Network Load Balancer를 생성한다.이후 Load Balancer Controller는 생성된 Amazon LB의 DNS 이름을 Kubernetes 클러스터 내의 서비스에 할당하여 클러스터 내의 Pod들이 Amazon LB를 통해 접근할 수 있게 한다. 이 과정에서 VPC CNI가 등록한 Pod IP 대역을 이용하여, Amazon LB와 Pod 사이의 네트워크 통신이 가능하도록 함.

     

     

    이것이 가능한 이유는 Amazon VPC CNI로 인해 Node IP와 Pod의 IP를 모두 알고 있으며 이를 통해 Aws LoadBalancer에서 Pod의 IP를 바로 알 수 있게 된다. 때문에 기본 동작방식인 LoadBalancer에서 NodePort와 iptables를 거치는 과정없이 바로 Pod가 Amazon LB의 target group이 되어 통신할 수 있게 되는 것이다(이 과정을 줄일 수 있기에 좀 더 효율적인 통신이 가능하다)

    -------(내용수정중)-------

     

     

    - 이 때 LoadBalancer Controller에 권한을 부여하기위한 Role을 생성하는 것이 바로 IAM Policy이다.

    Role로 사용될 IAM Policy 등록

    curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json
    aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

    Aws LoadBalancer는 목적지 대상 target이 추가되거나 제거되는 작업이 수행되는데  위의 구조에서는 이를  LoadBalancer Controller가 하게 된다. 때문에 LoadBalancer Controller에는 Aws LoadBalancer를 통제할 수 있는 권한이 필요하며  LoadBalancer Controller는 결국 Kubernetes에 속해있기 때문에 Aws의 object인 Aws LoadBalancer를 통제하기 위해서는 인증, 권한에 관련된(IRSA)설정이 필요하다.

     

     

    IRSA(IAM Roles for Service Accounts) 생성 -> 이 부분은 추후 Security에서 자세히.....

    eksctl create iamserviceaccount --cluster=$CLUSTER_NAME --namespace=kube-system --name=aws-load-balancer-controller \
    --attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve

    => AWS Load Balancer Controller를 위한 ServiceAccount를 생성하고 위에서 만든 IAM Role을 Binding 시켜준다. 위의 명령을 진행하게되면 Kubernetes Cluster의 kube-system namespace에 serivceaccount가 생성되며 metadata.annotations에 eks의 arn(amazon resource number)값으로 IAM에 생성했던 role이 부여된 것을 확인할 수 있었다(이 role은 이전에 생성한 IAM policy 즉, AWS LB를 통제할 수 있는 role이다)

     

     

    LoadBalancer Controller 배포 - helm 사용

    이제 위에서 생성한 IRSA와 helm을 사용해서 LoadBalancer Controller를 배포해보겠다.

    # helm 배포
    helm repo add eks https://aws.github.io/eks-charts
    helm repo update
    helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \
      --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller
      
      
    # 정상배포 확인
    kubectl get crd
    kubectl describe deploy -n kube-system aws-load-balancer-controller
    
    
    # ClusterRole, Role 확인
    kubectl describe clusterrolebindings.rbac.authorization.k8s.io aws-load-balancer-controller-rolebinding
    kubectl describe clusterroles.rbac.authorization.k8s.io aws-load-balancer-controller-role

    aws-load-balancer-controller에 biniding되어있는 Clusterrole

    => ServiceAccount는 이전에 생성했으니까 false로 주고 aws-load-balancer-controller를 ServiceAccount로 설정해준다.  aws-load-balancer-controller에 binding되어있는 clusterrole을 확인할 수 있었다. 참고로 clusterrole은 특정 namespace에 한정되지 않고 전체에 적용된다.

     

     

    - Network LoadBalancer Mode 종류

     

    Service

    Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.

    kubernetes.io

    Aws LoadBalancer 화면
    kubernetes service object(type: LoadBalancer)의 External Traffic Policy

    => EKS에서 service object type을 LoadBalancer로 생성하면 kubernetes 외부에 AWS LoadBalancer가 생성되면서 binding되는데 이때 kubernetes serivce의 policy 설정에 따라 external traffic이 조금씩 상이하게 동작한다.

     

     

    * 인스턴스 유형

    (spec.externalTrafficPolicy)

    1. externalTrafficPolicy : ClusterIP(Default 설정) ⇒ 2번의 분산 및 SNAT으로 Client IP 확인이 불가능함
    2. externalTrafficPolicy : Local ⇒ 1번 분산 및 ClientIP를 유지하며  Worker Node의 iptables rule을 사용함

     

     

    * IP 유형 -> LoadBalancer Controller 사용 시

    (metadata.annotations. service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*")

    1. Proxy Protocol v2 비활성화 ⇒ NLB에서 바로 Pod로 인입, 단 ClientIP가 NLB로 SNAT 되어 Client IP 확인 불가능
    2. Proxy Protocol v2 활성화 ⇒ NLB에서 바로 Pod로 인입 및 ClientIP 확인 가능(→ 단 PPv2 를 애플리케이션이 인지할 수 있게 설정 필요)

     


     

    Ingress

    kubernetes 내부의 서비스(ClusterIP, NodePort, LoadBalancer)를 외부로 노출하는 Web-proxy역할을 한다.

    CloudNet AEWS 1기 Gasida study 2주차 자료 - Ingress

    kubernetes cluster 내부의 service obejct(ClusterIP, NodePort, LoadBalancer)를 HTTP/HTTPS 방식으로 외부로 노출시켜주는 Web Proxy 역할을 한다. 위의 구성에서는 그림 그대로 Application LB를 통해 Pod 서비스를 제공하는 방식으로 볼 수 있을 것 같다.

     

    => 이 부분은 좀더 분석해서 내용 업데이트가 필요할 것 같다...


     

    마지막으로 스터디의 멤버중 한분이신 "이지오님"이 만들어 공유해주신 Network 마인드맵이다.
    2주차 스터디 관련 내용이 한눈에 잘보이는 좋은 그림인 것 같다!!ㅎㅎ

    반응형

    댓글

Designed by Tistory.