목표

EKS 네트워크의 이해
각각의 노드내 파드에서의 통신(내/외부) 흐름 이해

 

 

 

1. 실습 환경 배포

https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/eks-oneclick.yaml 을 통해 실습환경구축

Stackname, keyName, Accesskey, secret key 입력

SgIngressSshCidr 은 본인 아이피 입력

나머지는 자동

 

ps.

비용아끼겠다고 t3말고 t2로 하면 1시간도 더 걸린다. 그러니 그냥 t3로 진행할것

 

관리용 ec2 접속

에러는 아직 클라우드 포메이션이 전부 배포가 되지 않았기 때문이다.

클라우드 포메이션으로 생성중

 

배포완료
/root/myeks.yml 파일에서 배포정보를 확인가능

 

# default 네임스페이스 적용 kubectl ns default



# 노드 정보 확인 kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone eksctl get iamidentitymapping --cluster myeks



# 노드 IP 확인 및 PrivateIP 변수 지정

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

# 노드 보안그룹 ID 확인 NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text) aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32



# 워커 노드 SSH 접속

ssh ec2-user@$N1 hostname

ssh ec2-user@$N2 hostname

ssh ec2-user@$N3 hostname

 

위 작업들을 순서대로 진행하면 N1, N2, N3(노드1,2,3)서버로 접속이 가능해진다.

default name space 적용
노드 정보 확인
노드별로 N1,2,3 에 아이피 지정
노드 보안그룹 ID 확인
설치된 addon들
AWS 웹 콘솔에서도 설치된 에드온 확인이 가능하다.
node1,2,3 의 ssh 접속 및 hostname 확인

여기까지 하면 2주차 실습 준비 완료

 

 

온프레미스 k8s에 가장 많이 사용되는 CNI인 Calico와 AWS EKS에 가장 많이 사용되는 AWS VPC CNI의 차이점은 다음과 같다.

- Calico의 경우 파드와 노드의 대역이 다르지만 AWS VPC CNI는 네트워크 통신 최적화를 위해 파드와 노드의 대역이 같다.

- Calico는 오버레이(인캡슐 디캡슐진행) 통신을 하고 AWS VPC CNI는 동일대역으로 직접 통신

AWS VPC CNI를 구축할때 주의할점은 네트워크 대역을 보통 24비트로 하는경우가 많을텐데(나만 그런가...) AWS VPC CNI의 경우 파드 네트워크와 노드 네트워크가 공유되기때문에 네트워크 대역을 여유롭게 22비트 정도로 주는게 좋다.

위와같이 노드1,3에는 eni~로 가상의 네트워크가 추가돼있는데 이것들이 각각 노드1,3에 추가돼있는 파드의 네트워크 정보이다.

 

t3.medium의 경우 ENI별로 6개의 아이피를 할당받을수있는데 아래와같이 node1,3은 ENI가 2개라 보조 프라이빗 IP까지 총 12개가 할당된것을 볼수있고 node2는 6개가 할당된것을 볼수있다.

위와같이 노드1,3에는 보조 프라이빗 ip주소가 생성돼있는걸 확인할수있는데 노드2에는 파드가 추가돼있지 않아서 기본적으로 할당되는 6개(1개는 프라이빗으로 실제 할당이됐고 나머지5개)만 할당돼있는걸 확인할 수 있다.

 

여기서 replicas 3을 줘서 각각의 노드에 파드를 1개씩 추가로 생성되도록 해보면 결과는 아래와 같다.

보는것처럼 각각의 노드에 ENI가 1개씩 추가된것을 확인할수있다.

그럼 실제 할당된 아이피 갯수는 몇개일까

보는것처럼 노드2는 6개의 아이피가 추가된것을 확인할수있다. 다만 노드1,3은 아까와 동일하다.

그렇다. 파드가 추가(ENI가 생성)된다고 해서 무조건 새로운 아이피가 할당되는게 아니다.

ENI 가 생성되는 프로세스는 다음과같다.

IP POOL에 내용이 없으면 세컨더리 ENI를 생성(방금 노드2번의 경우) 그게 아니라면 기존 IP POOL에서 아이피를 할당하는것이다.

이렇게 IP POOL이 부족하면 새로운 ENI를 생성하는건데 무제한으로 생성되지 않는다.

 

 

 

