Amazon VPC CNI로 구성된 네트워크 환경을 확인해보자.
이러한 과정을 통해서 VPC CNI 동작과정에 대해서 실제로 어떻게 흘러가는지 알 수 있다.
이러한 실습 환경을 구축하기 위해서는 YAML 다운로드를 통해서 CloudFormation 스택을 정의해서 생성하면 한번에 생성이 가능하다.
Amazon VPC CNI 구성 환경에서 기본적인 네트워크 정보를 확인해보자.
// kube-system의 daemonset 확인
kubectl get daemonset -n kube-system
// kube-proxy config 확인
kubectl describe cm -n kube-system kube-proxy-config
// vpc-cni 정보 확인
kubectl describe daemonset aws-node -n kube-system | grep Image | cut -d "/" -f 2
kube-system에 설치된 daemonset을 확인해보자.
다음과 같이 aws-node
와 kube-proxy
2개의 데몬셋 파드가 배포되어있는 것을 확인할 수 있다.
먼저 kube-proxy
는 워커노드에서 서비스와 파드간 통신(로드밸런싱 포함)을 해주는 K8S의 컴포넌트이다.
즉, 서비스로 들어온 트래픽을 실제 파드로 전달하는 것을 kube-proxy
가 담당한다. 이 때, 어떤 방식을 사용해서 들어온 트래픽을 전달/분배할 지를 다음과 같이 mode
로 설정할 수 있다. 여기서는 iptables 방식을 사용했다.
(가독성을 위해 전체에서 mode
쪽만 캡쳐하였다.)
AWS VPC CNI의 kube-proxy는 iptables 방식을 사용하는데, 리눅스 커널에 구성되는 iptables를 kube-proxy가 관리하고 제어한다. iptables에 대한 자세한 사항은 여기를 참고
aws-node
는 AWS VPC CNI를 설치하면 자동으로 각 노드에 데몬셋 형태로 생성되는 VPC CNI 플러그인이다.
L-IPAM을 포함하기에 IPAM의 역할인 IP Warm Pool가지고, IP가 필요할 때 ENI의 빈 슬롯에 IP를 등록해주는 역할을 한다.
// 워커 노드 IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
// 파드 IP 확인
kubectl get pod -n kube-system -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase
워커노드와 파드의 IP를 확인해보면 kube-proxy
, aws-node
파드의 IP가 워커 노드의 IP와 동일하다는 것을 확인할 수 있다.
아니 이럴 수가 있는가? 분명 파드로 배포된 애들인데?! 노드의 IP와 같다고?!😧
즉, 이 의미는 노드의 ENI 테이블의 IP 슬롯의 첫번째 주소(Primary IP)를 노드와 파드가 함께 사용하고 있는 것이다.
(참고자료 - Primary IP 부분)
이는 특수한 용도인 kube-proxy
, aws-node
파드는 일반적인 K8S의 네임스페이스가 아닌 워커노드 자체의 네임스페이스에 위치하여 노드의 네트워크 인터페이스를 브릿지(공유)해서 사용하는 것이다. (hostNetwork: true
옵션을 지정)
이렇게 함으로써 노드 내 파드의 IP 관리 및 트래픽 처리를 보다 효율적으로 관리할 수 있다
실제로 kube-proxy
, aws-node
파드가 노드 IP를 사용하고 있음을 AWS 콘솔에서 실제로 확인할 수 있다.
여기서 CoreDNS는 클러스터에서 사용하는 DNS 서버로 노드수와 상관없이 최소 2대가 배포된다.
이제 워커노드의 네트워크가 어떻게 구성되었는지 확인해보자.
// 워커 노드 1에서 네트워크 정보 확인
ssh ec2-user@$N1 sudo ip -br -c addr
먼저 워커노드의 ENI가 어떻게 할당되어 있는 지 확인해보자.
2개의 네트워크 인터페이스와 1개의 가상 네트워크 인터페이스로 구성된 것을 확인할 수 있다.
eth0
: Primary ENI
eth1
: Secondary ENI
enibd472383de4@if3
: 파드의 인터페이스와 연결하는 목적으로 구성. 여기서는 CoreDNS 파드와 연결된다
// 라우팅 정보 확인
ssh ec2-user@$N1 sudo ip -c route
// coreDNS 파드 정보 확인
kubectl get pod -n kube-system -l k8s-app=kube-dns -owide
이제 리눅스 네트워크 인터페이스와 관련된 라우팅 정보를 확인해보자.
CoreDNS 파드가 외부로 통신을 하기 위해서 CoreDNS 파드 IP가 가상인터페이스 enibd472383de4@if3
와 연결된 것을 확인할 수 있다.
실제로 워커노드를 확인해보면 ENI가 2개 사용된 만큼, 2개의 IP 주소가 노드에 할당된 것을 확인할 수 있다.
➡️ ENI(네트워크 인터페이스)의 첫번째 슬롯은 Primary IP로 항상 노드의 IP로 사용되기 때문이다.
만일 파드의 수가 늘어나 더 많은 네트워크 인터페이스를 사용하게 된다면 노드의 IP주소는 3개, 4개 더욱 늘어나게 된다.
➡️이는 해당 ENI의 슬롯에 있는 파드와 노드간 통신이 되여하므로 노드는 ENI의 첫번째 슬롯(Primary IP)를 반드시 가져야 하기 때문이다..
이를 그림으로 보면 다음과 같다.
파드를 생성 할 때 아래 그림과 같이 노드에 첫번째 파드가 배포되는 순간 자동으로 ENI가 하나 더 생성된다.
EKS에서 AWS VPC CNI를 통해서 노드에 ENI가 생성되면 aws-node의 L-IPAM warm pool로 부터 Secondary IP를 전부 할당받아 슬롯을 가득 채운다.
따라서 첫 파드가 생성될 때 현재 ENI 슬롯이 가득 차 있는 것을 확인하고, 새로운 ENI를 생성하게 된다.
Reference📎 | CloudNet@와 함께하는 Amazon EKS 기본 강의