본문 바로가기
카테고리 없음

K8S의 네트워크와 AWS VPC CNI

by james_janghun 2023. 3. 19.

CNI

- CNI란, Container Network Interface의 약자로 컨테이너 간의 네트워크를 정의하는 인터페이스를 말한다.

- 기본적으로 Kubernetes에서 사용되는 CNI는 Calico, Flannel 등이 유명하고, AWS에서는 AWS VPC CNI라는 자체 CNI를 제공한다.

- 현재까지는 KOPS에서는 POD 단위의 보안그룹 적용이 되지 않는다. (EKS는 가능)

 

AWS VPC CNI

우리가 EKS 환경에서 실습을 하기 때문에 AWS VPC CNI에 대해서 조금 더 알아보자.

AWS VPC CNI의 경우 파드의 IP 네트워크 대역이 해당 노드의 IP 대역과 같게 설정되어 직접 통신이 가능하다는 장점이 있다.

아래 그림에서 확인할 수 있듯 Calico에서는 node와 pod의 ip 대역이 다르지만 AWS VPC CNI의 경우 같다.

Calico와 AWS VPC CNI 비교

 

Pod간 통신으로 넘어가 보면 pod1에서 pod2로 패킷이 전달될 때 Calico는 원본 패킷이 IP대역대의 변화로 인해 오버레이 통신을 진행하고, AWS VPC CNI의 경우 IP 대역대가 동일하기 때문에 원본 패킷을 그대로 전달 할 수 있다.

 

노드 간 파드 통신

앞서 보았듯 AWS VPC CNI의 경우 별도 오버레이 통신 기술 없이 VPC Native 통신이 가능하다.

 

# 파드 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})

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

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

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

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

# routing table management 확인
ip route show table local

 

파드에서 외부로의 통신

AWS VPC CNI에서 파드가 외부 통신하는 경우 다음과 같다. iptable에 SNAT를 통해 노드의 eth0 IP로 변경되 외부와 통신할 수 있다.

# 각 워커 노드에서 tcpdump 실행
sudo tcpdump -i any -nn icmp

# ping 테스트
kubectl exec -it $PODNAME1 -- ping -c 1 www.google.com
kubectl exec -it $PODNAME2 -- ping -c 1 www.google.com

# 파드가 외부와 통신시에는 아래 처럼 'AWS-SNAT-CHAIN-0, AWS-SNAT-CHAIN-1' 룰(rule)에 의해서 SNAT 되어서 외부와 통신!
# 참고로 뒤 IP는 eth0(ENI 첫번째)의 IP 주소이다
# --random-fully 동작 - 링크1  링크2
sudo iptables -t nat -S | grep 'A AWS-SNAT-CHAIN'
-A AWS-SNAT-CHAIN-0 ! -d 172.30.0.0/16 -m comment --comment "AWS SNAT CHAIN" -j AWS-SNAT-CHAIN-1
-A AWS-SNAT-CHAIN-1 ! -o vlan+ -m comment --comment "AWS, SNAT" -m addrtype ! --dst-type LOCAL -j SNAT --to-source 172.30.85.242 --random-fully

 

 

max-pod 설정

기본적으로 AWS 워커 노드에서 생성 가능한 최대 파드 갯수 제한이 있다. 네트워크 인터페이스는 3개, Secondary IPv4는 5개씩 할당 가능하다.  

- secondary IPv4 : 인스턴스 유형에 따라 최대 ENI 갯수와 할당 가능 IP 수를 조합해 선정

 

기본적으로 aws-node와 kube-proxy 파드는 제외하고 최대 갯수는 다음 공식대로 구할 수 있다. (뒤의 +2가 제외되는 2개이다)

최대 파드 생성 갯수 ( 인스턴스의 타입 별 최대 ENI 갯수 * ( ENI에 할당 가능한 최대 IP 갯수 - 1 ) ) + 2

 

aws ec2 describe-instance-types --filters Name=instance-type,Values=c5d.* \
 --query "InstanceTypes[].{Type: InstanceType, MaxENI: NetworkInfo.MaximumNetworkInterfaces, IPv4addr: NetworkInfo.Ipv4AddressesPerInterface}" \
 --output table
 
 --------------------------------------
