[AWS] EKS 클러스터에 서브넷 IP 추가 하기-3(VPC CNI custom networking 활용 성공 편)
IT/AWS

[AWS] EKS 클러스터에 서브넷 IP 추가 하기-3(VPC CNI custom networking 활용 성공 편)

반응형

Intro

앞서 포스팅한 EKS 클러스터에 서브넷 IP 추가 하기-2(VPC CNI custom networking 활용 실패 편 에 이어서 오늘은 성공 편입니다.

참고로 해당 포스팅은 AWS내부 담당자와 밀접하게 커뮤니케이션 하여 정리된 결론이며 따라서 어느정도 공신력있는 내용입니다.

우선 앞서 포스팅한 내용들을 요약해보면 EKS 클러스터를 생성할때 설정한 서브넷 안에서 노드그룹의 서브넷을 할당하게 되는데, 이 서브넷에 더 이상 할당 할 수 있는 IP가 없을때 VPC CNI custom networking을 사용해야합니다.

하지만 VPC CNI custom networking을 사용할때 하나의 노드그룹에 여러 가용영역(AZ)를 사용할 수 없었죠. 그 이유는 VPC CNI custom networking이 노드그룹이 사용할 서브넷의 기준을 노드에 할당되는 특정 라벨 (일반적으로 failure-domain.beta.kubernetes.io/zone)로 설정하기 때문입니다. (자세한내용은 EKS 클러스터에 서브넷 IP 추가 하기-2(VPC CNI custom networking 활용 실패 편 을 참고 바랍니다.)

특정 노드그룹에 여러 서브넷을 설정하고 싶다면?

예를들어 아래와 같이 노드그룹을 만들고 kubernetes node lable이 해당 노드가 어떤 AZ에 생성되는지 파악하여 frontend-subnet-a 또는 frontend-subnet-b와 같이 설정이 된다면 가능합니다.

FRONTEND-NODEGROUP(k8s lable is nodename=frontend-subnet-a or nodename=frontend-subnet-b )

  • FRONTEND-SUBNET-a
  • FRONTEND-SUBNET-c

BACKEND-NODEGROUPP(k8s lable is nodename=backend-subnet-a or nodename=backend-subnet-b)

  • BACCKEND-SUBNET-a
  • BACKEND-SUBNET-c

MANGE-NODEGROUPP(k8s lable is nodename=manage-subnet-a or nodename=manage-subnet-b)

  • MANAGE-SUBNET-a
  • MANAGE-SUBNET-c

이 경우 VPC CNI의 환경변수 설정을 아래와 같이 설정하고

kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=nodename

CRD를 다음과 같이 생성을 하면 됩니다.

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: frontend-subnet-a
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf01>
EOF

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: frontend-subnet-a
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf00>
EOF

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: backend-subnet-a
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf10>
EOF

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: backend-subnet-c
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf11>
EOF

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: manage-subnet-a
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf20>
EOF

cat << EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata: 
  name: manage-subnet-c
spec: 
  securityGroups: 
    - <sg-0dff111a1d11c1c11>
  subnet: <subnet-011b111c1f11fdf21>
EOF

그런데 도대체 노드가 생성될때 어떻게 노드가 어떤 AZ에 생성되는지 파악하여 노드에 라벨을 넣어줄 수 있을까요?
노드가 다 생성되고 난뒤에는 az를 파악하고 난뒤에 kubectl 명령어로 아래와 같이 설정할 수 있습니다.

kubectl label nodes <노드 이름> <라벨 키>=<라벨 값>

하지만 저희는 노드가 생성될때 할당해줘야 합니다. 노드가 생성될때 VPC CNI custom networking에 의해 IP할당도 같이 될 것이기 때문입니다.

노드가 생성될때 어떻게 라벨을 설정할 수 있는지?

정답은 노드그룹을 생성할때 Lauch tamplate을 사용하여 UserData에 아래와 같이 스크립트를 추가하면 됩니다. 파라미터 --kubelet-extra-args를 통해 노드의 라벨을 추가할 수 있습니다.

az=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)

/etc/eks/bootstrap.sh GSN-KYM-EKS --kubelet-extra-args --node-labels=nodegroup-subbnet=manage-${az}

그런데 만약에 Lauch tamplate을 사용했고 Managed EKS AMI 즉, AWS가 자동으로 관리해주는 EKS AMI 방식을 사용하게 되면 User Data에 넣은 스크립트와 자동으로 돌아가는 스크립트가 두번 동작하게 됩니다. (아래 part-001은 내가 설정한 UserData, part-002는 자동으로 생성되는 스크립트)

이게 문제가 되는데 나중에 돌아가는 part-002를 보면 아래와 같이 /etc/eks/bootstrap.sh가 한번더 돌아가게 되는데 그안에 파라미터값들이 덮어쓰기가 되어 우리가 기존에 커스텀하게 넣었던 --node-labels=nodegroup-subbnet=manage-${az}이 부분이 무시된다는 것입니다.

#!/bin/bash
set -ex
B64_CLUSTER_CA=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1EUXdNakE0TkRFMU1Gb1hEVE14TURNek1UQTROREUxTUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUtSCnBDVS9JcGt3bjNoVzNzNFFHRUpvck1lN0pxclhnVkd2NStSZkRVWm1JcCthb3hqS1Nac3ZzaFZPUWIwR2tDSVgKZmxwTEhiM0VXR3k0WEQwWEsralg3dGxCMDFlSkdPanFMaTNlOEdwanBvanZodVhjclNVUTNuNDNEWEJvMmxUQwpxVHJ5ZEsrNjBwTXNScE4xSUdMM2x6Qlg0dm84SEJrOXRRUEY3cjZNemc5S04vWEw3TnE3SGt0dkhQOG45ME9yCkVYclJsZXpJNm52NEprOElpbGlGWDhTOTBkREE2aUJtUUxIWHZsbE95Yit0UTZaTGhMN05wQ3dOaDJkR2pLSGcKbFhtRkw5M3NuVE1LSmo1ekZBTGVnV3cvMUFzUDMrcDBvcnlxTVdTcGZGOFdHMFVmQ2xsWmtUbWtJVUVZK1FEbwpEU0E1c1NnWTlsZitaTVNCbjdFQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFBUkhWalBCNEVJcUdxQ2djSFB3M3cxL01QaEcKNzRCZkx6M3dBQ2JZVTZPYklQZ2RveEpNeTV3cDVKQnZiOC95czFTWllOdGhDUWhlaFB3d1RJWlk5ZFRhQ0dqKwpzRTlwV1ZVQW93VHJnV3RYRTBOS3B6VGhMMGJuZHhUdFNMQUZrRG1xS200TUZLVmZudHcwVysyNGxzcklpMWl6Cm5lbmt4bnBDdnE5S0NFZTVIQW5mRTI1a0NyZEFPOERmYmFkT1lDeDJlTExXSWE2VFQ4aFlnckhiKzNZdzluWnQKOXZuVlJEUHQwRlJ3K2VFY2VPZmkvU2F2ZzBWMVBVWU45Mjd5MmJWWUZERWl0UVZhZ3dlUXZYR21iS1I5OUhOSgo3cUJPVzVEOWFmNnFNTmdaMnN3OUtBR0gyL0NwZmlkQzFyTUNoR0phdk4yQVR4R2c1ZVNUVmw4RVJvWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
API_SERVER_URL=https://2E72E2D7CC75D5CE001D36D61FADB656.yl4.ap-northeast-2.eks.amazonaws.com
K8S_CLUSTER_DNS_IP=172.20.0.10
/etc/eks/bootstrap.sh GSN-KYM-EKS --kubelet-extra-args '--node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=3,nodename=manage,nodegroup-type=MANAGE,eks.amazonaws.com/nodegroup-image=ami-0ff2055e699b1ac63,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=MANAGE-v2,eks.amazonaws.com/sourceLaunchTemplateId=lt-0d207bd686026bef0' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP

그렇다면 어떻게 내가 커스텀하게 설정한 /etc/eks/bootstrap.sh 의 스크립트가 덮어쓰여지지 않도록 할 수 있을까요??

그 방법은 바로 Launch template을 사용하면서 Custom AMI를 사용하는 방법 입니다. 이 말은 즉슨 만약 기존에 노드그룹이 Launch template + Custom AMI 의 전략으로 생성되어 있지 않다면 노드그룹을 새로 만들고 모두 마이그레이션 해야한다는 이야기 입니다.

Launch template + Custom AMI 의 전략은 아래 포스팅을 참고 하시기 바랍니다. eksctl을 이용한 EKS 생성 (Managed NodeGroup with Launchtemplate + Custom AMI)

이 전략을 사용하면 part-002의 스크립트가 생성되지 않으며 part-001만 생성이 됩니다. 대신 --kubelet-extra-args의 값을 아래와 같이 추가적으로 넣어 주어야합니다.

#!/bin/bash

az=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)

