이번 2주차 스터디에서는 쿠버네티스 네트워크에 대해서 학습 할 예정이다. 또한 일반적으로 사용하는 CNI(calico, weave net, Flannel)가 아닌 AWS VPC를 사용하면서 일반적인 CNI와 차이점에 대해서 학습 할 예정이다. 추가적으로 AWS ELB를 쿠버네티스에서 어떻게 설정하고 사용하는지 학습 할 예정이다.
AWS VPC
CNI(Container Network Interface)는 Pod간 네트워크 환경을, 즉 통신 환경을 구성해 준다. 일반적으로 많이 사용되는 CNI는 calico, weave net, Flannel 등이 있다. 이번 스터디에서 사용하는 KOPS에서는 AWS에서 구성되었고, CNI또한 AWS VPC를 사용한다. AWS VPC가 다른 CNI와 다른 점은 노드와 파드의 네트워크 대역이 같아 통신 상황이 훨씬 간결하다는 부분이다.
K8S Calico CNI 와 AWS VPC CNI 차이
네트워크 통신의 최적화(성능, 지연)를 위해서 노드와 파드의 네트워크 대역을 동일하게 설정함.
파드간 통신 시 일반적으로 K8S CNI는 오버레이(VXLAN, IP-IP 등) 통신을 하고, AWS VPC CNI는 동일 대역으로 직접 통신을 한다.
네트워크 정보 확인
# CNI 정보 확인
kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
amazon-k8s-cni-init:v1.11.4
amazon-k8s-cni:v1.11.4
# 노드 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
노드에서 기본 네트워크 정보
Network 네임스페이스는 호스트(Root)와 파드 별(Per Pod)로 구분된다
특정한 파드(kube-proxy, aws-node)는 호스트(Root)의 IP를 그대로 사용한다
t3.medium 의 경우 ENI 에 최대 6개의 IP를 가질 수 있다
ENI0, ENI1 으로 2개의 ENI는 자신의 IP 이외에 추가적으로 5개의 보조 프라이빗 IP를 가질수 있다
coredns 파드는 veth 으로 호스트에는 eniY@ifN 인터페이스와 파드에 eth0 과 연결되어 있다
[ Node2의 네트워크 정보 ] 현재 NIC가 2개(ens5, ens6), 논리 NIC가 2개
AWS 콘솔 화면 확인
노드 간 파드 통신
파드간 통신 흐름 : 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능하다
파드간 통신 테스트 및 확인: 별도의 NAT 동작 없이 통신 가능!
# 파드 IP 변수 지정
POD1=$(kubectl get pod pod-1 -o jsonpath={.status.podIP})
POD2=$(kubectl get pod pod-2 -o jsonpath={.status.podIP})
# 파드1 Shell 에서 파드2로 ping 테스트
kubectl exec -it pod-1 -- ping -c 2 $POD2
# 파드2 Shell 에서 파드1로 ping 테스트
kubectl exec -it pod-2 -- ping -c 2 $POD1
#각 노드에서 tcpdump 모니터링
sudo tcpdump -i any -nn icmp
[ TIP ] 두 번째 ENI에서 할당된 보조 IP를 사용하더라도 무조건 첫번째 ENI를 통해 통신이 되도록 설정되어 있음. 따라서 ens6의 ping은 tcpdump에서 확인 할 수 없음!!
파드에서 외부 통신
파드에서 외부 통신 흐름 : iptable 에 SNAT 을 통하여 노드의 eth0 IP로 변경되어서 외부와 통신됨
파드에서 외부 통신 테스트 및 확인
kubectl exec -it pod-1 -- curl -s ipinfo.io/ip : echo
#node1
curl -s ipinfo.io/ip : echo
#출력되는 공인 IP 확인
Node1의 Public IP 출력!
iptable 확인
# 파드가 외부와 통신시에는 아래 처럼 '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
## 아래 'mark 0x4000/0x4000' 매칭되지 않아서 RETURN 됨!
-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully
...
# 카운트 확인 시 AWS-SNAT-CHAIN-0, AWS-SNAT-CHAIN-1 에 매칭되어, 목적지가 172.30.0.0/16 아니고 외부 빠져나갈때 SNAT 172.30.85.242 변경되어 나간다!
sudo iptables -t filter --zero; sudo iptables -t nat --zero; sudo iptables -t mangle --zero; sudo iptables -t raw --zero
watch -d 'sudo iptables -v --numeric --table nat --list AWS-SNAT-CHAIN-0; echo ; sudo iptables -v --numeric --table nat --list AWS-SNAT-CHAIN-1; echo ; sudo iptables -v --numeric --table nat --list KUBE-POSTROUTING'
# conntrack 확인
sudo conntrack -L -n |grep -v '169.254.169'
conntrack v1.4.5 (conntrack-tools):
icmp 1 28 src=172.30.66.58 dst=8.8.8.8 type=8 code=0 id=34392 src=8.8.8.8 dst=172.30.85.242 type=0 code=0 id=50705 mark=128 use=1
tcp 6 23 TIME_WAIT src=172.30.66.58 dst=34.117.59.81 sport=58144 dport=80 src=34.117.59.81 dst=172.30.85.242 sport=80 dport=44768 [ASSURED] mark=128 use=1
노드에 파드 생성 갯수 제한
Secondary IPv4 addresses: 인스턴스 유형에 최대 ENI 갯수와 할당 가능 IP 수를 조합하여 선정
워커 노드의 인스턴스 타입 별 파드 생성 갯수 제한
인스턴스 타입별 ENI 최대 갯수와 할당 가능한 최대 IP 갯수에 따라서 파드 배치 갯수가 결정됨
단, aws-node 와 kube-proxy 파드는 호스트의 IP를 사용함으로 최대 갯수에서 제외함
최대 파드 생성 갯수 : (Number of network interfaces for the instance type × (the 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
# 파드 사용 가능 계산 예시 : aws-node 와 kube-proxy 파드는 host-networking 사용으로 IP 2개 남음
((MaxENI * (IPv4addr-1)) + 2)
t3.medium 경우 : ((3 * (6 - 1) + 2 ) = 17개 >> aws-node 와 kube-proxy 2개 제외하면 15개
# 워커노드 상세 정보 확인 : 노드 상세 정보의 Allocatable 에 pods 에 17개 정보 확인
kubectl describe node | grep Allocatable: -A6
Allocatable:
cpu: 2
ephemeral-storage: 59763732382
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3854320Ki
pods: 17
Service
AWS NLB의 타겟 그룹에 Pod의 IP가 직접 바인딩 되어 통신, iptable의 Rule을 타지 않음!! 로드밸런스 컨트롤러가 Endpint의 정보를 즉 Pod의 정보를 KOPS를 통해서 주기적으로 모니터링해서 NLB에 해당 정보를 제공!
# kOps 클러스터 편집 : 아래 내용 추가
kops edit cluster
-----
spec:
awsLoadBalancerController:
enabled: true
-----
# 업데이트 적용 : 적용이 안될 경우 한번 더 아래 명령 실행
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster
sudo tcpdump -i ens5 -nn icmp // Node1에서 ens5 인터페이스를 통해 tcpdump → 통신 확인
172.30.49.61 : Pod-1 IP / 172.30.71.69 : Pod-2 IP
해당 IP를 통해 별도의 NAT 동작 없이 통신하는 것을 확인 할 수 있음
이유는 VPC CNI를 사용하기 때문에!!
sudo tcpdump -i ens5 -nn icmp → Node2에서 ens5 인터페이스를 통해 tcpdump -> 통신 확인
과제2) 어떤 방식을 사용하더라도 좋으니, 워커 노드 1대에 100대의 파드가 배포되게 설정하고 관련 스샷을 올려주세요.
초기 kops 클러스터 구성을 c5.large로 하고 worker node의 수를 1로 설정하여 클러스터를 구성하였다.
구성 후 최대 Pod수를보면 29인 것을 볼 수 있다.
VPC CNI Nerwork 설정 - kubelet의 maxPods수를 설정 - networking에 WARM_PRENFIX_TARGET / PREFIX_DELEGATION 설정 - kops edit cluster --state s3://버킷이름
설정 후 cluster 업데이트 업데이트 시 Master Node 자체가 변경되어 IP도 변경된다. 따라서 도메인에 api 주소도 변경해줘야 함 → 해당 작업이 시간이 오래 걸림(시간이 오래 걸리면 알아서 이 부분도 변경되는 같다.)
Worker node가 변경 확인
노드 최대 Pod 수 변경 확인
PREFIX_DELEGATION 및 WARM_PREFIX_TARGET 설정 확인
LimitRange 설정 변경 기존 limits라는 LimitRange 오브젝트가 존재하며, 현재 cpu 100m으로 설정 오브젝트에 edit하여 cpu 100m 설정 삭제
Pod100개 배포 및 확인 - kubectl apply -f ~/pkos/2/nginx-dp.yaml - kubectl scale deployment nginx-deployment --replicas=100
추가적으로 t3.medium 인스턴스에서도 Test 진행 → 클러스터 구성 전, maxpod 수 확인 : 110개(c5.large)와 동일
위 과정을 동일하게 진행 후 단일 노드(t3.medium)에 Pod 100개 배포 및 확인
과제3) 서비스(NLB) / 파드 배포 시 externalDNS 설정해서, 각자 자신의 도메인으로 NLB를 통해 애플리케이션(파드)로 접속해보고 관련 스샷을 올려주세요. 퍼블릭 도메인이 없는 멤버분들은, externalDNS 제외하고 NLB 도메인으로 접속한 결과를 올려주세요.
nginx.burst89.com
마무리
사실 이번 스터디 내용이 조금은 어려웠다. 아는 내용도 있었지만, Service의 내용이 많이 헷갈렸다... 핵심은 AWS VPC CNI를 사용하면, 노드의 IP와 Pod의 IP가 같은 대역을 사용한다. 또한 로드밸런서 컨트롤러를 사용하면 로드밸런스 타겟대상에 Pod의 IP가 직접 연결되며, 컨트롤러가 계속해서 모니터링을 하고 해당 내용을 로드밸런서에게 전달하여 타겟의 정보를 확인 하여 보다 효과적으로 Service를 운영할 수 있다는 내용이다!! 추가적으로 노드의 최대 Pod 수 과제는 진짜 어려웠다......ㅠㅠ 3일은 걸려서 해당 과제를 해결할 수 있었다. 점점 난이도가 어려워 지는 느낌이 든다.. 그래도 화이팅 !!!!!!!