온프레미스에서는 iptables의 NAT 구성으로 트래픽을 포워딩 해주는데  eks는 하나의 네트워크 대역에 들어가니까 확실히 calico(온프레미스용 CNI)보다 네트워크 구성을 이해하기가 더 좋은거같다. 그렇기 때문에 문제가 발생했을경우 어떤구간에서 문제가 발생했는지 좀더 직관적(동일 네트워크이기에 원인 파악이 쉬움)으로 트러블 슈팅이 가능할것이다.

 

실제로 노드내 파드끼리, 통신을 해보자.

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

 

GitHub - aws/amazon-vpc-cni-k8s: Networking plugin repository for pod networking in Kubernetes using Elastic Network Interfaces

Networking plugin repository for pod networking in Kubernetes using Elastic Network Interfaces on AWS - GitHub - aws/amazon-vpc-cni-k8s: Networking plugin repository for pod networking in Kubernete...

github.com

위와같은 플로우로 진행이 되는데 실제로 실습을 해보고자 한다.

위와같이 파드2에서 ping 하여 tcpdump 해보면 pod1의 아이피로 통신하는것을 확인할수 있다.

 

이번엔 파드에서 외부로 나가는 통신을 확인해보자.

위와같이 파드1에서 google.com 으로 통신을 한 결과이다.

일단 ping이 정상적인거보면 통신은되는데... 172.217.31.132가 실제 구글 아이피는 아니다.

google의 아이피는 172.217.31.132가 아닌데 tcpdump의 결과는 172.217.31.132로 통신을 보내고있다.

그러면 172.217.31.132 에서 또 다른곳으로 NAT를 통해 실제 google로 통신이 되고 있는것이다.

다시 말하자면 파드의 실제 외부아이피(즉 외부 인터넷(구글)과 통신할 아이피)는 사설망 아이피(192나 172.로 시작하는게 아닌)가 아닌 외부 아이피로 통신을 해야한다. 

이건 iptables의 SNAT를 통해 통신이 된다.

iptables 설정은 위와같다.

위와같이 192.168(클러스터 내 파드들의 대역)은 AWS SNAT-CHAIN으로 통신을 하고 그 외 나머지는 192.168.1.190아이피 달고 가라. 그럼 라우팅 설정에 의해 외부(인터넷)으로 통신이 되는것이다.

 

위와같이 각 pod별로 아이피가 할당이되고 통신되는것을 알아보았는데. 파드에 할당되는 아이피는 설정한 대역내 랜덤으로 아이피가 할당된다. 그럼 실제 서비스를 하기위해 파드로의 통신은 어떻게 해야할까.

service 라는 리소스 오브젝트로 VIP를 만들어서 파드로 통신이 가능하다.

서비스 종류는 다음과 같다.

이중 NLB+AWS VPC CNI의 경우 앞단의 NLB에서 파드로 바로 통신이 가능하다. 이것이 가능한 이유는 node의 아이피대역과 파드의 아이피 대역이 같은 AWS VPC CNI의 특징때문이다. 

즉 노드내 iptables나 contrack와 같은 자원을 사용하지 않아 불필요한 자원이 사용되지 않고 통신구간이 줄어드는 장점이 있다.

다만 k8s와 AWS 로드밸런서(NLB)간에 어떠한 통신을하며 k8s 파드가 늘거나 혹은 줄어듬에 따라 NLB에서 대상타깃이 추가/제거가 필요하기 때문이다. 이는 k8s 클러스터내에 존재하는 load balancer controller 파드와 AWS의 서비스인 로드밸런서(NLB)간에 인증(OIDC)절차가 진행/완료되어 파드 IP등 지속적인 정보를 제공해주도록 해야한다.

인증 절차 진행을 위한 작업 IRSA 으로 진행한다.

더보기

IRSA는 AWS에서 제공하는 IAM Role을 Kubernetes Service Account와 연결하는 방법입니다. Kubernetes에서 Pod에서 사용하는 인증 방식 중 Service Account를 사용하는데, 이를 통해 Pod가 AWS 리소스에 접근할 수 있습니다. 하지만 이 때 Pod 내부에서 AWS SDK를 사용해 AWS API를 호출하면, 이 Pod는 AWS 인증 정보를 갖지 않아서 AWS API를 호출할 권한이 없습니다. 이 때 IRSA를 사용하면 Kubernetes Service Account를 IAM Role과 연결하여 Pod에서 AWS 리소스에 접근할 수 있게 됩니다. 이를 통해 보안성을 높일 수 있고, AWS IAM의 역할을 더욱 세분화하여 Pod에게 필요한 권한만 부여할 수 있습니다.

