본문 바로가기
Tech/Kubernetes

[AEWS_1기] 2주차 - EKS Networking (1/2)

by 구름_쟁이 2023. 5. 3.

본 시리즈는 가시다님의 AEWS(AWS EKS Workshop) 1기 진행 내용입니다. (가시다님 노션)

스터디에 사용되는 링크 (AWS EKS Workshop) 

 

 

 

목차

1. AWS VPC CNI 소개
2. 다른 Cloud의 CNI는?

 

2주차부터는 원클릭을 통해 한방에 (20분 정도 소요) 배포한다.(다시 한번 가시다님 최고..!)

도전과제는 2부로!

 

 

     


    AWS VPC CNI 소개

    이전 스터디인 PKOS에서도 다뤘으니 중요한 부분만 짚고 넘어가자!

     

     

     

    IP대역이 같다는 건 직접 통신을 한다는 이야기.(오버레이 X)

     

    장점

    • 통신 경로에 Hope이 줄어 들기 때문에 통신 속도나 자원 사용량 면에서 이점
    • VPC와 통합 (VPC Flow logs, VPC 라우팅 정책, 등)
    • SG, ACL과 같은 보안 기능과 통합하여 보안성 향상
    • 직접 통신 : Pod가 같은 네트워크 대역의 다른 서비스(EC2 및 Network 대역에 IP를 점유하는 기타 서비스들)

     

    단점

    • 부득이하게 하나의 클러스터에 엄청나게 많은 양의 Pod를 배포해서 사용하고자 하더라도 할당가능한 ENI 자원의 한계로 인해 일반적인 K8S CNI 보다 많은 Pod를 만들 수 없음
      • 단, 이정도로 많은 Pod를 배포하기 전에 K8S의 Control Plane의 Component인 API-Server의 부하를 고려해서 멀티 클러스터 구성을 진행하는 것이 더 바람직하다고 생각됨

     

    간단하게 보는 직접 통신 부분

    노드3의 Primary IP, Secondary IP 확인

     

     

    테스트용 파드 eniY 정보 확인 (워커 노드 EC2에서 진행)

     

     

     

    # 노드3에서 네트워크 인터페이스 정보 확인
    ssh ec2-user@$N3
    ----------------
    ip -br -c addr show
    ip -c link
    ip -c addr
    ip route # 혹은 route -n
    
    # 마지막 생성된 네임스페이스 정보 출력 -t net(네트워크 타입)
    sudo lsns -o PID,COMMAND -t net | awk 'NR>2 {print $1}' | tail -n 1
    
    # 마지막 생성된 네임스페이스 net PID 정보 출력 -t net(네트워크 타입)를 변수 지정
    MyPID=$(sudo lsns -o PID,COMMAND -t net | awk 'NR>2 {print $1}' | tail -n 1)
    
    # PID 정보로 파드 정보 확인
    sudo nsenter -t $MyPID -n ip -c addr
    sudo nsenter -t $MyPID -n ip -c route

    192.168.3.194를 찾아보자

    Pod가 노드(EC) 인스턴스의 Secondary IP를 잘 할당 받음

     

    노드 간 파드 통신

    목표 : 파드간 통신 시 tcpdump 내용을 확인하고 통신 과정을 알아본다

    파드간 통신 흐름 : AWS VPC CNI 경우 별도의 오버레이(Overlay) 통신 기술 없이, VPC Native 하게 파드간 직접 통신이 가능하다

     

    파드간 통신 시 과정 참고

    https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md

     

    파드간 통신 테스트 및 확인 : 별도의 NAT 동작 없이 통신 가능

    # 파드 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})
    PODIP3=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[2].status.podIP})
    
    # 파드1 Shell 에서 파드2로 ping 테스트
    kubectl exec -it $PODNAME1 -- ping -c 2 $PODIP2
    
    # 파드2 Shell 에서 파드3로 ping 테스트
    kubectl exec -it $PODNAME2 -- ping -c 2 $PODIP3
    
    # 파드3 Shell 에서 파드1로 ping 테스트
    kubectl exec -it $PODNAME3 -- ping -c 2 $PODIP1
    
    # 워커 노드 EC2 : TCPDUMP 확인
    sudo tcpdump -i any -nn icmp
    sudo tcpdump -i eth1 -nn icmp
    sudo tcpdump -i eth0 -nn icmp
    
    [워커 노드1]
    # routing policy database management 확인
    ip rule
    
    # routing table management 확인
    ip route show table local
    
    # 디폴트 네트워크 정보를 eth0 을 통해서 빠져나간다
    ip route show table main
    # 어떤 정보가 나올까?

     

     

    파드에서 외부 통신

    파드에서 외부 통신 흐름 : iptable 에 SNAT 을 통하여 노드의 eth0 IP로 변경되어서 외부와 통신됨

    VPC CNI 의 External source network address translation (SNAT) 설정에 따라, 외부(인터넷) 통신 시 SNAT 하거나 혹은 SNAT 없이 통신을 할 수 있다 - 링크

     

    파드에서 외부 통신 테스트 및 확인

    # 작업용 EC2 : pod-1 Shell 에서 외부로 ping
    kubectl exec -it $PODNAME1 -- ping -c 1 www.google.com
    kubectl exec -it $PODNAME1 -- ping -i 0.1 www.google.com
    
    # 워커 노드 EC2 : TCPDUMP 확인
    sudo tcpdump -i any -nn icmp
    sudo tcpdump -i eth0 -nn icmp
    
    # 워커 노드 EC2 : 퍼블릭IP 확인
    curl -s ipinfo.io/ip ; echo
    
    # 작업용 EC2 : pod-1 Shell 에서 외부 접속 확인 - 공인IP는 어떤 주소인가?
    ## The right way to check the weather - 링크
    kubectl exec -it $PODNAME1 -- curl -s ipinfo.io/ip ; echo
    kubectl exec -it $PODNAME1 -- curl -s wttr.in/seoul
    kubectl exec -it $PODNAME1 -- curl -s wttr.in/seoul?format=3
    kubectl exec -it $PODNAME1 -- curl -s wttr.in/Moon
    kubectl exec -it $PODNAME1 -- curl -s wttr.in/:help
    
    # 워커 노드 EC2
    ## 출력된 결과를 보고 어떻게 빠져나가는지 고민해보자!
    ip rule
    ip route show table main
    sudo iptables -L -n -v -t nat
    sudo iptables -t nat -S
    
    # 파드가 외부와 통신시에는 아래 처럼 '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 192.168.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 192.168.1.251 --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 에 매칭되어, 목적지가 192.168.0.0/16 아니고 외부 빠져나갈때 SNAT 192.168.1.251(EC2 노드1 IP) 변경되어 나간다!
    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

     

    워커 노드 EC2 : TCPDUMP 확인

     

     

     

    Pod-1의 Shell을 통해 외부 통신 시의 공인 IP 확인

    아까 본 노드 인스턴스의 공인 IP 확인

     

    iptables 룰셋 확인 (SNAT-CHAIN)

    VPC IP 대역인 192.168.0.0/16으로 향하는 통신을 제외하고는 192.168.3.227(노드 인스턴스의 Primary IP)를 통해 SNAT한다.

     

     

    192.168.3.194 IP를 가진 Pod가 192.168.0.0/16 대역이 아닌 곳으로 통신을 시도한다면?

     

     

     

     

     

    결론

    스터디를 하면할수록 새로운 것들이 생긴다 하하

    같은 네트워크 파트인데도 새로운 자료가 계속 생겨나서 정말 알찬 순간이였다.

    나날이 발전하는 스터디 화이팅!

     

     


    다른 Cloud의 CNI는?

     

    가시다님이 올려주신 자료 중 클라우드 벤더 3사의 매니지드 쿠버네티스 서비스의 노드 사이즈 관련된 비교표를 보게 되었다. (링크)

     

    그 중 눈에 띈 것.

    Azure 250개... 뭐지?

     

    Azure 문을 두드려보자. (Docs야 도와줘)

    최대라고만 나와있는데 좀 더 살펴보자.

    번역이 이상한 것 같은데 Azure CNI에 의해 IP 주소를 미리 구성해둔다는 내용이다.

    자 Azure CNI가 IP 주소를 어떻게 미리 제공하는지 알아보자.

     

     

    (대략 AKS 배포하는 주인장모습)

     

    Azure는 기본적으로 클러스터가 배포되는 Subnet에 Pod를 위한 IP를 미리 점유해놓는다.

    AKS가 배포된 VNET에 연결된 디바이스를 보자.

    아무 Pod도 배포하지 않은 상태에서 이 많은 IP 주소를 다 연결해두었다.

     

    kubenet CNI를 선택한 경우

     

     

    이 말은 뭐냐하면 저 IP는 다른 서비스(VM, Private Endpoint 등등)가 점유할 수 없다는 뜻이다.

    EKS에서는 기본적으로 노드 인스턴스가 할당할 수 있는 Secondary IP를 통해서 점차 확장되어 가는 구조라면, AKS는 사용할 대역만큼의 IP를 노드 소유라고 클러스터를 배포할 때부터 지정해놓고 쓰도록 한다.

     

    또한 EKS와 다른 점은 AKS는 노드 당 최대 Pod 갯수 제한을 별도로 설정할 수 있다.

     

    AKS 클러스터 생성 시 Node Pool 상세

     

     

    Azure_CNI_Docs

     

     

    그럼 진짜로 안되는지 검증을 해보도록 하자.

    간단하게 해당 VNET에 VM을 배포해보자

    Pod가 점유한 IP 대역을 피해서(?) IP가 할당되었다.

    그렇다면 NIC를 정적으로 변경해서 IP를 지정해보면?

    역시나 안된다. 

     

     

    결론

    지금 AWS의 VPC CNI를 배우고 있는 상황에서는 Azure CNI를 보며 '이렇게 쉽게 노드당 최대 파드 수를 설정한다고?' 라고 생각할 수 있다.

    근데 보자마자 든 생각은 너무 과하게 점유하는 것도 아키텍처의 자유도를 떨어트린다는 점이다.

    IP 자원 또한 설계/운영에 아주 중요한 자원인데, 확장에 불편함이 있더라도 쓰는만큼만 쓰고 나머지는 다른 서비스들도 들어와서 사용하다가 분리해나갈 수 있는 장점이 AWS에게는 있다고 느껴졌다.

    (Azure도 사랑합니다...)

     

     

     

    댓글