이전 게시글: [AWS] EKS 클러스터 구성 1 - 네트워크 구성
참고자료: Amazon EKS 클러스터 생성
이전 게시글에서는 AWS CLI를 사용하여 VPC, 서브넷, 게이트웨이 등 네트워크 인프라를 구성해 보았습니다. 이번에는 그 위에 Amazon EKS 클러스터를 구축하는 방법을 살펴보겠습니다.
EKS를 생성할 때는 eksctl
이라는 명령어 유틸을 사용할 수 있습니다. 가장 큰 장점은 쿠버네티스 자원을 배포할 때처럼 yaml파일에 모든 설정을 담아서 명령어 한번으로 템플릿처럼 EKS 클러스터를 생성하고, eksctl
을 통해 여러가지 정보를 수정이 가능합니다.
다만 앞서 콘솔을 사용하지 않았듯이 AWS CLI에 익숙해지면서 한 단계씩 생성해보기 위해서 AWS CLI 방식을 사용하겠습니다.
EKS는 노드를 생성/제거하거나 EBS 등의 AWS 서비스를 스스로 사용 및 관리 할 수 있어야 하기 때문에 EKS 자체에 IAM 권한을 부여해야합니다.
# JSON 정책 파일 생성
cat > eks-cluster-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# IAM 역할 생성
aws iam create-role \
--role-name my-eks-cluster-role \
--assume-role-policy-document file://eks-cluster-policy.json
# AmazonEKSClusterPolicy 정책 연결
aws iam attach-role-policy \
--role-name my-eks-cluster-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
아마존은 AmazonEKSClusterPolicy
라는 정책을 사전 정의해서 제공하고 있습니다. 콘솔에서 조회해보면 EKS에 볼륨을 붙이거나, 라우팅을 조회해서 로드밸런싱을 붙이는 등 EKS 클러스터 내 EC2 자원을 관리하기 위한 권한들이 구성되어 있습니다.
EKS 노드도 IAM 권한이 필요합니다. 현재 노드의 상태를 조회하고, 다른 노드와의 라우팅 설정과 pod 배포에 필요한 이미지를 가져오는 권한 등이 포함됩니다.
# JSON 정책 파일 생성
cat > node-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# IAM 역할 생성
aws iam create-role \
--role-name my-eks-node-role \
--assume-role-policy-document file://node-trust-policy.json
# 필요한 정책 연결
aws iam attach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
클러스터 내 control plane 또는 노드 간 통신을 위한 보안 그룹을 생성합니다.
# 클러스터 보안 그룹 생성
aws ec2 create-security-group \
--group-name my-eks-cluster-sg \
--description "EKS cluster security group" \
--vpc-id vpc-1a2b3cEXAMPLE \
--tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=my-eks-cluster-sg}]' \
--query GroupId \
--output text
>>> sg-1a2b3cEXAMPLE
create-cluster
명령어로 EKS 클러스터를 생성합니다.
aws eks create-cluster \
--name my-eks-cluster \
--role-arn arn:aws:iam::123456789012:role/my-eks-cluster-role \
--resources-vpc-config subnetIds=subnetprivate-az1,subnet--az2,subnetpublic-az1,subnetpublic-az2,securityGroupIds=sg-1a2b3cEXAMPLE \
--kubernetes-version 1.32 \
--region ap-northeast-2
1.32
는 현재(25년 3월 23일) 기준 최신 버전입니다. EKS의 Kubernetes 버전 수명 주기를 참고해서 가능한 최신 버전을 선택하는 것이 좋습니다. EKS는 다음 마이너 버전 출시 후 14개월까지만 기본 지원을 제공하는데, 기본 지원이 끝나면 클러스터 요금이 6배(!)가 되버립니다.EKS 클러스터 생성에는 몇 분정도 걸리기 때문에 아래 명령어로 생성 완료를 확인 후 진행합시다.
aws eks describe-cluster \
--name my-eks-cluster \
--query "cluster.status"
>>> "ACTIVE" 반환 시 생성 완료된 것
kubectl
명령어로 EKS Cluster의 자원들을 관리하기 위해서는 ~/.kube/config
파일을 설정해주어야 합니다.
다행히도 AWS에서 설정을 자동으로 수행해주는 명령어를 제공합니다.
# ~/.kube/config 파일 자동 설정
aws eks update-kubeconfig \
--name my-eks-cluster \
--region ap-northeast-2
# 설정 결과 확인
vim ~/.kube/config
# 출력
- name: arn:aws:eks:ap-northeast-2:{USER_ID}:cluster/my-eks-cluster
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- --region
- ap-northeast-2
- eks
- get-token
- --cluster-name
- my-eks-cluster
- --output
- json
command: aws
위와 같은 내용이 추가되어있다면 잘 적용된 것입니다. aws eks get-token
명령어를 통해 인증 토큰을 가져와서 eks에 kubectl 명령어를 전송할 때 함께 보내는 방식입니다.
설정이 되었다면 kubectl get namespace
등의 명령어로 연결 상태를 확인할 수 있습니다.
EKS 클러스터에 워커 노드를 배포하는 방법은 managed node groups
와 unmanaged node groups
가 있습니다.
그런데 unmanaged node groups는 말 그대로 AWS EKS가 관리하지 않는 노드들이기 때문에 EKS 콘솔에도 나타나지 않고 버전 업데이트 등을 모두 수동으로 수행해주어야 합니다.
또, eksctl create nodegroup --managed=false
로만 생성할 수 있어서 CLI로 생성하는 것도 불가능하니 managed node groups으로 진행하겠습니다.
노드 그룹 구성에 앞서 Launch Template를 먼저 구성하는게 좋습니다.
노드 그룹으로 launch template을 지정하면, 노드의 스펙을 변경해야할 때 템플릿만 수정하면 되고, 노드의 rolling update가 지원됩니다.
만약 launch template 없이 생성한 노드 그룹의 설정을 변경해야하면, 변경된 설정의 노드 그룹을 새로 만들고, kubectl cordon
으로 기존 노드의 스케줄링을 비활성화 -> 새 노드로 drain -> 기존 노드 그룹 삭제의 과정을 모두 수동으로 진행해야 하기 때문 작업이 많이 번거로워집니다.
# (추천 X) aws cli로 launch template 생성
aws ec2 create-launch-template \
--launch-template-name MyClusterNodeGroupLaunchTemplate \
--launch-template-data '{"NetworkInterfaces":[{"DeviceIndex":0,"AssociatePublicIpAddress":false,"Groups":["sg-1a2b3cEXAMPLE"],"DeleteOnTermination":true}],"InstanceType":"t3.medium","BlockDeviceMappings":[{"DeviceName":"/dev/xvda","Ebs":{"VolumeSize":20}}]}' --region ap-northeast-2 \
--query LaunchTemplate.LaunchTemplateId \
--output text
>> lt-1a2b3cEXAMPLE
인자로 structured string을 입력해야 해서 다소 복잡해 보입니다.
이 때문인지 공식 문서에서는 console을 통해 생성하는 가이드만 제공하고 있습니다.
때문에 위 명령어보다는 아래 사항에 주의해서 콘솔로 생성하는 것이 더 좋아보입니다.
이제 launch template을 이용하여 노드 그룹을 생성합시다.
한가지 문제가 있는데 launch template을 지정해서 노드 그룹을 생성하려면 콘솔 또는 eksctl를 이용해야 하는 것 같습니다. (제가 못찾은 것일수도 있습니다)
하지만 eksctl
로 노드 그룹를 생성하기 위해서는 eksctl managed cluster여야 하는데, AWS CLI로 생성한 클러스터는 해당하지 않습니다.
때문에 이번에는 콘솔에서 생성을 진행하였습니다.
AWS CLI 가이드가 좀처럼 없던것엔 이유가 있었네요...
앞서 생성한 AWS 리소스들이 콘솔에서 조회가 되기 때문에 선택해주시면 됩니다.
테스트 용이기 때문에 노드 개수는 전부 1로 설정해주었습니다.
EKS 클러스터 때와 마찬가지로 다소 시간이 걸립니다.
# 생성 상태 확인
aws eks describe-nodegroup \
--cluster-name my-eks-cluster \
--nodegroup-name my-eks-node-group \
--query "nodegroup.status"
>>> ACTIVE가 출력되면 생성이 완료된 것
노드가 준비되면 kubectl을 사용하여 확인할 수 있습니다:
kubectl get nodes
# 배포 YAML 생성
cat > nginx-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: nginx
EOF
# 배포 적용
kubectl apply -f nginx-deployment.yaml
배포 상태를 확인합니다:
kubectl get pods
kubectl get svc
EKS가 LoadBalancer 타입의 자원을 감지하면 자동으로 인터넷과 연결된 AWS의 로드밸런서를 프로비저닝 해줍니다.
콘솔에서 생성된 로드밸런서의 DNS 이름을 확인한 뒤 웹 브라우저에서 접속하면 Nginx 기본 페이지가 표시되어야 합니다.
그리고 프라이빗 서브넷에 있는 노드에서 NAT 게이트웨이를 통해 인터넷에 아웃바운드 트래픽을 보낼 수 있는지 확인해보는 걸로 테스트를 마치겠습니다.
kubectl exec -it nginx -- /bin/bash
curl -o https://www.google.com/
실습 후 비용이 발생하지 않도록 리소스를 정리합니다.
# 배포된 애플리케이션 삭제
kubectl delete -f nginx-deployment.yaml
# 노드 그룹 삭제
aws eks delete-nodegroup \
--cluster-name my-eks-cluster \
--nodegroup-name my-eks-node-group \
--region ap-northeast-2
# 노드 그룹이 완전히 삭제될 때까지 기다립니다
# 클러스터 삭제
aws eks delete-cluster \
--name my-eks-cluster \
--region ap-northeast-2
# IAM 역할 및 정책 정리
aws iam detach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam detach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam detach-role-policy \
--role-name my-eks-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam delete-role \
--role-name my-eks-node-role
aws iam detach-role-policy \
--role-name my-eks-cluster-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
aws iam delete-role \
--role-name my-eks-cluster-role
처음에 그렸던 아키텍처대로 EKS Cluster를 구축하였습니다.
여기에 더해 모니터링, 클러스터 관리, 스토리지(EBS, S3 등) 볼륨 마운트 등을 추가하기 위해서는 Addon을 클러스터에 추가하는 과정이 필요합니다. 이건 시간이 되면 추가로 작성하려고 합니다.