EKS Version Upgrade 워크샵 내용을 정리합니다.
Amazon EKS Upgrades: Strategies and Best Practices
워크샵 제공해주신 AWS 관계자님 & 가시다님 감사합니다.
Version Upgrade
EKS는 쿠버네티스 프로젝트 릴리스 주기를 따르며, 평균 4개월에 한번씩 마이너 버전이 출시됩니다.
EKS는 마이너 버전 출시 후 14개월동안 EKS 표준 지원을 받습니다.
표준 지원이 끝지나면 12개월동안 확장지원이 지원되나 비용이 6배 증가합니다.
- 표준 지원 : 클러스터 별 시간당 0.1$, 확장지원 0.6$
25년 4월 기준 버전 출시일정은 다음과 같습니다.
Kubernetes 클러스터의 보안, 안정성, 성능 및 호환성을 유지하는 데 중요하며, 플랫폼에서 제공하는 최신 기능과 역량을 활용할 수 있도록 보장합니다.
쿠버네티스 버전은 컨트롤 플레인과 데이터 플레인를 모두 포함합니다.
AWS EKS의 경우 공동 책임 모델에 의하여 AWS가 컨트롤 플레인을 관리하게 되며 , 데이터 플레인은 클러스터 소유자가 업그레이드를 해야할 책임이 있습니다.
업그레이드 버전 순서
클러스터 버전 업그레이드 순서는 다음과 같습니다.
- EKS 업그레이드 준비
- 클러스터 백업(선택사항)
- 컨트롤 플레인 업그레이드
- Addon 업그레이드
- 데이터 플레인 업그레이드(In -Plcae, Blue-Green)
참고 사항
- version skew policy에 따라 컨트롤 플레인과 데이터 플레인간 3개의 마이너 버전 호환성을 가집니다.
- 버전 순서를 바꾸는 것은 예상치 못한 동작을 발생합니다.
실습 환경 확인
EKS 컨트롤 플레인, 데이터 플레인 Version 1.25 Terraform EKS BluePrint 로 구성
# 클러스터 구성 확인
eksctl get cluster
NAME REGION EKSCTL CREATED
eksworkshop-eksctl us-west-2 False
# 컨트롤 플레인 버전 확인
aws eks describe-cluster --name $EKS_CLUSTER_NAME | jq
..
"cluster": {
"version": "1.25",
..
# addon 구성 확인 1. AWS addon
eksctl get addon --cluster $CLUSTER_NAME
NAME VERSION STATUS ISSUES IAMROLE UPDATE AVAILABLE CONFIGURATION VALUES
aws-ebs-csi-driver v1.41.0-eksbuild.1 ACTIVE 0 arn:aws:iam::773588311077:role/eksworkshop-eksctl-ebs-csi-driver-2025033005471319150000001d
coredns v1.8.7-eksbuild.10 ACTIVE 0 v1.9.3-eksbuild.22,v1.9.3-eksbuild.21,v1.9.3-eksbuild.19,v1.9.3-eksbuild.17,v1.9.3-eksbuild.15,v1.9.3-eksbuild.11,v1.9.3-eksbuild.10,v1.9.3-eksbuild.9,v1.9.3-eksbuild.7,v1.9.3-eksbuild.6,v1.9.3-eksbuild.5,v1.9.3-eksbuild.3,v1.9.3-eksbuild.2
kube-proxy v1.25.16-eksbuild.8 ACTIVE 0
vpc-cni v1.19.3-eksbuild.1 ACTIVE 0
# addon 구성 확인 2. 서드 파티
helm list -A
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
argo-cd argocd 1 2025-03-30 05:52:33.912269919 +0000 UTC deployed argo-cd-5.55.0 v2.10.0
aws-efs-csi-driver kube-system 1 2025-03-30 05:53:03.366112976 +0000 UTC deployed aws-efs-csi-driver-2.5.6 1.7.6
aws-load-balancer-controller kube-system 1 2025-03-30 05:53:03.311299928 +0000 UTC deployed aws-load-balancer-controller-1.7.1 v2.7.1
karpenter karpenter 1 2025-03-30 05:53:02.547414863 +0000 UTC deployed karpenter-0.37.0 0.37.0
metrics-server kube-system 1 2025-03-30 05:52:33.909528959 +0000 UTC deployed metrics-server-3.12.0 0.7.0
# 데이터 플레인 버전 확인 1. 노드 그룹
eksctl get nodegroup --cluster $CLUSTER_NAME
CLUSTER NODEGROUP STATUS CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID ASG NAME TYPE
eksworkshop-eksctl blue-mng-2025033005474785250000002b ACTIVE 2025-03-30T05:47:49Z 1 2 1 m5.large,m6a.large,m6i.large AL2_x86_64 eks-blue-mng-2025033005474785250000002b-f2caf2cb-c39d-eadb-7113-a366a35c0387 managed
eksworkshop-eksctl initial-20250330054747829400000029 ACTIVE 2025-03-30T05:47:49Z 2 10 2 m5.large,m6a.large,m6i.large AL2_x86_64 eks-initial-20250330054747829400000029-68caf2cb-c38c-dd8d-d589-e617df1c2afd managed
# 데이터 플레인 버전 확인 2. fargate profile 구성 확인
eksctl get fargateprofile --cluster $CLUSTER_NAME
NAME SELECTOR_NAMESPACE SELECTOR_LABELS POD_EXECUTION_ROLE_ARN SUBNETS TAGS STATUS
fp-profile assets <none> arn:aws:iam::773588311077:role/fp-profile-20250330054742331800000021 subnet-00b8866f562019542,subnet-03d62f35a7786e72f,subnet-083e8dff66d967d83 Blueprint=eksworkshop-eksctl,GithubRepo=github.com/aws-ia/terraform-aws-eks-blueprints,karpenter.sh/discovery=eksworkshop-eksctl ACTIVE
# 데이터 플레인 버전 확인 3. Karpenter
kubectl get nodepools
NAME NODECLASS
default default
# 데이터 플레인 버전 확인 3. Karpenter
kubectl get nodeclaims
NAME TYPE ZONE NODE READY AGE
default-cl56j m6i.large us-west-2a ip-10-0-13-94.us-west-2.compute.internal True 2d8h
# 노드 그룹 구성 확인
kubectl get nodes \
--label-columns=eks.amazonaws.com/nodegroup,karpenter.sh/nodepool,eks.amazonaws.com/capacityType,node.kubernetes.io/lifecycle,karpenter.sh/capacity-type,eks.amazonaws.com/compute-type,node.kubernetes.io/instance-type,kubernetes.io/arch,kubernetes.io/os,topology.kubernetes.io/zone
NAME STATUS ROLES AGE VERSION NODEGROUP NODEPOOL CAPACITYTYPE LIFECYCLE CAPACITY-TYPE COMPUTE-TYPE INSTANCE-TYPE ARCH OS ZONE
fargate-ip-10-0-46-241.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-2d5f260 fargate amd64 linux us-west-2c
ip-10-0-13-94.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 default spot m6i.large amd64 linux us-west-2a
ip-10-0-16-54.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 self-managed m5.large amd64 linux us-west-2b
ip-10-0-17-142.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 initial-20250330054747829400000029 ON_DEMAND m5.large amd64 linux us-west-2b
ip-10-0-42-186.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 initial-20250330054747829400000029 ON_DEMAND m5.large amd64 linux us-west-2c
ip-10-0-45-187.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 self-managed m5.large amd64 linux us-west-2c
ip-10-0-6-32.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 blue-mng-2025033005474785250000002b ON_DEMAND m5.large amd64 linux us-west-2a
# 노드 테인트 확인
kubectl get nodes -o custom-columns='NODE:.metadata.name,TAINTS:.spec.taints[*].key,VALUES:.spec.taints[*].value,EFFECTS:.spec.taints[*].effect'
NODE TAINTS VALUES EFFECTS
fargate-ip-10-0-46-241.us-west-2.compute.internal eks.amazonaws.com/compute-type fargate NoSchedule
ip-10-0-13-94.us-west-2.compute.internal dedicated CheckoutApp NoSchedule
ip-10-0-16-54.us-west-2.compute.internal <none> <none> <none>
ip-10-0-17-142.us-west-2.compute.internal <none> <none> <none>
ip-10-0-42-186.us-west-2.compute.internal <none> <none> <none>
ip-10-0-45-187.us-west-2.compute.internal <none> <none> <none>
ip-10-0-6-32.us-west-2.compute.internal dedicated
- fargete 전용 노드
- CheckoutApp, OrderApp 전용 노드 Toleration이 없다면 해당 파드로 못 들어감
# crd 확인
kubectl get crd
NAME CREATED AT
applications.argoproj.io 2025-03-30T05:52:36Z
applicationsets.argoproj.io 2025-03-30T05:52:37Z
appprojects.argoproj.io 2025-03-30T05:52:36Z
cninodes.vpcresources.k8s.aws 2025-03-30T05:43:32Z
ec2nodeclasses.karpenter.k8s.aws 2025-03-30T05:53:02Z
eniconfigs.crd.k8s.amazonaws.com 2025-03-30T05:45:21Z
ingressclassparams.elbv2.k8s.aws 2025-03-30T05:53:03Z
nodeclaims.karpenter.sh 2025-03-30T05:53:02Z
nodepools.karpenter.sh 2025-03-30T05:53:02Z
policyendpoints.networking.k8s.aws 2025-03-30T05:43:32Z
securitygrouppolicies.vpcresources.k8s.aws 2025-03-30T05:43:32Z
targetgroupbindings.elbv2.k8s.aws 2025-03-30T05:53:03Z
# argoCD 확인
kubectl get applications -n argocd
NAME SYNC STATUS HEALTH STATUS
apps Synced Healthy
assets Synced Healthy
carts Synced Healthy
catalog Synced Healthy
checkout Synced Healthy
karpenter Synced Healthy
orders Synced Healthy
other Synced Healthy
rabbitmq Synced Healthy
ui OutOfSync Healthy
# 구성 파드 확인
kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
argocd argo-cd-argocd-application-controller-0 1/1 Running 0 2d8h
argocd argo-cd-argocd-applicationset-controller-74d9c9c5c7-dhkpv 1/1 Running 0 2d8h
argocd argo-cd-argocd-dex-server-6dbbd57479-csnkh 1/1 Running 0 2d8h
argocd argo-cd-argocd-notifications-controller-fb4b954d5-d5fsq 1/1 Running 0 2d8h
argocd argo-cd-argocd-redis-76b4c599dc-gs47l 1/1 Running 0 2d8h
argocd argo-cd-argocd-repo-server-6b777b579d-5wxgm 1/1 Running 0 2d8h
argocd argo-cd-argocd-server-86bdbd7b89-klvk6 1/1 Running 0 2d8h
assets assets-7ccc84cb4d-ngfjf 1/1 Running 0 2d8h
carts carts-7ddbc698d8-xqffb 1/1 Running 0 2d8h
carts carts-dynamodb-6594f86bb9-l9q5g 1/1 Running 0 2d8h
catalog catalog-857f89d57d-mzllb 1/1 Running 3 (2d8h ago) 2d8h
catalog catalog-mysql-0 1/1 Running 0 2d8h
checkout checkout-558f7777c-hggz4 1/1 Running 0 2d8h
checkout checkout-redis-f54bf7cb5-dds5x 1/1 Running 0 2d8h
karpenter karpenter-5c7d586576-kf2kr 1/1 Running 0 2d8h
karpenter karpenter-5c7d586576-zpsfw 1/1 Running 1 (2d8h ago) 2d8h
kube-system aws-load-balancer-controller-5d7b54456d-9mbrp 1/1 Running 0 2d8h
kube-system aws-load-balancer-controller-5d7b54456d-bx7nt 1/1 Running 0 2d8h
kube-system aws-node-bqmkt 2/2 Running 0 2d8h
kube-system aws-node-c7svq 2/2 Running 0 2d8h
kube-system aws-node-d9zzw 2/2 Running 0 2d8h
kube-system aws-node-srv48 2/2 Running 0 2d8h
kube-system aws-node-xmwkj 2/2 Running 0 2d8h
kube-system aws-node-zgvnn 2/2 Running 0 2d8h
kube-system coredns-98f76fbc4-46jrv 1/1 Running 0 2d8h
kube-system coredns-98f76fbc4-m82wn 1/1 Running 0 2d8h
kube-system ebs-csi-controller-6b575b5f4d-7bvw7 6/6 Running 0 2d8h
kube-system ebs-csi-controller-6b575b5f4d-mlwhh 6/6 Running 0 2d8h
kube-system ebs-csi-node-62nsv 3/3 Running 0 2d8h
kube-system ebs-csi-node-fc7vb 3/3 Running 0 2d8h
kube-system ebs-csi-node-fqzcm 3/3 Running 0 2d8h
kube-system ebs-csi-node-kz9d6 3/3 Running 0 2d8h
kube-system ebs-csi-node-l5rd9 3/3 Running 0 2d8h
kube-system ebs-csi-node-tvxx7 3/3 Running 0 2d8h
kube-system efs-csi-controller-5d74ddd947-9h9nz 3/3 Running 0 2d8h
kube-system efs-csi-controller-5d74ddd947-lxftq 3/3 Running 0 2d8h
kube-system efs-csi-node-657hw 3/3 Running 0 2d8h
kube-system efs-csi-node-9wxp7 3/3 Running 0 2d8h
kube-system efs-csi-node-bfq44 3/3 Running 0 2d8h
kube-system efs-csi-node-fjzqx 3/3 Running 0 2d8h
kube-system efs-csi-node-gvdg6 3/3 Running 0 2d8h
kube-system efs-csi-node-s4h6l 3/3 Running 0 2d8h
kube-system kube-proxy-62c2l 1/1 Running 0 2d8h
kube-system kube-proxy-6q5ht 1/1 Running 0 2d8h
kube-system kube-proxy-7n7z6 1/1 Running 0 2d8h
kube-system kube-proxy-9mzh7 1/1 Running 0 2d8h
kube-system kube-proxy-c2wdz 1/1 Running 0 2d8h
kube-system kube-proxy-jddxw 1/1 Running 0 2d8h
kube-system metrics-server-785cd745cd-6n9qn 1/1 Running 0 2d8h
orders orders-5b97745747-b9vtf 1/1 Running 2 (2d8h ago) 2d8h
orders orders-mysql-b9b997d9d-8nwm2 1/1 Running 0 2d8h
rabbitmq rabbitmq-0 1/1 Running 0 2d8h
ui ui-5dfb7d65fc-nr2cr 1/1 Running 0 2d8h
# pdb 확인
kubectl get pdb -A
NAMESPACE NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
karpenter karpenter N/A 1 1 2d8h
kube-system aws-load-balancer-controller N/A 1 1 2d8h
kube-system coredns N/A 1 1 2d8h
kube-system ebs-csi-controller N/A 1 1 2d8h
# argocd svc 확인
kubectl get svc -n argocd argo-cd-argocd-server
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argo-cd-argocd-server LoadBalancer 172.20.159.26 k8s-argocd-argocdar-039ae6c012-8a23ea8f8b1c8c57.elb.us-west-2.amazonaws.com 80:31453/TCP,443:31616/TCP 2d8h
# arogcd 계정 정보 확인
export ARGOCD_USER="admin"
export ARGOCD_PWD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
echo "Username: ${ARGOCD_USER}"
echo "Password: ${ARGOCD_PWD}"
# statefulSet 확인
kubectl get sts -A
NAMESPACE NAME READY AGE
argocd argo-cd-argocd-application-controller 1/1 2d8h
catalog catalog-mysql 1/1 2d8h
rabbitmq rabbitmq 1/1 2d8h
# 스토리지클래스 확인
kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
efs efs.csi.aws.com Delete Immediate true 2d8h
gp2 kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 2d8h
gp3 (default) ebs.csi.aws.com Delete WaitForFirstConsumer true 2d8h
# efs 볼륨 확인
kubectl describe sc efs
Name: efs
IsDefaultClass: No
Annotations: <none>
Provisioner: efs.csi.aws.com
Parameters: basePath=/dynamic_provisioning,directoryPerms=755,ensureUniqueDirectory=false,fileSystemId=fs-09c7449db5761f1c3,gidRangeEnd=200,gidRangeStart=100,provisioningMode=efs-ap,reuseAccessPoint=false,subPathPattern=${.PVC.namespace}/${.PVC.name}
AllowVolumeExpansion: True
MountOptions:
iam
ReclaimPolicy: Delete
VolumeBindingMode: Immediate
Events: <none>
# PV, PVC 확인
kubectl get pv,pvc -A
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-3a8a338f-a30f-4bd7-9aa2-251593f40c2f 4Gi RWO Delete Bound catalog/catalog-mysql-pvc gp3 2d8h
persistentvolume/pvc-a33898ed-3a5b-41f0-934f-8e74977a3b22 4Gi RWO Delete Bound orders/order-mysql-pvc gp3 2d8h
persistentvolume/pvc-f2535625-698f-48e2-b2c8-b172a1b440ec 4Gi RWO Delete Bound checkout/checkout-redis-pvc gp3 2d8h
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
catalog persistentvolumeclaim/catalog-mysql-pvc Bound pvc-3a8a338f-a30f-4bd7-9aa2-251593f40c2f 4Gi RWO gp3 2d8h
checkout persistentvolumeclaim/checkout-redis-pvc Bound pvc-f2535625-698f-48e2-b2c8-b172a1b440ec 4Gi RWO gp3 2d8h
orders persistentvolumeclaim/order-mysql-pvc Bound pvc-a33898ed-3a5b-41f0-934f-8e74977a3b22 4Gi RWO gp3 2d8h
# 클러스터 내 접근가능한 IAM 권한
aws eks list-access-entries --cluster-name $CLUSTER_NAME
{
"accessEntries": [
"arn:aws:iam::773-:role/aws-service-role/eks.amazonaws.com/AWSServiceRoleForAmazonEKS",
"arn:aws:iam::773-:role/blue-mng-eks-node-group-2025033005375015570000000e",
"arn:aws:iam::773-:role/default-selfmng-node-group-20250330053750304900000010",
"arn:aws:iam::773-:role/fp-profile-20250330054742331800000021",
"arn:aws:iam::773-:role/initial-eks-node-group-2025033005375015740000000f",
"arn:aws:iam::773-:role/karpenter-eksworkshop-eksctl",
"arn:aws:iam::773-:role/workshop-stack-ekstfcodebuildStackDeployProjectRole-NHlxMh6z4HgI"
]
}
# 권한 매핑 확인
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
ARN USERNAME GROUPS ACCOUNT
arn:aws:iam::77-:role/WSParticipantRole admin system:masters
arn:aws:iam::77-:role/blue-mng-eks-node-group-2025033005375015570000000e system:node:{{EC2PrivateDNSName}} system:bootstrappers,system:nodes
arn:aws:iam::77-:role/fp-profile-20250330054742331800000021 system:node:{{SessionName}} system:bootstrappers,system:nodes,system:node-proxier
arn:aws:iam::77-:role/initial-eks-node-group-2025033005375015740000000f system:node:{{EC2PrivateDNSName}} system:bootstrappers,system:nodes
arn:aws:iam::77-:role/workshop-stack-IdeIdeRoleD654ADD4-FsCM43iYJfVE admin system:masters
# RBAC 확인
kubectl describe cm -n kube-system aws-auth
..
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::773-:role/blue-mng-eks-node-group-2025033005375015570000000e
username: system:node:{{EC2PrivateDNSName}}
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::773-:role/initial-eks-node-group-2025033005375015740000000f
username: system:node:{{EC2PrivateDNSName}}
- groups:
- system:bootstrappers
- system:nodes
- system:node-proxier
rolearn: arn:aws:iam::773-:role/fp-profile-20250330054742331800000021
username: system:node:{{SessionName}}
- groups:
- system:masters
rolearn: arn:aws:iam::773-:role/WSParticipantRole
username: admin
- groups:
- system:masters
rolearn: arn:aws:iam::773-:role/workshop-stack-IdeIdeRoleD654ADD4-FsCM43iYJfVE
username: admin
..
# IRSA 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
No iamserviceaccounts found
ec2-user:~/environment:$ kubectl describe sa -A | grep role-arn
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::773588311077:role/karpenter-20250330055301070200000039
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::773588311077:role/alb-controller-2025033005530108620000003a
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::773588311077:role/eksworkshop-eksctl-ebs-csi-driver-2025033005471319150000001d
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::773588311077:role/aws-efs-csi-driver-2025033005530109790000003e
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::773588311077:role/aws-efs-csi-driver-2025033005530109790000003e
# pod identity 없음
eksctl get podidentityassociation --cluster $CLUSTER_NAME
No podidentityassociations found
# OIDC
aws eks describe-cluster --name $CLUSTER_NAME --query cluster.identity.oidc.issuer --output text
https://oidc.eks.us-west-2.amazonaws.com/id/492AE2DC69F87A8BD4CBDACD8C43A003..
# s3 버킷 확인
aws s3 ls
2025-03-30 05:34:08 workshop-stack-tfstatebackendbucketf0fc9a9d-2hmno5ruguo3
aws s3 ls s3://workshop-stack-tfstatebackendbucketf0fc9a9d-2hmno5ruguo3
2025-03-30 05:55:47 933696 terraform.tfstate
# state 확인
aws s3 cp s3://workshop-stack-tfstatebackendbucketf0fc9a9d-2hmno5ruguo3/terraform.tfstate .
# 테라폼 확인
terraform state list
data.aws_availability_zones.available
data.aws_caller_identity.current
data.aws_ecrpublic_authorization_token.token
data.aws_partition.current
aws_codecommit_repository.gitops_repo_cc
aws_eks_access_entry.karpenter_node_access_entry
aws_iam_service_specific_credential.argocd_codecommit_credential
aws_iam_user.argocd_user
aws_iam_user_policy.argocd_user_codecommit_rw
aws_secretsmanager_secret.argocd_user_creds_secret
aws_secretsmanager_secret_version.argocd_user_creds_secret_version
..
# 환경 변수 확인
cat ~/.bashrc
1. 업그레이드 준비
1.1 업그레이드 인사이트
릴리스 노트를 검토하여 더 이상 사용되지 않거나 제거된 Kubernetes API를 확인한 다음 해당 API를 사용하는 애플리케이션을 확인하는 작업
aws eks list-insights --filter kubernetesVersions=1.26 --cluster-name $CLUSTER_NAME | jq .
매니페스트 버전 마이그레이션 도구인 kubectl-covert 로 마이그레이션할 수 있습니다.
# kubectl-convert 플러그인 설치
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert"
# 사용 동작
kubectl convert -f --output-version /
1.2 업그레이드 체크리스트 확인
1.2.1 버전 업그레이드 변동 사항은 AWS 문서를 통해 참고 1.31 1.32
1.2.2 addon 및 서드 파티 도구들 호환성 확인 - 각 문서 확인
- AWS addon 들은 AWS 콘솔에서 버전 별로 업그레이드가 가능하며, 서드 파티들은 각 홈페이지에서 버전 호환성을 확인해야함
- 테스트 환경에서 충분히 사전 테스트를 해보며, velero 와 같은 백업 툴로 중요 데이터를 백업하는 것을 추천
- Amazon VPC CNI: Upgrades for Amazon EKS Add-on deployments are limited to single minor version bumps at a time.
- kube-proxy: Find upgrade instructions in Updating the Kubernetes kube-proxy self-managed add-on .
- CoreDNS: Upgrade guidance is available in Updating the CoreDNS self-managed add-on .
- AWS Load Balancer Controller: Compatibility with your EKS version is crucial. Refer to the installation guide for details.
- Amazon EBS/EFS CSI Drivers: Installation and upgrade information can be found in Managing the Amazon EBS CSI driver as an Amazon EKS add-on and Amazon EFS CSI driver respectively.
- Metrics Server: For more information, see metrics-server on GitHub .
- Cluster Autoscaler: Upgrade by modifying the image version within the deployment definition. Given its tight coupling with the scheduler, the Cluster Autoscaler typically requires upgrading alongside the cluster itself. Consult the GitHub releases to locate the latest image compatible with your Kubernetes minor version.
- Karpenter: Refer to the Karpenter documentation for installation and upgrade instructions .
1.3 EKS 컨트롤 플레인 업그레이드 전 기본 요구 사항 확인
1.3.1 사용 가능한 IP주소 확인 : 클러스터 생성 시 지정한 서브넷 내에 최소 5개의 여유 IP 주소가 필요
aws ec2 describe-subnets --subnet-ids \
$(aws eks describe-cluster --name ${CLUSTER_NAME} \
--query 'cluster.resourcesVpcConfig.subnetIds' \
--output text) \
--query 'Subnets[*].[SubnetId,AvailabilityZone,AvailableIpAddressCount]' \
--output table
----------------------------------------------------
| DescribeSubnets |
+---------------------------+--------------+-------+
| subnet-00b8866f562019542 | us-west-2b | 4049 |
| subnet-03d62f35a7786e72f | us-west-2c | 4048 |
| subnet-083e8dff66d967d83 | us-west-2a | 4050 |
+---------------------------+--------------+-------+
- 서브넷이 IP가 없는 경우 새로운 서브넷을 추가
- VPC 자체 사용할 서브넷이 없다면 추가 CIDR 블록을 추가(Add Private CIDR Blocks, Subnet Update based on New CIDR)
1.3.2 IAM Role 확인
ROLE_ARN=$(aws eks describe-cluster --name ${CLUSTER_NAME} \
--query 'cluster.roleArn' --output text)
aws iam get-role --role-name ${ROLE_ARN##*/} \
--query 'Role.AssumeRolePolicyDocument'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EKSClusterAssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": [
"sts:TagSession",
"sts:AssumeRole"
]
}
]
}
1.3.3 보안 그룹 확인
클러스터를 생성할 때 EKS는 eks-cluster-sg-my-cluster-uniqueID 라는 보안그룹을 가짐.
보안 그룹 안에는 다음의 기본 룰이 존재
- 자동 태그: EKS는 클러스터에 대해 만든 보안 그룹에 특정 태그를 주입합니다. 이러한 태그는 작동에 필수적이며 제거하면 다시 추가됩니다.
- 리소스 연결 : 이 보안 그룹은 여러 리소스에 자동으로 연결됩니다.
- 기본 보안 규칙 : 처음에 보안 그룹은 제한 없는 통신을 허용합니다.
- 사용자 지정 보안 그룹(선택 사항) : 클러스터 생성 중에 선택적으로 자체 보안 그룹을 지정할 수 있습니다. 그렇게 하는 경우:
기본적으로 EKS는 광범위한 권한을 가진 기본 보안 그룹을 제공하지만, 사용자가 사용자 정의 그룹을 사용하여 더 엄격한 보안 정책을 구현할 수 있도록 합니다.
추가 고려사항
- 아웃바운드 인터넷 액세스 (선택사항)
- 컨테이너 이미지 액세스
- IPv4/IPv6에 대한 별도 규칙
1.4 데이터 플레인 워크로드 보장
중요한 워크로드의 경우 가용성을 보장하기 위해 적절한 옵션을 설정해야 합니다.
- Pod disruption budgets(PDB) : 설정된 파드가 사용 가능한 상태로 유지되도록하는 옵션
- ToplologySpreadConstraints : 특정 노드나 가용영역에 쏠리지 않게 퍼지도록 강제하는 옵션
1.4.1 PDB 설정
kubectl get pdb
cd ~/environment
git clone codecommit::${REGION}://eks-gitops-repo
# 예제 파드 PDB 설정
cat << EOF > ~/environment/eks-gitops-repo/apps/orders/pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: orders-pdb
namespace: orders
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/component: service
app.kubernetes.io/instance: orders
app.kubernetes.io/name: orders
EOF
# 변경사항 커밋
echo " - pdb.yaml" >> ~/environment/eks-gitops-repo/apps/orders/kustomization.yaml
cd ~/environment/eks-gitops-repo/
git add apps/orders/kustomization.yaml
git add apps/orders/pdb.yaml
git commit -m "Add PDB to orders"
git push
# argoCD 싱크
export ARGOCD_SERVER=$(kubectl get svc argo-cd-argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname')
echo "ArgoCD URL: http://${ARGOCD_SERVER}"
export ARGOCD_USER="admin"
export ARGOCD_PWD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
echo "Username: ${ARGOCD_USER}"
echo "Password: ${ARGOCD_PWD}"
argocd login ${ARGOCD_SERVER} --username ${ARGOCD_USER} --password ${ARGOCD_PWD} --insecure --skip-test-tls --grpc-web
argocd app sync orders
..
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Namespace orders Synced namespace/orders unchanged
policy PodDisruptionBudget orders orders-pdb Synced poddisruptionbudget.policy/orders-pdb created
ServiceAccount orders orders Synced serviceaccount/orders unchanged
Secret orders orders-db Synced secret/orders-db unchanged
ConfigMap orders orders Synced configmap/orders unchanged
PersistentVolumeClaim orders order-mysql-pvc Synced Healthy persistentvolumeclaim/order-mysql-pvc unchanged
Service orders orders Synced Healthy service/orders unchanged
Service orders orders-mysql Synced Healthy service/orders-mysql unchanged
apps Deployment orders orders Synced Healthy deployment.apps/orders unchanged
apps Deployment orders orders-mysql Synced Healthy deployment.apps/orders-mysql unchanged
1.4.2 토폴리지 설정 확인
# 토폴로지 설정 확인
kubectl get deploy -A -o json | jq '.items[] | select(.spec.template.spec.topologySpreadConstraints != null) | {namespace: .metadata.namespace, name: .metadata.name, constraints: .spec.template.spec.topologySpreadConstraints}'
{
"namespace": "karpenter",
"name": "karpenter",
"constraints": [
{
"labelSelector": {
"matchLabels": {
"app.kubernetes.io/instance": "karpenter",
"app.kubernetes.io/name": "karpenter"
}
},
"maxSkew": 1,
"topologyKey": "topology.kubernetes.io/zone",
"whenUnsatisfiable": "ScheduleAnyway"
}
]
}
- labelSelector.matchLabels - app.kubernetes.io/instance=karpenter, app.kubernetes.io/name=karpenter 라벨을 가진 파드에만 적용됨
- maxSkew: 1 - 각 Zone 간 파드 개수 차이가 최대 1개 이하로 유지되도록 함
- topologyKey: topology.kubernetes.io/zone - Zone 단위로 파드를 고르게 분산시킴
- whenUnsatisfiable: ScheduleAnyway - 조건을 만족 못 해도 파드는 스케줄됨 (경고만 남김)
토폴리지가 변경되는 경우 파드가 재배포됩니다.
운영 환경에서 적용시 주의가 필요합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkout
spec:
template:
spec:
containers:
- name: checkout
image: ...
# 생략
topologySpreadConstraints: # 추가
- labelSelector:
matchLabels:
app.kubernetes.io/instance: checkout
app.kubernetes.io/name: checkout
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
업그레이드 전략 선택
전략
|
장점
|
단점
|
In-Place 업그레이드
|
- 기존 VPC, 서브넷, 보안 그룹 유지 - 동일한 API 엔드포인트 유지 - 여러 클러스터를 관리할 필요 없음 - 상태 저장 앱과 데이터 마이그레이션 최소화
|
- 가동 중지 최소화를 위한 사전 계획 필요 - 여러 버전 건너뛸 경우 단계별 업그레이드 필요 - 실패 시 롤백 어려움 (Control Plane은 롤백 불가) - 구성 요소 및 종속성 호환성 테스트 필요
|
Blue-Green 업그레이드
|
- 새 클러스터에서 충분히 테스트 가능 - 여러 버전 건너뛰기 가능 - 문제 발생 시 빠르게 롤백 가능 - 업그레이드 중에도 무중단 운영 가능
|
- 두 개의 클러스터를 유지해야 하므로 리소스/비용 증가 - 트래픽 전환 및 리소스 관리 복잡 - 외부 도구(CI/CD, 모니터링 등) 설정 변경 필요 - 상태 저장 앱은 데이터 동기화가 어려울 수 있음
|
- In-Place 업그레이드는 다운타임 허용 범위가 낮은 부 버전 업그레이드에 적합한 반면, Blue-Green 업그레이드는 주요 버전 업그레이드나 상태 복잡도가 높은 애플리케이션에 권장됩니다.
업그레이드는 테라폼을 기반으로 진행합니다.
In-place 업그레이드 (1.25 > 1.26)
컨트롤 플레인 업그레이드
준비 사항
- EKS 클러스터를 업데이트하기 위해 클러스터를 생성할 때 지정한 서브넷에서 최대 5개의 사용 가능한 IP 주소가 필요합니다.
- 업그레이드 인사이트 확인(API 호환성 확인)
- 클러스터에 비밀 암호화가 활성화된 경우 클러스터 IAM 역할에 AWS Key Management Service(AWS KMS) 키를 사용할 수 있는 권한이 있는지 확인 필요
- 컨테이너 이미지 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c > 1.25.txt
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.19.3-eksbuild.1
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-network-policy-agent:v1.2.0-eksbuild.1
8 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-ebs-csi-driver:v1.41.0
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.8.7-eksbuild.10
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-attacher:v4.8.1-eks-1-32-7
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-node-driver-registrar:v2.13.0-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-provisioner:v5.2.0-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-resizer:v1.13.2-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-snapshotter:v8.2.1-eks-1-32-7
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.25.16-minimal-eksbuild.8
8 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/livenessprobe:v2.14.0-eks-1-32-7
8 amazon/aws-efs-csi-driver:v1.7.6
1 amazon/dynamodb-local:1.13.1
1 ghcr.io/dexidp/dex:v2.38.0
1 hjacobs/kube-ops-view:20.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-cart:0.7.0
1 public.ecr.aws/aws-containers/retail-store-sample-catalog:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-checkout:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-orders:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-ui:0.4.0
1 public.ecr.aws/bitnami/rabbitmq:3.11.1-debian-11-r0
2 public.ecr.aws/docker/library/mysql:8.0
1 public.ecr.aws/docker/library/redis:6.0-alpine
1 public.ecr.aws/docker/library/redis:7.0.15-alpine
2 public.ecr.aws/eks-distro/kubernetes-csi/external-provisioner:v3.6.3-eks-1-29-2
8 public.ecr.aws/eks-distro/kubernetes-csi/livenessprobe:v2.11.0-eks-1-29-2
6 public.ecr.aws/eks-distro/kubernetes-csi/node-driver-registrar:v2.9.3-eks-1-29-2
2 public.ecr.aws/eks/aws-load-balancer-controller:v2.7.1
2 public.ecr.aws/karpenter/controller:0.37.0@sha256:157f478f5db1fe999f5e2d27badcc742bf51cc470508b3cebe78224d0947674f
5 quay.io/argoproj/argocd:v2.10.0
1 registry.k8s.io/metrics-server/metrics-server:v0.7.0
컨트롤 플레인 코드 확인 후 버전 업데이트
terraform state list
# 결과 텍스트 확인
terraform plan -out=tfplan.out
terraform show tfplan.out > plan.txt
텍스트가 깨져서 확인되지만, plan 결과를 확인할 수 있습니다.
terraform apply -auto-approve # 자동 적용 옵션 활성화
# 8분 정도 소요
aws eks describe-cluster --name $EKS_CLUSTER_NAME | jq
"cluster": {
"name": "eksworkshop-eksctl",
"arn": "arn:aws:eks:us-west-2:773588311077:cluster/eksworkshop-eksctl",
"createdAt": "2025-03-30T05:38:01.163000+00:00",
"version": "1.26", # 업그레이드 확인
"endpoint": "https://492AE2DC69F87A8BD4CBDACD8C43A003.gr7.us-west-2.eks.amazonaws.com",
"roleArn": "arn:aws:iam::773588311077:role/eksworkshop-eksctl-cluster-20250330053737244700000003",
"resourcesVpcConfig": {
# 컨테이너 이미지 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c > 1.26
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.19.3-eksbuild.1
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-network-policy-agent:v1.2.0-eksbuild.1
8 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-ebs-csi-driver:v1.41.0
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.8.7-eksbuild.10
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-attacher:v4.8.1-eks-1-32-7
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-node-driver-registrar:v2.13.0-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-provisioner:v5.2.0-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-resizer:v1.13.2-eks-1-32-7
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-snapshotter:v8.2.1-eks-1-32-7
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.25.16-minimal-eksbuild.8
8 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/livenessprobe:v2.14.0-eks-1-32-7
8 amazon/aws-efs-csi-driver:v1.7.6
1 amazon/dynamodb-local:1.13.1
1 ghcr.io/dexidp/dex:v2.38.0
1 public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-cart:0.7.0
1 public.ecr.aws/aws-containers/retail-store-sample-catalog:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-checkout:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-orders:0.4.0
1 public.ecr.aws/aws-containers/retail-store-sample-ui:0.4.0
1 public.ecr.aws/bitnami/rabbitmq:3.11.1-debian-11-r0
2 public.ecr.aws/docker/library/mysql:8.0
1 public.ecr.aws/docker/library/redis:6.0-alpine
1 public.ecr.aws/docker/library/redis:7.0.15-alpine
2 public.ecr.aws/eks-distro/kubernetes-csi/external-provisioner:v3.6.3-eks-1-29-2
8 public.ecr.aws/eks-distro/kubernetes-csi/livenessprobe:v2.11.0-eks-1-29-2
6 public.ecr.aws/eks-distro/kubernetes-csi/node-driver-registrar:v2.9.3-eks-1-29-2
2 public.ecr.aws/eks/aws-load-balancer-controller:v2.7.1
2 public.ecr.aws/karpenter/controller:0.37.0@sha256:157f478f5db1fe999f5e2d27badcc742bf51cc470508b3cebe78224d0947674f
5 quay.io/argoproj/argocd:v2.10.0
1 registry.k8s.io/metrics-server/metrics-server:v0.7.0
# 컨테이너 이미지 변경 사항 확인
diff 1.26.txt 1.25.txt
AWS Addon & 서드파티 업그레이드
AWS Addon 과 서드파티에 대해 호환서을 체크 후 업그레이드를 진행해야 합니다.
AWS addon는 AWS CLI 명령어를 통해 관리(버전 확인 및 업데이트 등)를 할 수 있습니다.
# 구성 addon 확인
eksctl get addon --cluster $CLUSTER_NAME
NAME VERSION STATUS ISSUES IAMROLE UPDATE AVAILABLE CONFIGURATION VALUES
aws-ebs-csi-driver v1.41.0-eksbuild.1 ACTIVE 0 arn:aws:iam::773588311077:role/eksworkshop-eksctl-ebs-csi-driver-2025033005471319150000001d
coredns v1.8.7-eksbuild.10 ACTIVE 0 v1.9.3-eksbuild.22,v1.9.3-eksbuild.21,v1.9.3-eksbuild.19,v1.9.3-eksbuild.17,v1.9.3-eksbuild.15,v1.9.3-eksbuild.11,v1.9.3-eksbuild.10,v1.9.3-eksbuild.9,v1.9.3-eksbuild.7,v1.9.3-eksbuild.6,v1.9.3-eksbuild.5,v1.9.3-eksbuild.3,v1.9.3-eksbuild.2
kube-proxy v1.25.16-eksbuild.8 ACTIVE 0 v1.26.15-eksbuild.24,v1.26.15-eksbuild.19,v1.26.15-eksbuild.18,v1.26.15-eksbuild.14,v1.26.15-eksbuild.10,v1.26.15-eksbuild.5,v1.26.15-eksbuild.2,v1.26.13-eksbuild.2,v1.26.11-eksbuild.4,v1.26.11-eksbuild.1,v1.26.9-eksbuild.2,v1.26.7-eksbuild.2,v1.26.6-eksbuild.2,v1.26.6-eksbuild.1,v1.26.4-eksbuild.1,v1.26.2-eksbuild.1
vpc-cni v1.19.3-eksbuild.1 ACTIVE 0
# coreDNS 1.26 버전 호환성 확인
aws eks describe-addon-versions --addon-name coredns --kubernetes-version 1.26 --output table \
--query "addons[].addonVersions[:10].{Version:addonVersion,DefaultVersion:compatibilities[0].defaultVersion}"
------------------------------------------
| DescribeAddonVersions |
+-----------------+----------------------+
| DefaultVersion | Version |
+-----------------+----------------------+
| False | v1.9.3-eksbuild.22 |
| False | v1.9.3-eksbuild.21 |
| False | v1.9.3-eksbuild.19 |
| False | v1.9.3-eksbuild.17 |
| False | v1.9.3-eksbuild.15 |
| False | v1.9.3-eksbuild.11 |
| False | v1.9.3-eksbuild.10 |
| False | v1.9.3-eksbuild.9 |
| True | v1.9.3-eksbuild.7 |
| False | v1.9.3-eksbuild.6 |
+-----------------+----------------------+
위 결과는 Default Version 입니다.
EKS 추가 기능에서 addon 관리 호환성을 확인할 수 있으니 상황에 따라 맞춰 가면 됩니다.
addon.tf에서 addon 코드값을 변경하겠습니다.
terraform plan
terraform apply -auto-approve
데이터 플레인 업그레이드
데이터 플레인에 따라 업그레이드 방식과 인프레이스 내 전략이 존재합니다.
# 노드 그룹 구성 확인
kubectl get nodes \
--label-columns=eks.amazonaws.com/nodegroup,karpenter.sh/nodepool,eks.amazonaws.com/capacityType,node.kubernetes.io/lifecycle,karpenter.sh/capacity-type,eks.amazonaws.com/compute-type,node.kubernetes.io/instance-type,kubernetes.io/arch,kubernetes.io/os,topology.kubernetes.io/zone
NAME STATUS ROLES AGE VERSION NODEGROUP NODEPOOL CAPACITYTYPE LIFECYCLE CAPACITY-TYPE COMPUTE-TYPE INSTANCE-TYPE ARCH OS ZONE
fargate-ip-10-0-46-241.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-2d5f260 fargate amd64 linux us-west-2c
ip-10-0-13-94.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 default spot m6i.large amd64 linux us-west-2a
ip-10-0-16-54.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 self-managed m5.large amd64 linux us-west-2b
ip-10-0-17-142.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 initial-20250330054747829400000029 ON_DEMAND m5.large amd64 linux us-west-2b
ip-10-0-42-186.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 initial-20250330054747829400000029 ON_DEMAND m5.large amd64 linux us-west-2c
ip-10-0-45-187.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 self-managed m5.large amd64 linux us-west-2c
ip-10-0-6-32.us-west-2.compute.internal Ready <none> 2d8h v1.25.16-eks-59bf375 blue-mng-2025033005474785250000002b ON_DEMAND m5.large amd64 linux us-west-2a
데이터플레인 1. 관리 노드 그룹 업그레이드 (인플레이스)
EKS 관리 노드 업그레이드는 5단계로 진행됩니다.
단계
|
설명
|
주요 설정 / 조건
|
1. 설정 단계
|
새로운 AMI 또는 시작 템플릿 버전 생성 후, ASG에 반영
|
- 새 Launch Template 버전 생성 - updateConfig로 최대 병렬 업그레이드 노드 수 설정 (기본 1, 최대 100)
|
2. 확장 단계
|
ASG의 크기를 일시적으로 증가시켜 새 노드 추가
|
- ASG 최대/원하는 크기 증가(자동) - 최대 확장은 AZ 수의 2배까지 가능
|
3. 준비 단계
|
새 노드 준비 및 기존 노드 예약 불가 처리
|
- 새 노드 준비 상태 확인 - 기존 노드에 NoSchedule taint 부여- node.kubernetes.io/exclude-from-external-load-balancers=true 레이블 설정
|
4. 업그레이드 단계
|
기존 노드를 순차적으로 교체
|
- 최대 병렬 업그레이드 수만큼 노드 선택 - Pod 퇴거 (15분 제한, 실패 시 force 플래그 사용) - 퇴거 후 60초 대기 및 ASG 종료 요청 - 이전 노드 모두 교체될 때까지 반복
|
5. 축소 단계
|
ASG 크기를 원래대로 복원
|
- ASG의 maxSize, desiredSize를 원래대로 감소
|
- 업그레이드 단계(15분 제한)이 끝나면 데이터 플레인은 원복됩니다. 파드 또한 다시 마이그레이션되니 파드 스케쥴링 검증이 필요합니다.
업그레이드 방법은 두 가지입니다.
- Using default AMI for given K8s version - 버전만 기입하여 업그레이드, AMI는 AWS 제공하는 최적화된 이미지로 설정됩니다.
- Using specific AMI ID (like custom AMIs) - 사용자 정의 버전 AMI를 지정하여 업그레이드
Using default AMI for given K8s version 은 테라폼 코드에서 버전만 수정하면 동작합니다.
Using specific AMI ID (like custom AMIs)은 AMI를 검색하여 기입해야 합니다.
확인한 AMI를 가지고 신규 그룹을 생성하여 적용하겠습니다.
# AMI 확인
aws ssm get-parameter --name /aws/service/eks/optimized-ami/1.26/amazon-linux-2/recommended/image_id \
--region $AWS_REGION --query "Parameter.Value" --output text
ami-086414611b43bb691
terraform plan
terraform apply -auto-approve
데이터플레인 2. 관리 노드 그룹 업그레이드 (블루/그린)
쿠버네티스 skew 정책에 따라 버전 호환 범위 내에서 노드 그룹을 신규 생성하여 블루/그린 방식으로 이주가 가능합니다. 상태 저장 워크로드(order) 를 가지고 업그레이드를 진행하겠습니다.
기존 블루 그룹을 확인하겠습니다.
kubectl get nodes -l type=OrdersMNG
NAME STATUS ROLES AGE VERSION
ip-10-0-6-32.us-west-2.compute.internal Ready <none> 2d23h v1.25.16-eks-59bf375
blue-mng={
instance_types = ["m5.large", "m6a.large", "m6i.large"]
cluster_version = "1.25"
min_size = 1
max_size = 2
desired_size = 1
update_config = {
max_unavailable_percentage = 35
}
labels = {
type = "OrdersMNG"
}
subnet_ids = [module.vpc.private_subnets[0]]
taints = [
{
key = "dedicated"
value = "OrdersApp"
effect = "NO_SCHEDULE"
}
]
}
주목할 점은 노드 Taint 입니다.
신규 노드 그룹 생성시 위와 같이 그대로 구성하여 추가해야 합니다.
terraform plan
terraform apply -auto-approve
노드 그룹 생성 확인 후 파드를 마이그레이션 해야합니다.
PDB가 설정된 replica 수를 늘려 해당 노드에 파드를 배치하겠습니다.
kubectl get nodes -l type=OrdersMNG -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints[?(@.effect=='NoSchedule')]}{\"\n\"}{end}"
# 애플리케이션 파드 설정
cd ~/environment/eks-gitops-repo/
sed -i 's/replicas: 1/replicas: 2/' apps/orders/deployment.yaml
git add apps/orders/deployment.yaml
git commit -m "Increase orders replicas 2"
git push
# arogoCD 싱크
argocd app sync orders
파드 확인 후 이전 노드 그룹을 삭제하겠습니다.
terraform plan
terraform apply -auto-approve
데이터플레인 2. 카펜터 (Karpenter)
Drift나 타이머(expireAfter) 와 같은 기능은 Karpenter를 통해 프로비저닝된 Kubernetes 데이터 플레인에 적용합니다.
기능
|
설명
|
예시
|
Drift (드리프트)
|
노드가 "원래 의도한 상태"와 다르게 된 경우 자동으로 교체
|
태그, 보안 설정, AMI 등이 변경되는 경우
|
expireAfter (만료 타이머)
|
노드를 일정 시간 후 자동 종료
|
TTL 설정 값이 지나면 변경
|
드리프트 방식은 다음과 같이 나뉘어 분류됩니다.
- amiSelectorTerms를 사용하여 AMI ID, AMI 이름 또는 특정 태그로 명시적으로 지정
- amiSelectorTerms가 지정되지 않은 경우 Karpenter는 Amazon EKS 최적화 AMI에 대해 게시된 SSM 매개변수를 모니터링하여 최신 버전이 있는 경우 교체
expireAfter는 노드 풀에서 spec.template.spec.expireAfter 를 통해 설정 가능합니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
# Template section that describes how to template out NodeClaim resources that Karpenter will provision
# Karpenter will consider this template to be the minimum requirements needed to provision a Node using this NodePool
# It will overlay this NodePool with Pods that need to schedule to further constrain the NodeClaims
# Karpenter will provision to launch new Nodes for the cluster
template:
# The amount of time a Node can live on the cluster before being removed
# Avoiding long-running Nodes helps to reduce security vulnerabilities as well as to reduce the chance of issues that can plague Nodes with long uptimes such as file fragmentation or memory leaks from system processes
# You can choose to disable expiration entirely by setting the string value 'Never' here
# Note: changing this value in the nodepool will drift the nodeclaims.
expireAfter: 720h | Never
expireAfter 의 경우 NodePool의 spec.disruption.budgets를 통해 Karpenter의 중단을 제한할 수 있습니다.
예를 들어 "30일 뒤에 만료” 만료 후 동작 스케쥴링을 아래와 같이 변경할 수 있습니다.
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec: # This is not a complete NodePool Spec.
disruption:
consolidationPolicy: WhenEmpty
expireAfter: 720h # 30 * 24h = 720h
budgets:
- schedule: "0 9 * * mon-fri"
duration: 8h
nodes: 0
- nodes: 10
Karpenter는 평일 업무 시간 동안 노드를 프로비저닝 해제할 수 없고, 다른 시간에는 10개의 노드만 동시에 프로비저닝 해제할 수 있도록 허용합니다.
구성된 노드 풀은 다음과 같이 확인할 수 있습니다.
kubectl describe nodepool
Name: default
Namespace:
Labels: argocd.argoproj.io/instance=karpenter
Annotations: karpenter.sh/nodepool-hash: 12028663807258658692
karpenter.sh/nodepool-hash-version: v2
API Version: karpenter.sh/v1beta1
Kind: NodePool
Metadata:
Creation Timestamp: 2025-03-30T05:58:00Z
Generation: 1
Resource Version: 6627
UID: e0394e0b-dfc2-40a6-b8e9-d4d6865b588b
Spec:
Disruption:
Budgets:
Nodes: 10%
Consolidation Policy: WhenUnderutilized
Expire After: Never # 없음
Limits:
Cpu: 100
Template:
Metadata:
Labels:
Env: dev
Team: checkout
Spec:
Node Class Ref:
Name: default
Requirements:
Key: karpenter.k8s.aws/instance-family
Operator: In
Values:
c5
m5
m6i
m6a
r4
c4
Key: kubernetes.io/arch
Operator: In
Values:
amd64
Key: karpenter.sh/capacity-type
Operator: In
Values:
on-demand
spot
Key: kubernetes.io/os
Operator: In
Values:
linux
Taints:
Effect: NoSchedule
Key: dedicated
Value: CheckoutApp
Status:
Resources:
Attachable - Volumes - Aws - Ebs: 39
Cpu: 2
Ephemeral - Storage: 20959212Ki
Memory: 7981952Ki
Pods: 29
Events: <none>
# 구성 정보 확인
kubectl describe ec2nodeclass
Name: default
Namespace:
Labels: argocd.argoproj.io/instance=karpenter
Annotations: karpenter.k8s.aws/ec2nodeclass-hash: 5256777658067331158
karpenter.k8s.aws/ec2nodeclass-hash-version: v2
API Version: karpenter.k8s.aws/v1beta1
Kind: EC2NodeClass
Metadata:
Creation Timestamp: 2025-03-30T05:58:00Z
Finalizers:
karpenter.k8s.aws/termination
Generation: 1
Resource Version: 1857182
UID: e448bee4-cae6-43d9-a3bf-cce39966f9c1
Spec:
Ami Family: AL2
Ami Selector Terms:
Id: ami-0ee947a6f4880da75
Metadata Options:
Http Endpoint: enabled
httpProtocolIPv6: disabled
Http Put Response Hop Limit: 2
Http Tokens: required
Role: karpenter-eksworkshop-eksctl
Security Group Selector Terms:
Tags:
karpenter.sh/discovery: eksworkshop-eksctl
Subnet Selector Terms:
Tags:
karpenter.sh/discovery: eksworkshop-eksctl
Tags:
Intent: apps
Managed - By: karpenter
Team: checkout
Status:
Amis:
Id: ami-0ee947a6f4880da75
Name: amazon-eks-node-1.25-v20250123
Requirements:
Key: kubernetes.io/arch
Operator: In
Values:
amd64
Conditions:
Last Transition Time: 2025-03-30T05:58:01Z
Message:
Reason: Ready
Status: True
Type: Ready
Instance Profile: eksworkshop-eksctl_4067990795380418201
Security Groups:
Id: sg-02c20fac7d05ee8bd
Name: eksworkshop-eksctl-node-20250330053748685300000009
Id: sg-0e679282c4b01346d
Name: eksworkshop-eksctl-cluster-2025033005374871870000000b
Id: sg-0ff5221c9c93d17ce
Name: eks-cluster-sg-eksworkshop-eksctl-1769733817
Subnets:
Id: subnet-00b8866f562019542
Zone: us-west-2b
Zone ID: usw2-az1
Id: subnet-03d62f35a7786e72f
Zone: us-west-2c
Zone ID: usw2-az3
Id: subnet-083e8dff66d967d83
Zone: us-west-2a
Zone ID: usw2-az2
Events: <none>
# 노드 구성 확인
kubectl get nodes -l team=checkout
NAME STATUS ROLES AGE VERSION
ip-10-0-13-94.us-west-2.compute.internal Ready <none> 2d23h v1.25.16-eks-59bf375
파드 수를 늘려서 노드를 늘려 가용성을 보장하는 작업을 진행합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkout
labels:
app.kubernetes.io/created-by: eks-workshop
app.kubernetes.io/type: app
spec:
replicas: 10 # 1 - > 10
..
# 코드 반영
git add apps/checkout/deployment.yaml
git commit -m "scale checkout app"
git push --set-upstream origin main
# 싱크
argocd app sync checkout
# 노드 수 증가
kubectl get nodes -l team=checkout
NAME STATUS ROLES AGE VERSION
ip-10-0-13-94.us-west-2.compute.internal Ready <none> 3d v1.25.16-eks-59bf375
ip-10-0-25-183.us-west-2.compute.internal NotReady <none> 6s v1.25.16-eks-59bf375
AMI 를 검색 후 드리프트로 설정하겠습니다.
aws ssm get-parameter --name /aws/service/eks/optimized-ami/1.26/amazon-linux-2/recommended/image_id \
--region ${AWS_REGION} --query "Parameter.Value" --output text
ami-0685d6ff76087efe1
노드 클래스에서 AMI를 설정하고, 노드 풀에서 노드 변경 수를 지정합니다.
아래 명령어 방식으로 수정하였지만, 원복되었고 ArgoCD를 통해 정상 적용하였습니다.
싱크 작업으로 AMI가 변경된 것으로 확인됩니다.
kubectl edit nodepool
kubectl edit ec2nodeclass
# 위 반영이 안되어 코드 푸쉬 후 싱크
git add apps/karpenter/default-ec2nc.yaml apps/karpenter/default-np.yaml
git commit -m "disruption changes"
git push --set-upstream origin main
argocd app sync karpenter
# 로그 확인
kubectl -n karpenter logs deployment/karpenter -c controller --tail=33
# 노드 버전 확인
kubectl get nodes -l team=checkout
NAME STATUS ROLES AGE VERSION
ip-10-0-15-185.us-west-2.compute.internal Ready <none> 3m11s v1.26.15-eks-1552ad0
ip-10-0-31-160.us-west-2.compute.internal Ready <none> 4m23s v1.26.15-eks-1552ad0
expireAfter: Never 였지만 AMI를 명시적으로 변경하여 노드 그룹이 교체됨을 확인하였습니다.
데이터플레인 3. Fargate
Fargate 는 서버리스 컨테이너 관리 서비스로 사용자가 노드 그룹을 확인할 수 없습니다.
클러스터에서 실행 중인 Fargate 컨트롤러가 Pod를 인식하고 업데이트하며 Fargate에 예약합니다.
AWS Fargate 노드를 업그레이드하려면 K8s 배포를 다시 시작하여 새로운 Pod가 자동으로 최신 Kubernetes 버전에 예약되도록 할 수 있습니다.
# farate 파드 확인
kubectl get pod -A -o wide | grep fargate
assets assets-7ccc84cb4d-ngfjf 1/1 Running 0 3d 10.0.46.241 fargate-ip-10-0-46-241.us-west-2.compute.internal <none> <none>
# 노드 버전 확인
kubectl get node $(kubectl get pods -n assets -o jsonpath='{.items[0].spec.nodeName}') -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
fargate-ip-10-0-46-241.us-west-2.compute.internal Ready <none> 3d v1.25.16-eks-2d5f260 10.0.46.241 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25
# Faragte 파드 재배포
kubectl rollout restart deployment assets -n assets
# 노드 확인
kubectl get node $(kubectl get pods -n assets -o jsonpath='{.items[0].spec.nodeName}') -o wide
Blue/Green 업그레이드(1.26 > 1.30)
Blue-green 클러스터 업그레이드 전략을 사용하면 한 번에 여러 K8s 버전을 건너뛰거나 여러 업그레이드를 하나씩 수행할 수 있습니다.
EKS 클러스터는 이전 클러스터에서 만든 것과 동일한 VPC 내에 만들어집니다.
항목
|
설명
|
네트워크 연결
|
두 클러스터가 같은 VPC에 있어 리소스 간 통신이 원활하고, 워크로드 및 데이터 마이그레이션이 쉬움
|
공유 리소스
|
NAT Gateway, VPN, Direct Connect 등 기존 VPC 리소스를 재사용하여 복잡성과 비용 절감
|
보안 그룹
|
동일한 보안 그룹 규칙을 재사용함으로써 보안 정책을 일관되게 유지 가능
|
서비스 검색
|
AWS Cloud Map 등으로 클러스터 간 서비스 검색이 쉬워짐
|
서브넷 활용도
|
기존 서브넷을 재사용함으로써 네트워크 재설정 없이 자원 할당 가능
|
VPC 피어링
|
피어링된 외부 VPC에 대한 접근 권한을 두 클러스터 모두 유지 가능
|
일관된 DNS
|
Route 53 등 내부 DNS 설정을 일관되게 유지 가능
|
IAM 및 리소스 정책
|
IAM 정책 및 리소스 권한이 동일 VPC 기준으로 설정돼 있어 권한 관리가 단순함
|
ls -lrt eksgreen-terraform/
total 24
-rw-r--r--. 1 ec2-user ec2-user 542 Sep 1 2024 versions.tf
-rw-r--r--. 1 ec2-user ec2-user 15 Sep 1 2024 README.md
-rw-r--r--. 1 ec2-user ec2-user 464 Sep 8 2024 variables.tf
-rw-r--r--. 1 ec2-user ec2-user 4849 Sep 8 2024 addons.tf
-rw-r--r--. 1 ec2-user ec2-user 4010 Sep 8 2024 base.tf
cd eksgreen-terraform
terraform init
terraform plan -var efs_id=$EFS_ID
terraform apply -var efs_id=$EFS_ID
- 테라폼 코드 실행시 EFS 스토리지를 전달하는 이유는 StorageClass 와 StatefulSet 리소스를 생성할 때 해당 값을 사용할 것이므로 해당 EFS 파일 시스템의 ID를 기록해 두어야 합니다.
- 그린 클러스터 구성까지 약 30분정도 소요됩니다.
# 클러스터 확인
eksctl get cluster
NAME REGION EKSCTL CREATED
eksworkshop-eksctl us-west-2 False
eksworkshop-eksctl-gr us-west-2 False
# 클러스터 컨텍스트 등록
aws eks --region ${AWS_REGION} update-kubeconfig --name ${EKS_CLUSTER_NAME} --alias blue && \
kubectl config use-context blue
aws eks --region ${AWS_REGION} update-kubeconfig --name ${EKS_CLUSTER_NAME}-gr --alias green && \
kubectl config use-context green
# 그린 클러스터 노드 확인, 1.30
kubectl get nodes --context green
NAME STATUS ROLES AGE VERSION
ip-10-0-15-131.us-west-2.compute.internal Ready <none> 36m v1.30.9-eks-5d632ec
ip-10-0-17-2.us-west-2.compute.internal Ready <none> 36m v1.30.9-eks-5d632ec
ip-10-0-24-139.us-west-2.compute.internal Ready <none> 36m v1.30.9-eks-5d632ec
ip-10-0-42-2.us-west-2.compute.internal Ready <none> 36m v1.30.9-eks-5d632ec
# 그린 클러스터 배포 패키지 확인
helm list -A --kube-context green
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
argo-cd argocd 1 2025-04-02 06:49:16.963339726 +0000 UTC deployed argo-cd-5.55.0 v2.10.0
aws-efs-csi-driver kube-system 1 2025-04-02 06:49:45.623111902 +0000 UTC deployed aws-efs-csi-driver-2.5.6 1.7.6
aws-load-balancer-controller kube-system 1 2025-04-02 06:49:48.447800098 +0000 UTC deployed aws-load-balancer-controller-1.7.1 v2.7.1
karpenter karpenter 1 2025-04-02 06:49:45.425515154 +0000 UTC deployed karpenter-0.37.0 0.37.0
metrics-server kube-system 1 2025-04-02 06:49:16.948759521 +0000 UTC deployed metrics-server-3.12.0 0.7.0
상태 비저장 워크로드 마이그레이션
상태 비저장 애플리케이션은 클러스터에 영구 데이터를 보관할 필요가 없으므로 업그레이드하는 동안 새 그린 클러스터에 이를 배포하고 트래픽을 라우팅할 수 있습니다.
ArgoCD에 신규 클러스터 대상을 등록하고 배포를 진행하겠습니다.
사용하고 있는 repo는 1.26 AMI가 등록되어 있으므로 1.30 AMI를 확인하여 수정하고 푸쉬하는 과정입니다.
cd ~/environment/eks-gitops-repo
git status
git switch -c green
git branch -a
Switched to a new branch 'green'
* green
main
remotes/origin/HEAD -> origin/main
remotes/origin/main
# AMI 확인
export AL2023_130_AMI=$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/1.30/amazon-linux-2023/x86_64/standard/recommended/image_id --region ${AWS_REGION} --query "Parameter.Value" --output text)
echo $AL2023_130_AMI
ami-08eb2eb81143e2902
cat << EOF > ~/environment/eks-gitops-repo/apps/karpenter/default-ec2nc.yaml
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2023
amiSelectorTerms:
- id: "${AL2023_130_AMI}" # Latest EKS 1.30 AMI
role: karpenter-eksworkshop-eksctl-gr
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: eksworkshop-eksctl-gr
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: eksworkshop-eksctl
tags:
intent: apps
managed-by: karpenter
team: checkout
EOF
또한, pluto 를 통해 버전 API 확인 진행하고 수정합니다.
pluto 는 GitOps 저장소에서 더 이상 사용되지 않는 API 사용을 찾는 데 도움이 되는 유틸리티입니다.
아래 결과 확인시 autoscaling/v2beta2 은 지원되지 않으므로, convert를 통해 API를 전환하도록 하겠습니다.
pluto detect-files -d ~/environment/eks-gitops-repo/
NAME KIND VERSION REPLACEMENT REMOVED DEPRECATED REPL AVAIL
ui HorizontalPodAutoscaler autoscaling/v2beta2 autoscaling/v2 false true false
Want more? Automate Pluto for free with Fairwinds Insights!
🚀 https://fairwinds.com/insights-signup/pluto 🚀
# API 전환
cd ~/environment/eks-gitops-repo/
kubectl convert -f apps/ui/hpa.yaml --output-version autoscaling/v2 -o yaml > apps/ui/tmp.yaml && mv apps/ui/tmp.yaml apps/ui/hpa.yaml
cat apps/ui/hpa.yaml
마지막으로 ArgoCD 애플리케이션이 green 브랜치를 사용하도록 설정하고 그린 브랜치의 yaml들을 그린 클러스터에 배포할 수 있도록 설정하겠습니다.
# 브랜치 설정
sed -i 's/targetRevision: main/targetRevision: green/' app-of-apps/values.yaml
# 브랜치 푸쉬
git add . && git commit -m "1.30 changes"
git push -u origin green
# ARgoCD 정보 지정
export ARGOCD_SERVER_GR=$(kubectl get svc argo-cd-argocd-server -n argocd -o json --context green | jq --raw-output '.status.loadBalancer.ingress[0].hostname')
echo "ArgoCD URL: http://${ARGOCD_SERVER_GR}"
export ARGOCD_USER_GR="admin"
export ARGOCD_PWD_GR=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" --context green | base64 -d)
echo "Username: ${ARGOCD_USER_GR}"
echo "Password: ${ARGOCD_PWD_GR}"
# 로그인
argocd login --name green ${ARGOCD_SERVER_GR} --username ${ARGOCD_USER_GR} --password ${ARGOCD_PWD_GR} --insecure --skip-test-tls --grpc-web
'admin:login' logged in successfully
Context 'green' updated
# 키 반환
argo_creds=$(aws secretsmanager get-secret-value --secret-id argocd-user-creds --query SecretString --output text)
# repo 등록
argocd repo add $(echo $argo_creds | jq -r .url) --username $(echo $argo_creds | jq -r .username) --password $(echo $argo_creds | jq -r .password) --server ${ARGOCD_SERVER_GR}
Repository 'https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo' added
# repo에 등록된 yaml 배포
argocd app create apps --repo $(echo $argo_creds | jq -r .url) --path app-of-apps \
--dest-server https://kubernetes.default.svc --sync-policy automated --revision green --server ${ARGOCD_SERVER_GR}
# 구성 확인
argocd app list --server ${ARGOCD_SERVER_GR}
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/apps https://kubernetes.default.svc default Synced Healthy Auto https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo app-of-apps green
argocd/assets https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/assets green
argocd/carts https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/carts green
argocd/catalog https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/catalog green
argocd/checkout https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/checkout green
argocd/karpenter https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/karpenter green
argocd/orders https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/orders green
argocd/other https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/other green
argocd/rabbitmq https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/rabbitmq green
argocd/ui https://kubernetes.default.svc default Synced Healthy Auto-Prune https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-gitops-repo apps/ui green
구성이 완료되었다면 트래픽 전환이 필요합니다.
트래픽 전환에는 Amazon Route 53의 가중 레코드, AWS Application Load Balancer의 가중 대상 그룹 등 여러 가지 기술을 사용할 수 있습니다.
본 워크샵에서는 Route53 가중 레코드를 통한 이론적 지침만 제공합니다.
Route53 라우팅은 external-DNS annotation을 통해 설정할 수 있습니다.
필자가 테스트한 결과를 공유드리니, 정책 설정 및 카나리 배포에 참고 부탁드립니다.
external-dns.alpha.kubernetes.io/set-identifier: {{ .Values.spec.clusterName }}
external-dns.alpha.kubernetes.io/aws-weight: '{{ .Values.spec.ingress.route53_weight }}'
상태 저장 워크로드 마이그레이션
Kubernetes에서 실행되는 상태 저장 애플리케이션을 위한 영구 저장소를 호스팅하는 데는 Amazon EBS 볼륨이나 클러스터 간에 동기화해야 하는 데이터베이스 컨테이너를 포함하여 다양한 저장소 옵션이 있습니다.
이 워크숍의 단순성을 위해 Amazon EFS 파일 시스템을 사용하지만, 블루 그린 프로세스를 사용하여 상태 저장 애플리케이션을 업그레이드하는 일반적인 개념은 동일합니다.
영구 저장소가 있는 상태 저장 애플리케이션의 업그레이드를 시뮬레이션하려면 다음 단계를 순서대로 따릅니다.
- Blue 클러스터에서 Kubernetes StatefulSet 리소스를 만들고 정적 html 파일을 수동으로 만듭니다. 이 파일은 공유 EFS 파일 시스템에 저장됩니다.
- nginx를 실행하는 포드를 호스팅하고 Blue 포드와 동일한 파일 저장소에 액세스하는 Green 클러스터에서 StatefulSet 리소스를 만듭니다.
- (선택 사항) Blue 클러스터에서 원래 StatefulSet을 삭제합니다.
[1단계] Blue 클러스터 내 EFS 볼륨 기반 nginx 애플리케이션 배포
# 블루 클러스터 컨텍스트 설정
kubectl config use-context blue
# EFS 구성 확인
kubectl get storageclass efs -o yaml
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
creationTimestamp: "2025-03-30T05:54:16Z"
name: efs
resourceVersion: "3908"
uid: 9deecea9-ce8c-4007-a25c-3dbb1ef97ace
mountOptions:
- iam
parameters:
basePath: /dynamic_provisioning
directoryPerms: "755"
ensureUniqueDirectory: "false"
fileSystemId: fs-09c7449db5761f1c3
gidRangeEnd: "200"
gidRangeStart: "100"
provisioningMode: efs-ap
reuseAccessPoint: "false"
subPathPattern: ${.PVC.namespace}/${.PVC.name}
provisioner: efs.csi.aws.com
reclaimPolicy: Delete
volumeBindingMode: Immediate
# StatefulSet 매니패스트 배포
cat <<EOF | kubectl apply -f -
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: efs-example
namespace: default
spec:
serviceName: "efs-example"
replicas: 1
selector:
matchLabels:
app: efs-example
template:
metadata:
labels:
app: efs-example
spec:
containers:
- name: app
image: nginx:latest
volumeMounts:
- name: efs-storage
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: efs-storage
spec:
accessModes: ["ReadWriteMany"]
storageClassName: efs # efs 볼륨 사용 설정
resources:
requests:
storage: 1Gi
EOF
# 상태 저장 볼륨 확인
kubectl exec $(kubectl get pods -o jsonpath='{.items[0].metadata.name}' -l app=efs-example) -- bash -c 'touch /usr/share/nginx/html/index.html'
# 파일 삭제 후 이전 파드 동작 확인
kubectl delete pods -l app=efs-example && \
kubectl exec $(kubectl get pods -o jsonpath='{.items[0].metadata.name}' -l app=efs-example) -- bash -c 'ls -lh /usr/share/nginx/html/index.html'
pod "efs-example-0" deleted
-rw-r--r-- 1 100 users 0 Apr 2 07:55 /usr/share/nginx/html/index.html
[2단계] Green 클러스터 내 StatefulSet 애플리케이션 배포
# 그린 클러스터 컨텍스트 설정
kubectl config use-context green
# 스토리지 클래스 확인, fileSystemID가 동일함
kubectl get storageclass efs -o yaml
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
creationTimestamp: "2025-04-02T06:50:59Z"
name: efs
resourceVersion: "3334"
uid: dfea7abf-3872-4a21-8abd-f45f4ed3ba40
mountOptions:
- iam
parameters:
basePath: /dynamic_provisioning
directoryPerms: "755"
ensureUniqueDirectory: "false"
fileSystemId: fs-09c7449db5761f1c3
gidRangeEnd: "2000"
gidRangeStart: "1000"
provisioningMode: efs-ap
reuseAccessPoint: "false"
subPathPattern: ${.PVC.namespace}/${.PVC.name}
provisioner: efs.csi.aws.com
reclaimPolicy: Delete
# 배포
cat <<EOF | kubectl apply -f -
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: efs-example
namespace: default
spec:
serviceName: "efs-example"
replicas: 1
selector:
matchLabels:
app: efs-example
template:
metadata:
labels:
app: efs-example
spec:
containers:
- name: app
image: nginx:latest
volumeMounts:
- name: efs-storage
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: efs-storage
spec:
accessModes: ["ReadWriteMany"]
storageClassName: efs
resources:
requests:
storage: 1Gi
EOF
# 동작 확인
kubectl exec $(kubectl get pods -o jsonpath='{.items[0].metadata.name}' -l app=efs-example) -- bash -c 'ls -lh /usr/share/nginx/html/index.html'
-rw-r--r-- 1 100 users 0 Apr 2 07:55 /usr/share/nginx/html/index.html
[3단계] 블루 클러스터 내 StatefulSet 애플리케이션 삭제
kubectl delete statefulset efs-example --context blue
위 상태 저장 워크로드는 EFS 스토리지 기반의 시나리오입니다.
EBS 로 동작하는 워크로드인 경우 시나리오에 따라 처리할 수 있도록 합시다.
시나리오
|
처리 방법
|
StatefulSet에서 EBS 사용하는 경우
|
기존 볼륨을 새 클러스터로 이동해야 함
|
임시 볼륨이거나 삭제해도 되는 경우
|
새 클러스터에서 새로 생성하면 됨 (볼륨 복사 불필요)
|
EBS-backed PVC를 그대로 유지하고 싶은 경우
|
EBS Volume을 Detach → Attach 또는 스냅샷 복원 필요
|
'Cloud' 카테고리의 다른 글
EKS 파드로 노드 관리하기 (0) | 2025.04.12 |
---|---|
EKS Fargate & AutoMode (0) | 2025.03.23 |
EKS Security (2) | 2025.03.16 |
EKS Karpenter (0) | 2025.03.09 |
EKS Autoscaling (0) | 2025.03.09 |