AWS announces preview of AWS Interconnect - multicloud
AWS announces AWS Interconnect – multicloud (preview), providing simple, resilient, high-speed private connections to other cloud service providers. AWS Interconnect - multicloud is easy to configure and provides high-speed, resilient connectivity with dedicated bandwidth, enabling customers to interconnect AWS networking services such as AWS Transit Gateway, AWS Cloud WAN, and Amazon VPC to other cloud service providers with ease.
AWS EKS에서 Node의 EC2 타입과 --max-pods 설정간 관계
본 기사에서는 AWS EKS의 노드의 EC2 인스턴스 타입에 따라 kubelet에서 최대로 Pod를 배치할 수 있는 —max-pods 설정간 관계에 대해 설명합니다. 또한 kubelet의 --max-pods 설정이 Pod 배치에 미치는 영향에 대해 설명합니다. 이 기사에서는 Pod 배치에 영향을 미치는 다른 리소스에 대해서는 고려하지 않습니다.
AWS EKS 클러스터에는 Pod를 하나 이상 배치할 수 있는 EC2 Node가 포함되어 있습니다. EC2 인스턴스의 유형이 다양한 만큼 Node 역시 다양한 유형의 인스턴스를 사용할 수 있습니다. 인스턴스 유형 별 컴퓨팅, 메모리, 스토리지 및 네트워크 기능들이 다양하게 제공되나 이 기사에서는 탄력적 네트워크 인터페이스(Elastic Network Interface)에 대해 집중적으로 다루어보겠습니다.
각 EC2 인스턴스는 유형별로 사용 가능한 네트워크 인터페이스(ENI)와 각 네트워크 인터페이스 별 프라이빗 IP 주소가 각각 다르게 지정되어 있습니다. [1]
예를 들어 m5.large 타입의 인스턴스의 경우, 최대 사용 가능한 네트워크 인터페이스는 3개, 각 네트워크 인터페이스 별로 프라이빗 IPv4는 10개 그리고 프라이빗 IPv6는 10개로 지정되어 있습니다.
$ aws ec2 describe-instance-types --filters "Name=instance-type,Values=m5.large" --query "InstanceTypes[].{Type: InstanceType, MaxENI: NetworkInfo.MaximumNetworkInterfaces, IPv4addr: NetworkInfo.Ipv4AddressesPerInterface, IPv6addr: NetworkInfo.Ipv6AddressesPerInterface}" --output table
------------------------------------------------
| DescribeInstanceTypes |
+----------+------------+---------+------------+
| IPv4addr | IPv6addr | MaxENI | Type |
+----------+------------+---------+------------+
| 10 | 10 | 3 | m5.large |
+----------+------------+---------+------------+
이러한 네트워크 인터페이스 설정으로 인해 kubelet[2]에 실행 가능한 최대 Pod 수를 나타내는 --max-pods 값에 적당한 값을 입력할 필요가 있습니다. 이를 위해 EKS AMI에서는 자동으로 —max-pods를 계산하기 위한 max-pods-calculator.sh[3] 및 각 인스턴스 타입별로 이미 계산된 결과인 eni-max-pods.txt[4]를 제공하고 있습니다.
최대 실행 가능한 Pod 수를 계산하는 계산식은 다음과 같습니다.
# of ENI * (# of IPv4 per ENI - 1) + 2
인스턴스 타입별로 정의된 네트워크 인터페이스에서 사용 가능한 프라이빗 IP 주소에서 네트워크 인터페이스의 첫번째 IP를 제외한 갯수만큼 Pod를 사용할 수 있으며 각 Node에서 기본적으로 호스트 네트워크를 사용하는 Pod인 aws-node와 kube-proxy Pod를 위해 임의로 2를 더한 갯수로 계산해 최대 사용 가능한 Pod 수를 정의합니다.
위의 계산식을 통해 m5.large 타입의 인스턴스가 사용 가능한 Pod 수는 다음과 같이 계산할 수 있습니다.
3 * (10 - 1) + 2 = 29
샘플 Pod를 통해 배포 테스트를 진행해보았습니다.
-
m5.large 타입 인스턴스 노드를 1개 생성합니다.
$ kubectl get nodes -A NAME STATUS ROLES AGE VERSION ip-10-0-147-219.ec2.internal Ready <none> 98s v1.27.6-eks-a5df82a -
클러스터에 노드가 1개만 존재하는 경우 호스트 네트워크를 사용하는 파드와 coredns 2개가 위치하게 됩니다.
$ kubectl get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system aws-node-xn476 1/1 Running 0 3m22s kube-system coredns-79df7fff65-fspsl 1/1 Running 0 12m kube-system coredns-79df7fff65-psggs 1/1 Running 0 12m kube-system kube-proxy-628x7 1/1 Running 0 3m22s -
샘플 Deployment의 replica를 25로 설정하여 배포합니다. [5]
$ kubectl get deployment -A NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE game-2048 deployment-2048 25/25 25 25 9m11s kube-system coredns 2/2 2 2 19m -
Deployment Pod 25개, coredns Pod 2개, aws-node, kube-proxy까지 총 29개의 Pod가 정상 배포되었음을 확인할 수 있습니다.
$ kubectl get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES game-2048 deployment-2048-8886b7b6b-2kr9j 1/1 Running 0 27s 10.0.147.98 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-2xfmd 1/1 Running 0 27s 10.0.151.226 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-446l4 1/1 Running 0 26s 10.0.149.12 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-5bpv8 1/1 Running 0 27s 10.0.153.85 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-7mgdp 1/1 Running 0 27s 10.0.145.12 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-7srh9 1/1 Running 0 27s 10.0.158.114 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-8hnkt 1/1 Running 0 82s 10.0.152.6 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-8vlmb 1/1 Running 0 26s 10.0.147.178 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-dz9rj 1/1 Running 0 26s 10.0.157.96 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-g9tbq 1/1 Running 0 27s 10.0.155.26 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-gmmbz 1/1 Running 0 82s 10.0.159.126 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-gnb84 1/1 Running 0 82s 10.0.148.62 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-hg2bp 1/1 Running 0 82s 10.0.152.145 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-jtx6k 1/1 Running 0 82s 10.0.147.52 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-kj8sh 1/1 Running 0 91s 10.0.157.169 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-ldmzd 1/1 Running 0 26s 10.0.159.74 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-lwsbb 1/1 Running 0 26s 10.0.152.77 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-mdsh9 1/1 Running 0 82s 10.0.159.157 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-pdslz 1/1 Running 0 26s 10.0.152.49 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-ptmm2 1/1 Running 0 26s 10.0.155.201 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-r86w4 1/1 Running 0 82s 10.0.145.3 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-tdzgd 1/1 Running 0 27s 10.0.145.24 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-tpjkf 1/1 Running 0 91s 10.0.158.178 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-v5r8w 1/1 Running 0 82s 10.0.157.250 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-xczrl 1/1 Running 0 26s 10.0.145.148 ip-10-0-147-219.ec2.internal <none> <none> kube-system aws-node-xn476 1/1 Running 0 10m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-fspsl 1/1 Running 0 18m 10.0.156.64 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-psggs 1/1 Running 0 18m 10.0.154.128 ip-10-0-147-219.ec2.internal <none> <none> kube-system kube-proxy-628x7 1/1 Running 0 10m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none> -
Deployment Pod의 replica를 1개 증가시켜 26개로 증가하였습니다.
$ kubectl get deploymemt -A NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE game-2048 deployment-2048 25/26 26 25 10m kube-system coredns 2/2 2 2 20m -
추가된 Pod 1개가
Too many Pod메시지와 함께 Pending 상태로 유지됨을 확인할 수 있습니다.$ kubectl get pods -A -o wide ... game-2048 deployment-2048-8886b7b6b-j9h69 0/1 Pending 0 10s <none> <none> <none> <none>$ kubectl describe pod deployment-2048-8886b7b6b-j9h69 -n game-2048 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 84s (x2 over 6m49s) default-scheduler 0/1 nodes are available: 1 Too many pods. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod..
DaemonSet이 있는 경우
DaemonSet을 배포한 경우에 어떤 영향이 있는지 살펴보겠습니다.
-
이전의 샘플에서 26개까지 증가시킨 Deployment를 0으로 초기화시키겠습니다.
$ kubectl scale -n game-2048 deploy/deployment-2048 --replicas 0 deployment.apps/deployment-2048 scaled -
DaemonSet을 배포합니다.[6]
$ kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml -
DaemonSet이 설치되었습니다.
$ kubectl get ds -A NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE kube-system aws-node 1 1 1 1 1 <none> 32m kube-system fluentd-elasticsearch 1 1 1 1 1 <none> 8s kube-system kube-proxy 1 1 1 1 1 <none> 32m$ kubectl get pods -A -o wide NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES kube-system aws-node-xn476 1/1 Running 0 24m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-fspsl 1/1 Running 0 33m 10.0.156.64 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-psggs 1/1 Running 0 33m 10.0.154.128 ip-10-0-147-219.ec2.internal <none> <none> kube-system fluentd-elasticsearch-pmsf7 1/1 Running 0 69s 10.0.157.169 ip-10-0-147-219.ec2.internal <none> <none> kube-system kube-proxy-628x7 1/1 Running 0 24m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none> -
Deployment의 Replica를 다시 25로 증가시킵니다.
$ kubectl scale -n game-2048 deploy/deployment-2048 --replicas 25 deployment.apps/deployment-2048 scaled$ kubectl get pods -A -o wide [23/11/5| 3:45PM] NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES game-2048 deployment-2048-8886b7b6b-6g4cv 0/1 Pending 0 56s <none> <none> <none> <none> game-2048 deployment-2048-8886b7b6b-6k7kt 1/1 Running 0 56s 10.0.157.96 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-7cfkn 1/1 Running 0 56s 10.0.159.126 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-7gd9r 1/1 Running 0 56s 10.0.159.74 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-8dg6s 1/1 Running 0 56s 10.0.145.3 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-9k9ss 1/1 Running 0 56s 10.0.155.15 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-9nzhc 1/1 Running 0 56s 10.0.145.148 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-fkj44 1/1 Running 0 56s 10.0.149.12 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-gpbqq 1/1 Running 0 56s 10.0.148.62 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-jlb5x 1/1 Running 0 56s 10.0.158.52 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-k7rn2 1/1 Running 0 56s 10.0.147.178 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-kjvp5 1/1 Running 0 56s 10.0.146.214 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-m2v8m 1/1 Running 0 56s 10.0.147.99 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-nnl5d 1/1 Running 0 56s 10.0.149.148 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-pqkl7 1/1 Running 0 56s 10.0.147.52 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-r87cf 1/1 Running 0 56s 10.0.145.222 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-rw8lr 1/1 Running 0 56s 10.0.159.157 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-s2cnk 1/1 Running 0 56s 10.0.155.201 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-t649h 1/1 Running 0 56s 10.0.152.49 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-thk4m 1/1 Running 0 56s 10.0.153.85 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-v2dsh 1/1 Running 0 56s 10.0.152.38 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-x6lv5 1/1 Running 0 56s 10.0.154.102 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-xwc5w 1/1 Running 0 56s 10.0.152.77 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-z7ql8 1/1 Running 0 56s 10.0.146.60 ip-10-0-147-219.ec2.internal <none> <none> game-2048 deployment-2048-8886b7b6b-z8vp9 1/1 Running 0 56s 10.0.158.178 ip-10-0-147-219.ec2.internal <none> <none> kube-system aws-node-xn476 1/1 Running 0 26m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-fspsl 1/1 Running 0 35m 10.0.156.64 ip-10-0-147-219.ec2.internal <none> <none> kube-system coredns-79df7fff65-psggs 1/1 Running 0 35m 10.0.154.128 ip-10-0-147-219.ec2.internal <none> <none> kube-system fluentd-elasticsearch-pmsf7 1/1 Running 0 2m55s 10.0.157.169 ip-10-0-147-219.ec2.internal <none> <none> kube-system kube-proxy-628x7 1/1 Running 0 26m 10.0.147.219 ip-10-0-147-219.ec2.internal <none> <none>$ kubectl describe pod deployment-2048-8886b7b6b-6g4cv -n game-2048 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 112s (x2 over 114s) default-scheduler 0/1 nodes are available: 1 Too many pods. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod..
기존과 동일하게 25개로 Pod를 배포하였으나 Pod 1개가 Too many Pod 메시지와 함께 Pending 상태로 유지됨을 확인할 수 있습니다.
기존 25개 모두 배포되었을 때와 비교하면 현재는 인스턴스의 프라이빗 IP 중 하나가 사용중이지 않은 상태입니다.
이러한 예시를 통해 다음과 같은 내용을 확인할 수 있었습니다.
- --max-pods 에 호스트 네트워크를 사용하는 Pod의 갯수가 포함됩니다.
- 호스트 네트워크를 사용하는 Pod를 사용하는 경우, 사용 가능한 프라이빗 IP가 남아 있음에도 Pod를 배포할 수 없습니다.
이미 —max-pods 계산식에도 호스트 네트워크를 사용하는 aws-node, kube-proxy 파드에 대해 고려되어 +2가 포함되었으나 그 외에 사용자가 생성한 별도의 DaemonSet 혹은 Amazon EBS CSI 드라이버[7], Amazon EFS CSI 드라이버[8] 등을 사용하는 경우에는 프라이빗 IP를 사용하지 않는 Pod로 인해 프라이빗 IP는 남아있지만 더 이상 Pod를 배포할 수 없는 상황이 발생할 수 있습니다.
만일 클러스터 사용시 호스트 네트워크를 사용하는 Pod에 대해 예상할 수 있는 상황이신 경우에는, Pod 배치에 대해 사전에 고려하시어 —max-pods 값을 증가시켜 Node에 사용 가능한 프라이빗 IP 낭비 없이 Pod를 배치 하실 수 있습니다.
References:
[1] https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI
[2] https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
[3] https://github.com/awslabs/amazon-eks-ami/blob/master/files/max-pods-calculator.sh
[4] https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt
[6] https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/#create-a-daemonset
[7] https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/ebs-csi.html
[8] https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/efs-csi.html
- 주제
- 컨테이너
- 언어
- 한국어
관련 콘텐츠
AWS 공식업데이트됨 10달 전