EKS Study - w02

wdb·2024년 3월 16일

EKS 네트워크

AWS VPC CNI

  • EKS에서 지원하는 유일한 CNI 플로그인입니다.
  • EKS 클러스터는 VPC 내부에서 동작합니다. 즉, VPC 네트워크 환경의 영향을 받습니다.
  • 파드는 클러스터가 배포된 서브넷 대역에서 CNI를 통해 IP를 할당받습니다.
  • VPC CNI(Container Network Interface)는 VCP 네트워크와 EKS 네트워크 간 인터페이스 역할을 수행합니다.
  • 파드와 IP 대역과 노드의 IP 대역이 같기 때문에 직접 통신이 가능합니다.
    - K8s Calico CNI의 경우 파드 IP 대역과 노드의 IP 대역이 상이합니다.
  • VPC CNI는 동일한 네트워크 대역 안에서 파드 간 직접 통신이 이루어지기 때문에 오버레이(VXLAN, IP-IP 통신으로 인한 오버헤드가 발생하지 않습니다.

L-IPAM

  • L-IPAM(Local IP Address Manager)은 네트워크 내의 IP 주소를 관리하는 소프트웨어 도구입니다.
  • L-IPAM은 IP를 할당 및 추적하여 IP 중복없이 주소 공간을 효율적으로 사용할 수 있게 해줍니다.
  • AWS VPC CNI는 EKS Addon으로 제공되며 aws_node라는 DaemonSet으로 모든 노드에 배포되는데, aws_node의 일부로 L-IPAM을 설치하여 파드의 IP를 할당받는 방식을 사용합니다.
  • Kubelet에서 파드를 추가하라는 요청을 받으면, L-IPAM은 IP warm-pool에서 사용가능한 보조 IP 주소를 파드에 할당합니다.
  • L-IPAM의 warm-pool은 DaemonSet이 시작될 때마다 Kubelet을 통해 파드의 이름, 네임스페이스, IP 주소 등의 파드 정보를 통해 IP warm-pool을 구축합니다.
  • EC2 인스턴스는 유형마다 ENI의 최대 개수가 정해져 있는데, L-IPAM을 사용하면 VPC CNI가 IP를 할당하는 범위를 정해서 IPv4 28bit(IP 16개) 서브넷을 위임하여 보다 많은 IP를 사용할 수 있게 해줍니다.

실습 진행

1. 인프라 배포


CloudFormation을 통해 인프라를 배포합니다. 구성된 인프라의 아키텍처는 아래와 같습니다.

2. 기본 구성 확인

# 디폴트 네음스페이스 적용
kubectl ns default

# 클러스터 배포 확인
kubectl cluster-info
eksctl get cluster
eksctl get nodegroup --cluster $CLUSTER_NAME

# 환경변수 확인
export | egrep 'ACCOUNT|AWS_|CLUSTER|KUBERNETES|VPC|Subnet'

# 노드 정보 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,ekmazonaws.com/capacityType,topology.kubernetes.io/zone

# 노드 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
N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address})
N3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile
echo "export N3=$N3" >> /etc/profile
echo $N1, $N2, $N3 

# Secondary Group Rule 추가
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text)
echo $NGSGID
echo "export NGSGID=$NGSGID" >> /etc/profile
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32

# 핑테스트 (EC2 -< Worker Nodes)
ping -c 1 $N1
ping -c 1 $N2
ping -c 1 $N3

3. Addon 확인

EKS -> 클러스터 선택 -> 추가기능 탭에서 Addon을 확인할 수 있습니다.

# 모든 파드의 커네이너 이미지 정보 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
# Addon 정보 확인
eksctl get addon --cluster $CLUSTER_NAME
# K8s 버전별 Addon 지원 확인
eksctl utils describe-addon-versions --kubernetes-version 1.29 | grep AddonName | wc -l
eksctl utils describe-addon-versions --kubernetes-version 1.28 | grep AddonName | wc -l

4. 네트워크 정보 확인

# 파드 모니터링
watch -d kubectl get pod -A
# CNI 정보 확인
ubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i tree /var/log/aws-routed-eni; echo; done
ssh ec2-user@$N1 sudo cat /var/log/aws-routed-eni/plugin.log | jq
# kube-proxy 모드 확인
kubectl describe cm -n kube-system kube-proxy-config | grep mode
# 파드 정보 확인
kubectl get pod -n kube-system -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase
# ENI & veth pair 정보 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -br -c addr; echo; done
# kube-proxy iptables 확인
ssh ec2-user@$N1 sudo iptables -t nat -S 
  • kube-proxy 모드로 iptables을 사용하는 이유
    - IPVS의 경우 서비스 수가 10000를 초과하는 대규모 클러스터에 적합합니다. 소규모 클러스터에서는 iptables가 더 적합할 수 있습니다.

5. 노드에서 네트워크 정보 확인

# coredns 파드 IP 조회
kubectl get pod -n kube-system -l k8s-app=kube-dns -owide
# 노드 IP 조회
kubectl get node -owide
# 호스트 Routing Table 조회 -> veth coredns IP 일치 확인 
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c route; echo; done

  • 네트워크 네임스페이스는 호스트와 파드 별로 구분됩니다.
  • aws-node와 kube-proxy 파드는 호스트의 IP 주소를 사용합니다.
    - 파드 옵션 중 hostNetwork가 true일 때
  • aws-node와 kube-proxy 파드는 포트를 구분하여 서비스합니다.
  • coredns 파드는 veth로 호스트와 eniY@ifN 인터페이스로 연결되어 있고, 파드와는 eth0으로 연결되어 있습니다.

6. 파드 추가 생성 후 네트워크 정보 확인

# 테스트용 파드 생성
cat <<EOF | kubectl create -f -
> apiVersion: apps/v1
> kind: Deployment
> metadata:
>   name: netshoot-pod
> spec:
>   replicas: 3
>   selector:
>     matchLabels:
>       app: netshoot-pod
>   template:
>     metadata:
>       labels:
>         app: netshoot-pod
>     spec:
>       containers:
>       - name: netshoot-pod
>         image: nicolaka/netshoot
>         command: ["tail"]
>         args: ["-f", "/dev/null"]
>       terminationGracePeriodSeconds: 0
> EOF
# 파드 생성 확인
kubectl get pod -o wide
# 호스트 라우팅 테이블 조회 -> 워크노드 1 veth 인터페이스 생성 확인
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c route; echo; done

  • Worker Node에 veth 인터페이스가 하나씩 생성된 것을 확인할 수 있습니다.
  • 라우팅 테이블에는 새 파드를 대상으로 한 경로가 추가되었습니다.
  • 미리 구성된 IP Pool에서 새 파드에 Secondary 프라이빗 IP가 할당되었습니다.

7. 통신 테스트

파드에 접속하여 파드 간 통신을 확인합니다.

파드에서 외부 통신이 필요하면 iptables의 SNAT를 통해 외부와 통신합니다.

파드와 노드 각각에서 외부와 통신하는 공인 IP 주소가 동일합니다.

0개의 댓글