EKS 프로비저닝하기
March 2024 (1001 Words, 6 Minutes)
EKS Provisiong
이번 AEWS 스터디 에서는 Cloud Fromation을 이용해
Bastion 역할과 비슷한 EC2 Console을 생성하여 EKS를 프로비저닝 합니다.
예전 스터디 자료처럼 다음과 같은 아키텍처로 구성됩니다.
에서 그릴 수 있습니다.
CloudFormation 링크는 다음과 같습니다.
해당 Cloud Formation 링크에 접속하여 필요한 IAM 역할과 작업용 EC2에 접속하기 위한 IP를 /32로 할당 해준 후 생성 진행을 합니다.
aws configure
우선 EKS 생성을 위한 자격 증명을 진행합니다.
Access Key ID, Secret Access Key를 넣고 Region을 설정해줍니다.
이후에 생성할 클러스터의 변수들을 조회 및 설정합니다.
## EKS 배포할 VPC 정보 확인
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId)
echo "export VPCID=$VPCID" >> /etc/profile
echo $VPCID
## 퍼블릭 서브넷 ID 확인
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" | jq
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
echo "export PubSubnet1=$PubSubnet1" >> /etc/profile
echo "export PubSubnet2=$PubSubnet2" >> /etc/profile
echo $PubSubnet1
echo $PubSubnet2
이제 프로비저닝에 필요한 변수 값들을 다시 한번 확인해봅니다.
# 변수 확인
echo $AWS_DEFAULT_REGION
echo $CLUSTER_NAME
echo $VPCID
echo $PubSubnet1,$PubSubnet2
해당 작업용 EC2에서는 EKSCTL을 이용해 클러스터를 생성하기로 했습니다.
EKSCTL로 클러스터를 생성하기에 앞서, dry-run 옵션을 이용해 생성하려 하는 클러스터의 정보를 얻어보는 것이 가능합니다.
eksctl create cluster -h | grep version
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.28 --ssh-access --external-dns-access --dry-run | yh
생성하려는 클러스터의 정보를 dry-run으로 실행하면 다음과 같은 결과가 나옵니다
accessConfig:
authenticationMode: API_AND_CONFIG_MAP
apiVersion: eksctl.io/v1alpha5
cloudWatch:
clusterLogging: {}
iam:
vpcResourceControllerPolicy: true
withOIDC: false
kind: ClusterConfig
kubernetesNetworkConfig:
ipFamily: IPv4
managedNodeGroups:
- amiFamily: AmazonLinux2
desiredCapacity: 2
disableIMDSv1: true
disablePodIMDS: false
iam:
withAddonPolicies:
albIngress: false
appMesh: false
appMeshPreview: false
autoScaler: false
awsLoadBalancerController: false
certManager: false
cloudWatch: false
ebs: false
efs: false
externalDNS: true
fsx: false
imageBuilder: false
xRay: false
instanceSelector: {}
instanceType: t3.medium
labels:
alpha.eksctl.io/cluster-name: myeks
alpha.eksctl.io/nodegroup-name: myeks-nodegroup
maxSize: 2
minSize: 2
name: myeks-nodegroup
privateNetworking: false
releaseVersion: ""
securityGroups:
withLocal: null
withShared: null
ssh:
allow: true
publicKeyPath: ~/.ssh/id_rsa.pub
tags:
alpha.eksctl.io/nodegroup-name: myeks-nodegroup
alpha.eksctl.io/nodegroup-type: managed
volumeIOPS: 3000
volumeSize: 30
volumeThroughput: 125
volumeType: gp3
metadata:
name: myeks
region: ap-northeast-2
version: "1.28"
privateCluster:
enabled: false
skipEndpointCreation: false
vpc:
autoAllocateIPv6: false
cidr: 192.168.0.0/16
clusterEndpoints:
privateAccess: false
publicAccess: true
id: vpc-05c8bab796b9ffcda
manageSharedNodeSecurityGroupRules: true
nat:
gateway: Disable
subnets:
public:
ap-northeast-2a:
az: ap-northeast-2a
cidr: 192.168.1.0/24
id: subnet-002518082823e72ba
ap-northeast-2c:
az: ap-northeast-2c
cidr: 192.168.2.0/24
id: subnet-08c8e0a876668b973
이제 클러스터 구성에 이상이 없음을 확인했으므로
클러스터 생성을 시작합니다.
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.28 --ssh-access --external-dns-access --verbose 4
위의 변수확인
과정이 선행 되어있어야 클러스터 프로비저닝이 진행이 가능합니다.
프로비저닝에는 약 15분가량의 시간이 소요됩니다.
프로비저닝이 완료되면 다음과 같은 명령어로 생성된 인스턴스들의 정보를 볼 수 있습니다.
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
EKS는 노드의 확장을 노드 그룹으로 진행하는데, eksctl로 생성하면서 만들어진 nodegroup은
AWS Console의 EC2 Autoscaling Group에서도 확인이 가능합니다.
여기서 AZ별, 최소 최대 사용량등에 대한 값을 조회할수도 있습니다.
환경에따라 AWS Console에서 작업하지 않아도 되는 값들이라면 AWS CLI등 외부 환경에서도 확인 및 설정이 가능합니다.
EKS 에서의 ENI는 좀 특이한점이 있습니다.
그림에서 볼 수 있듯이, AWS Managed VPC에서의 ENI는 EKS owned ENI로 현재 프로비저닝 된 EKS Node의 ENI는 EKS owned ENI
로 설정이 되어있습니다.
계정정보는 소유자인 값이지만, 해당 ENI의 요청자 ID는 AWS측의 ID로 되어있음을 확인 할 수 있습니다. 인스턴스 소유자 또한 AWS측의 ID로 확인이 되네요
관리 편의성
Console 인스턴스 에서는 각종 Krew 패키지등 쿠버네티스를 원활하게 사용 할 수 있는 패키지들이 설치되어있습니다.
가시다님이 스터디를 진행하면서 편리성에 신경을 많이 쓴 부분들입니다.
# 자동 완성 및 alias 축약 설정
source <(kubectl completion bash)
alias k=kubectl
complete -F __start_kubectl k'
# krew 설치
curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/download/v0.4.4/krew-linux_amd64.tar.gz
tar zxvf krew-linux_amd64.tar.gz
./krew-linux_amd64 install krew
# ctx 설치
kubectl krew install ctx
# 컨텍스트 확인
kubectl ctx
# ns 설치
kubectl krew install ns
# 네임스페이스 확인
kubectl ns
# kube-ps1 설치 및 설정
git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1
cat <<"EOT" >> /root/.bash_profile
source /root/kube-ps1/kube-ps1.sh
KUBE_PS1_SYMBOL_ENABLE=true
function get_cluster_short() {
echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1
EOT
자동 완성을 통해 kubectl apply -f 같은 명령어에 자동 완성으로 많은 실수를 줄일 수 있기도 하고
kubectl addon인 krew를 통해 꽤 여러가지 패키지들을 설치할 수 있습니다
위의 사례에선 ns와 ctx를 이용해 “현재 namespace” 자동완성과 “context” 고정 등의 기능을 사용하기도 합니다.
그리고 이 두 애드온은 kube-ps1을 통해 완성이 되는데,
저런 형태로 현재 context와 namespace를 쉘 앞에서 볼 수 있어 실수를 줄일 수 있습니다.
API Endpoint 변경하기
AWS Console의 EKS 메뉴에서 확인 가능한
control plane의 api 서버 엔드 포인트는
kubectl cluster-info에서 확인 가능한 control plane의 주소와 동일합니다.
근데 그 API 서버는 Public으로 되어있습니다.
API 서버 Public 주소 확인을 해보면 전부 Public으로 되어있는 것을 확인 할 수 있습니다
위의 AWS EKS 장표에서도 확인이 가능하지만, EKS의 Controlplane이 AWS Managed 영역에서 Public 으로 Open되어있는것을 별도로 변경 해 줄 수 있습니다.
aws eks update-cluster-config \
--region ap-northeast-2 \
--name myeks \
--resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true
명령어로 API Endpoint를 Private로 수정했습니다.
해당 API Endpoint 정보를 EKS내에서 업데이트하는데 시간이 소요되는데
다음과 같은 명령어로 API DNS를 조회해봅니다.
while true; do dig +short $APIDNS ; echo "------------------------------" ; date; sleep 1; done
명령어를 통해 엔드포인트를 조회했고
public ip에서
private ip로 변경된것을 확인할 수 있었습니다
콘솔 에서도 프라이빗으로 변경된것을 확인할 수 있습니다.
Private ECR 만들기
AWS에서 제공하는 Public 컨테이너 이미지 레지스트리는
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/add-ons-images.html
에서 확인이 가능하며, 서울리전의 경우
602401143452.dkr.ecr.ap-southeast-2.amazonaws.com
주소를 사용합니다.
하지만 Public ECR뿐만아니라 개인적인 Private ECR을 사용해야할경우,
aws_account_id.dkr.ecr.region.amazonaws.com
와 같은 형태로 생성해서 사용이 가능합니다.
우선 Private ECR을 생성하기 전에 Public ECR의 접근을 다뤄보겠습니다.
Public ECR Login
ecr에 로그인하기전에 docker pull 등의 작업을 할경우
Error response from daemon: Head “<이미지명>”: no basic auth credentials이미지명>
에러가 발생하는데 자격증명을 한 후에 다시 시도해봅니다.
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com
EKS Nodegroup의 IAM Role에 AmazonEC2ContainerRegistryReadOnly 의 권한이 부여되어있어 ECR에서 이미지를 가져오는 것이 가능합니다.
하지만 Public ECR만으로는 작업을 할 수 없기에, Private ECR을 AWS CLI로 생성해줍니다.
aws ecr create-repository \
--repository-name mont-private-ecr \
--image-scanning-configuration scanOnPush=true \
--region ap-northeast-2
Private ECR을 생성한 후 데이터들을 확인해봅니다.
# ecr 조회
aws ecr describe-repositories
aws ecr describe-images --repository-name mont-private-ecr
CLI 명령어로도 ECR에 대해서 확인이 가능하지만, 실제로 ECR에 접근하기위해선 IAM 권한을 갖고있는 상태에서 docker login을 해주어야 pull/push 가 가능합니다.
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin <계정ID>.dkr.ecr.ap-northeast-2.amazonaws.com
자격증명을 완료한후, 정상적으로 이미지를 pull / push 가능한것을 확인했습니다.
ECR에 Pull 과 Push 의 적절한 권한을 부여하여 최소 권한 액세스 부여 원칙을 지키는 아키텍처를 구성하는데 힘써야합니다.