/etc/eks/bootstrap.sh EKSCTL-TEST --kubelet-extra-args --node-labels=eks.amazonaws.com/nodegroup=custom-nodegroup,eks.amazonaws.com/nodegroup-image=ami-078d540cf1d599e95,--node-labels=nodegroup-subbnet=manage-${az}

참고로 curl http://169.254.169.254/latest/meta-data/placement/availability-zone 이 부분은 EC2의 메타 데이터 값을 조회할 수 있는 명령어 입니다.

요약

  • EKS 클러스터에 서브넷 IP를 추가하려면 VPC CNI custom networking을 사용해야 한다.
  • VPC CNI custom networking는 다중 서브넷을 할당 할 수 없다.
  • 다중 서브넷을 할당하려면 노드가 생성될때 노드 라벨에 어떤 AZ에 생성된 노드인지를 파악하여 설정하는 스크립트가 필요하다
  • 노드에 라벨을 추가하기위해서는 노드그룹을 생성할때 Launch template + Custom AMI전략으로 생성해야한다.

결론

EKS 클러스터에 서브넷 IP를 추가하려면 EKS클러스터의 노드그룹을 생성할때 Launch template + Custom AMI전략으로 생성해야 합니다.

현재 더 쉽게 IP를 추가할 수 있는 방법을 AWS에서 현재 개발 중에 있다고 합니다. ENIConfig CRD에 다중 서브넷을 넣을 수 있도록 지원만 해주면 간단할 것 같은데 쉽지 않은가 보네요. 이상으로 포스팅 마치도록 하겠습니다. 감사합니다.

반응형