|        DescribeInstanceTypes       |
+----------+----------+--------------+
| IPv4addr | MaxENI   |    Type      |
+----------+----------+--------------+
|  15      |  4       |  t3.2xlarge  |
|  6       |  3       |  t3.medium   |
|  12      |  3       |  t3.large    |
|  15      |  4       |  t3.xlarge   |
|  2       |  2       |  t3.micro    |
|  2       |  2       |  t3.nano     |
|  4       |  3       |  t3.small    |
+----------+----------+--------------+

만약 위의 표처럼 t3.medium을 예로 들면 MaxENI 3 * (IPv4addr 6 - 1 ) + 2 이므로 총 17개가 생성 가능하다. 

 

이를 해결하기 위해서는 LimitRange 설정인 kubelet의 max-pods 태그를 수정하거나

AWS VPC CNI애서 (ENABLE_PREFIX_DELEGATION, WARM_PREFIX_TARGET)을 수정하면 설정 값을 늘릴 수 있다.

 

LimitRange를 확인하는 방법은 다음과 같은데, 기본적으로 컨테이너에게 0.1cpu를 보장하기 때문에 해당 설정 값을 제거해서 제한을 푸는 것이다.

# LimitRanges 기본 정책 확인 : 컨테이너는 기본적으로 0.1CPU(=100m vcpu)를 최소 보장(개런티)
kubectl describe limitranges
Name:       limits
Namespace:  default
Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---  ---  ---------------  -------------  -----------------------
Container   cpu       -    -    100m             -              -

# LimitRanges 기본 정책 삭제
kubectl delete limitranges limits
kubectl get limitranges

 

KOPS를 통한 VPC CNI 수정

# 수정 전 env 정보 확인 : WARM_PREFIX_TARGET은 기본값이 1로 이미 되어 있음
kubectl describe ds -n kube-system aws-node | grep ADDITIONAL_ENI_TAGS: -A22
      ADDITIONAL_ENI_TAGS:                    {"KubernetesCluster":"gasida.link","kubernetes.io/cluster/gasida.link":"owned"}
      AWS_VPC_CNI_NODE_PORT_SUPPORT:          true
      AWS_VPC_ENI_MTU:                        9001
      AWS_VPC_K8S_CNI_CONFIGURE_RPFILTER:     false
      AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG:     false
      AWS_VPC_K8S_CNI_EXTERNALSNAT:           false
      AWS_VPC_K8S_CNI_LOGLEVEL:               DEBUG
      AWS_VPC_K8S_CNI_LOG_FILE:               /host/var/log/aws-routed-eni/ipamd.log
      AWS_VPC_K8S_CNI_RANDOMIZESNAT:          prng
      AWS_VPC_K8S_CNI_VETHPREFIX:             eni
      AWS_VPC_K8S_PLUGIN_LOG_FILE:            /var/log/aws-routed-eni/plugin.log
      AWS_VPC_K8S_PLUGIN_LOG_LEVEL:           DEBUG
      DISABLE_INTROSPECTION:                  false
      DISABLE_METRICS:                        false
      DISABLE_NETWORK_RESOURCE_PROVISIONING:  false
      ENABLE_IPv4:                            true
      ENABLE_IPv6:                            false
      ENABLE_POD_ENI:                         false
      ENABLE_PREFIX_DELEGATION:               false
      WARM_ENI_TARGET:                        1
      WARM_PREFIX_TARGET:                     1


# kops 클러스터와 인스턴스 그룹에 파라미터 수정 : 노드에 kubelet 에 maxPods 110개로 수정, Prefix Assign 활성화 
kops edit cluster
...
  kubelet:
    anonymousAuth: false
    maxPods: 110
...
  networking:
    amazonvpc:
      env:
      - name: ENABLE_PREFIX_DELEGATION
        value: "true"
...

 

 

이상으로 AWS VPC CNI를 기반으로 한 EKS의 네트워킹에 대해서 확인해보았다.

쿠버네티스를 온프레미스 환경에서 운영하는 것 보다는 확실히 EKS에서도 많은 최적화가 되어있고 

오히려 AWS 서비스를 이용하는 사람들이라면 쿠버네티스 운영에 EKS가 더 효율적이라고 생각해볼 수 있는 구간이였다.