인증 방법은 아래와같다.

# OIDC 확인
aws eks describe-cluster --name $CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text
aws iam list-open-id-connect-providers | jq

# IAM Policy (AWSLoadBalancerControllerIAMPolicy) 생성
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

# 혹시 이미 IAM 정책이 있지만 예전 정책일 경우 아래 처럼 최신 업데이트 할 것
# aws iam update-policy ~~~

# 생성된 IAM Policy Arn 확인
aws iam list-policies --scope Local
aws iam get-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy
aws iam get-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --query 'Policy.Arn'

우선 OIDC 를 설정(클라우드 포메이션으로 자동 설정)하면 아래와 같이 EKS 클러스터에서 OIDC 가 설정돼있음을 확인할수있고

 

IAM 폴리시를 생성하면

 

위와같이 IAM 폴리시가 추가된것을 확인할수 있다.

여기까지하면 aws EKS에서는 OIDC를 통해 인증을 진행할 준비가 됐고 IAM 폴리시를 추가하여 EKS 클러스터에서 AWS 로드밸런서를 컨트롤할수있는 권한을 가져올 준비가 끝났다.

 

이제 IRSA를 통해 컨트롤이 가능하도록 구성하면된다.

방법은 아래와 같다.

# AWS Load Balancer Controller를 위한 ServiceAccount를 생성 >> 자동으로 매칭되는 IAM Role 을 CloudFormation 으로 생성됨!
# IAM 역할 생성. AWS Load Balancer Controller의 kube-system 네임스페이스에 aws-load-balancer-controller라는 Kubernetes 서비스 계정을 생성하고 IAM 역할의 이름으로 Kubernetes 서비스 계정에 주석을 답니다
eksctl create iamserviceaccount --cluster=$CLUSTER_NAME --namespace=kube-system --name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve

## IRSA 정보 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME

## 서비스 어카운트 확인
kubectl get serviceaccounts -n kube-system aws-load-balancer-controller -o yaml | yh

eksctl을 통해 서비스 어카운트를 생성하고 이는 클라우드포메이션을 통해 추가로 배포된다.

IRSA 확인

이제 모든 준비가 끝났으니 로드밸런서 컨트롤러를 EKS 클러스터에 헬름차트를 통해 배포하여 사용해보자.

helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \
  --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller

이후 로드밸런싱이 어떻게 구성되는지 확인하기 위해 아래와같이 테스트로 서비스와 파드를 배포하면

curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/2/echo-service-nlb.yaml
cat echo-service-nlb.yaml | yh
kubectl apply -f echo-service-nlb.yaml

아래와같이 enpoint가 두개(192.168.2.101, 192.168.3.75)로 로드밸런싱되도록 배포 된것을 확인할수 있다.

여기서 중요한부분은 앞서 말한것처럼 NLB에서 다이렉트로 파드의 아이피로 간다는것이다. 

이것이 가능한이유는 AWS VPC CNI의 장점인 노드아이피와 파드의 아이피가 동일한 대역이라 가능하기 때문이다.

 

실제 AWS 로드밸런서를 확인해보면

위와같이 eks 클러스터에서 AWS 로드밸런서 서비스가 생성된것을 확인할수있다.

이것이 가능한것은 앞서 클러스터에서는 OIDC, AWS에는 IAM 정책을 생성해줬고 이를 IRSA로 설정해줬기 때문이다.

 

실습 완료후 자원 삭제 

aws cloudformation delete-stack --stack-name eksctl-$CLUSTER_NAME-addon-iamserviceaccount-kube-system-aws-load-balancer-controller

 

'job > eks' 카테고리의 다른 글

eks 6주차  (0) 2023.05.31
eks 5주차  (0) 2023.05.23
4주차 eks 스터디  (0) 2023.05.16
3주차 eks 스터디  (0) 2023.05.13
eks 교육 1  (0) 2023.04.24

+ Recent posts