-
먼저, 쿠버네티스 업그레이드 이해하기
-
지원 되는 버전
-
업그레이드 시 반드시 고려해야 할 구성 요소들
-
업그레이드 방식
-
Amazon EKS Upgrades
-
무엇이 다를까?
-
Amazon EKS Upgrades Workshop 실습 : In-place Upgrade
-
들어가며
-
컨트롤 플레인(Control Plane) 업그레이드
-
애드온(Addons)
-
데이터플레인(Data Plane)
-
Amazon EKS Upgrades Workshop 실습 : BlueGreen Upgrade
-
들어가며
-
신규 Green EKS 클러스터 생성
-
Stateless Workload Migration
-
Stateful Workload Migration
📌 해당 글은 가시다님의 AEWS 스터디 중, AWS EKS Upgrade Workshop에 대한 실습 정리 글입니다.
실습환경을 제공해주신 최영락 님에게 감사드립니다.
먼저, 쿠버네티스 업그레이드 이해하기
Amazon EKS 업그레이드를 논하기 전에, 먼저 Kubernetes 업그레이드의 기본 개념부터 살펴봅니다.
쿠버네티스는 여러 컴포넌트가 서로 상호작용하는 분산 시스템으로, 단순히 버전만 올리는 작업이 아니라, 구성요소 간의 호환성과 순서를 고려해야 합니다.
지원 되는 버전
- Kubernetes는 가장 최근의 3개 마이너 버전만 공식 패치를 제공합니다.
- 예를 들어 현재 시점 기준으로는
v1.30
v1.31
v1.32
가 패치 대상이며,v1.29
이하의 버전에서는 보안 패치조차 지원되지 않습니다. - 참고로, EKS에서는 지원 기간이 지난 Kubernetes 버전을 계속 사용하는 경우, 추가 요금이 부과됩니다.
업그레이드 시 반드시 고려해야 할 구성 요소들
쿠버네티스 핵심 컴포넌트
- Kubernetes의 핵심 컴포넌트 간 버전 차이를 어느 정도까지 허용하는지 확인 - Version Skew Policy
- 업그레이드를 진행할 때는 Kubernetes 주요 구성요소 간의 버전 호환성을 반드시 검토해야 합니다.
컨테이너 런타임 & CNI
- 클러스터와 호환되는 써드파티들의 버전 확인
- cilium - https://docs.cilium.io/en/stable/network/kubernetes/compatibility/
- conatainerd - https://containerd.io/releases/
업그레이드 방식
Kubernetes 클러스터를 업그레이드하는 방식에는 크게 2가지가 있습니다.
1.In-Place Upgrade
- 기존 클러스터 위에서 직접 버전을 올리는 방식입니다.
- 다운타임을 최소화할 수 있지만, 실수 시 롤백이 어려울 수 있습니다.
- 주요 컴포넌트를 하나씩 업그레이드하며 조심스럽게 진행해야 합니다.
2.Blue-Green Upgrade
- 동일한 신규 클러스터를 구성한 뒤, 워크로드와 트래픽을 점진적으로 전환합니다.
- 무중단 배포가 가능하며, 문제가 생기면 빠르게 이전 상태로 롤백 가능합니다.
- 비용이 크며, 복잡하다는 단점이 있으나, 운영 안정성을 확보할 수 있습니다.
Amazon EKS Upgrades
무엇이 다를까?
Kubernetes 업그레이드는 일반적으로 컨트롤 플레인, 노드, 애드온을 수동으로 업그레이드해야 하는 복잡한 작업입니다.
Amazon EKS는 이를 아래와 같이 단순화해 줍니다.
컨트롤 플레인 자동 관리
컨트롤 플레인은 AWS에서 완전 관리(Managed)되며, 사용자는 버튼 클릭 또는 Terraform 등 IaC 도구를 통해 단일 명령어로 업그레이드 가능합니다.
애드온 버전 제공
각 Kubernetes 버전에 맞는 Addon 버전을 AWS CLI 또는 eksctl로 조회할 수 있어, **호환성 검증이 쉽습니다.
유연한 업그레이드 전략
기존 클러스터에서 점진적 In-place 업그레이드
또는 신규 클러스터로 전환하는 Blue/Green 방식 모두 지원
Amazon EKS는 컨트롤 플레인을 관리해 주기 때문에, 복잡한 업그레이드 과정을 안정적이고 안전하게 운영할 수 있습니다.사용자는 노드 그룹 / 애드온 / 애플리케이션에만 집중하면 됩니다.
Amazon EKS Upgrades Workshop 실습 : In-place Upgrade
들어가며
EKS 역시 쿠버네티스 기반 플랫폼인 만큼, 여러 핵심 컴포넌트들이 유기적으로 연결되어 있어 단계적인 업그레이드 절차가 필요합니다.
AWS 공식 문서에서는 다음과 같은 업그레이드 순서를 권장합니다:
- 컨트롤 플레인 (Control Plane)
- API Server, Controller Manager 등 핵심 K8S 컴포넌트 버전 업그레이드
- 애드온(Addons)
- CoreDNS, kube-proxy, CNI, ALB Controller, Karpenter 등
- 데이터 플레인 (Data Plane)
- 워커 노드 또는 노드 그룹의 업그레이드 (관리형 / 셀프 관리형 노드 포함)
이번 실습에서는 Terraform을 활용하여 In-place 방식으로 EKS 클러스터를 업그레이드하였습니다
- 업그레이드 버전:
1.25
->1.26
- 샘플 애플리케이션을 통한 ArgoCD를 통한 GitOps 패턴을 유지한 채 샘플 애플리케이션도 함께 업그레이드
컨트롤 플레인(Control Plane) 업그레이드
EKS 클러스터의 현재 Kubernetes 버전(1.25)을 AWS 콘솔에서 확인합니다.

variable.tf 파일 수정
- EKS 모듈에서 사용할
cluster_version
변수 값을 변경합니다.

테라폼 배포: Control Plane 업그레이드 실행
# 변경 사항 사전 확인
terraform plan
...
# module.eks_blueprints_addons.data.aws_eks_addon_version.this["aws-ebs-csi-driver"] will be read during apply # (depends on a resource or a module with changes pending) <= data "aws_eks_addon_version" "this" { + addon_name = "aws-ebs-csi-driver" + id = (known after apply) + kubernetes_version = "1.26" + most_recent = true + version = (known after apply) }
# 자동 승인 후 배포 실행
terraform apply -auto-approve




업그레이드 완료 후 상태 확인

Cluster Insight
EKS Insights를 통해 호환성 및 문제점 사전 확인할 수도 있습니다.

컨트롤 플레인 업그레이드 이후 문제 발생 - ArgoCD 에러 해결 - OutofSync
업그레이드 이후, ArgoCD에서 일부 리소스에 OutOfSync 상태가 발생했습니다. 이는 apiVersion이 더 이상 지원되지 않아서 생긴 오류입니다. 뒤에서 다른 방법으로 문제 해결 예정입니다.


애드온(Addons)
EKS 클러스터의 마이너 버전을 올린 후에는, 그에 호환되는 Addon 버전도 함께 업그레이드해야 합니다CoreDNS
, kube-proxy
, VPC CNI
, EBS CSI Driver
등은 클러스터 동작에 필수적인 컴포넌트이기 때문에, 버전 불일치 시, 오류가 발생할 수 있습니다.
아래 명령어로 현재 클러스터의 Addon 버전과 업그레이드 가능한 버전 목록을 확인할 수 있습니다.
# 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::271345173787:role/eksworkshop-eksctl-ebs-csi-driver-2025032502294618580000001d
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
# 쿠버네티스 버전에 따라 호환되는 Addon 상세 정보 확인 - CoreDNS
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 |
+-----------------+----------------------+
addons.tf 파일 수정core-dns
, kube-proxy
업그레이드 할 버전을 명시합니다.

이후 아래 명령으로 변경 사항을 적용합니다:
terraform plan
terraform apply -auto-approve
EKS는 Addon 업그레이드도 Blue/Green 롤링 방식으로 처리합니다. 기존 리소스를 점진적으로 교체하면서 서비스에 영향이 없도록 합니다.

업그레이드 후 버전 확인
업데이트된 컨테이너 이미지 버전은 다음 명령어로 확인할 수 있습니다:
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.9.3-eksbuild.22
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.26.15-minimal-eksbuild.24
업그레이드 결과
• CoreDNS: v1.8.7-eksbuild.10
→ v1.9.3-eksbuild.22
• kube-proxy: v1.25.16-eksbuild.8
→ v1.26.15-eksbuild.24
데이터플레인(Data Plane)
EKS 업그레이드의 마지막 단계는 데이터 플레인(Node Group)입니다. 클러스터 내에서 실제 워크로드를 수행하는 노드들은 다양한 방식으로 구성할 수 있으며, Amazon EKS는 다음과 같은 방식들을 지원합니다.
- 관리형 노드 그룹(Managed Node Group)
- Karpenter 기반의 자동 노드 프로비저닝
- Fargate 기반 서버리스 노드
- 셀프노드(Skip!)
1. 관리형 노드그룹(ASG:Auto Scaling Group)
1.1 신규 관리 노드 그룹 추가(Custom)
variables.tf 작성
새로운 노드 그룹에서 사용할 AMI ID를 명시적으로 지정합니다.
# ami 추가
variable "ami_id" {
description = "EKS AMI ID for node groups"
type = string
default = "ami-0078a0f78fafda978"
}
base.tf 작성
새로운 노드 그룹(Custom)을 명시합니다.

Terraform을 실행하여 새로운 노드 그룹을 배포합니다.
terraform apply -auto-approve
AWS 콘솔 - 신규 Custom 노드 관리 그룹 확인


kubectl get nodes 명령으로 신규 노드들이 잘 등록되었는지 확인합니다.

커스텀 노드도 동일하게, 1.26으로 업그레이드를 진행합니다.

업그레이드는 롤링 방식으로 진행되며, 파드가 축출되고 노드가 교체되는 과정에서 시간이 오래 소요될 수도 있습니다.(약 20분 정도)

Custom 노드 업그레이드 완료

Custom 노드 업그레이드 확인

1.2 관리형 노드그룹 : 블루-그린 업그레이드
이번 단계에서는 기존 노드 그룹(Blue)을 유지한 상태에서 새로운 노드 그룹(Green)을 생성하고, 점진적으로 워크로드를 이전하는 블루-그린 업그레이드 전략을 적용합니다. 이 방식은 다운타임 없이 안정적으로 노드를 교체할 수 있다는 장점이 있습니다.
기존 Blue Node Group은 삭제하고, 새로운 Green Node Group을 Terraform으로 생성합니다.
Green 노드 그룹 생성
base.tf 파일 수정: 노드 그룹(Green)을 정의합니다.

이 노드 그룹은PV(EBS)를사용하는 파드를 위해 반드시 특정 서브넷에 위치해야 합니다. 기존 PV는 프라이빗 서브넷 1에 생성된 EBS 볼륨을 사용 중입니다. 따라서 새로 생성되는 Green 노드 그룹도 module.vpc.private_subnets[0]
고정 배치해야 합니다.
EBS는 AZ(Local Zone) 종속성이 강하기 때문에, 다른 서브넷(AZ)에 위치한 노드에서는 기존 EBS 볼륨을 마운트 할 수 없습니다.
동일한 서브넷에 노드를 위치시키지 않으면 VolumeAttachment 오류가 발생할 수 있습니다.
테라폼 배포 : Green 노드 그룹 생성
terraform apply -auto-approve

Green 노드 확인
# 신규 노드 확인(Green)
kubectl get node -l eks.amazonaws.com/nodegroup=$GREEN_MNG
NAME STATUS ROLES AGE VERSION
ip-10-0-4-73.us-west-2.compute.internal Ready <none> 17h v1.26.15-eks-59bf375
AWS 콘솔 - ASG 확인

기존 Blue 노드 그룹 제거
base.tf 파일 수정
기존(Blue-mng) 관리 노드 그룹을 삭제합니다.

노드 그룹 리소스를 제거하고 다시 apply를 수행합니다
terraform apply -auto-approve
워크로드가 모두 Green 노드로 정상적으로 이전되었는지 확인해야 합니다
- 안정적인 전환을 위해서는 Pod Disruption Budget(PDB) 설정을 통해 동시에 내려갈 수 있는 파드 수를 제어하고,
- replica 수를 일시적으로 늘려 이중화를 강화하면 보다 원활한 롤링 업데이트 및 비상시 롤백이 쉬워집니다.

2. 카펜터(Karpenter)
이번 단계에서는 Karpenter 기반의 동적 노드 프로비저닝 방식에서 노드를 새롭게 교체하고, 애플리케이션이 새로운 노드로 마이그레이션 되도록 구성합니다. 기존 노드는 점진적으로 종료되고, 새로운 노드는 수정된 템플릿(AMI 버전 등)을 기반으로 자동 생성됩니다.
Karpenter는 자체적으로 스케일링과 노드 수명을 조절하므로 비교적 간단하게 노드 업그레이드를 구현할 수 있습니다.
Karpenter 리소스 변경
먼저, Karpenter가 새로운 버전의 AMI를 기준으로 노드를 생성할 수 있도록 EC2 NodeClass와 NodePool 설정을 업데이트합니다.
EC2 NodeClass의 최신 AMI로 amiSelectorTerms를 지정

NodePool의 필요한 만큼 노드를 유지하도록 budget 설정

Drift 감지 및 동기화
ArgoCD를 통해 리소스 변경 사항이 감지되며, 상태가 Drift로 표시됩니다. 이후 Sync 버튼을 눌러 동기화를 수행하면, 기존 노드는 점진적으로 정리되고, 새로운 노드가 자동으로 생성됩니다.
Karpenter 애플리케이션을 Sync 합니다.

Karpenter Pod 상태 확인
# Karpenter Pod 상태 확인
k get pod -n karpenter -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
karpenter-6b746879cb-db5vw 1/1 Running 0 2d 10.0.24.173 ip-10-0-16-77.us-west-2.compute.internal <none> <none>
karpenter-6b746879cb-g8h89 1/1 Running 0 2d 10.0.4.54 ip-10-0-14-97.us-west-2.compute.internal <none> <none>
# 스케줄링된 노드 확인
kubectl get nodes --show-labels | grep karpenter
ip-10-0-42-84.us-west-2.compute.internal Ready <none> 2d v1.25.16-eks-59bf375 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c4.xlarge,beta.kubernetes.io/os=linux,env=dev,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,k8s.io/cloud-provider-aws=a94967527effcefb5f5829f529c0a1b9,karpenter.k8s.aws/instance-category=c,karpenter.k8s.aws/instance-cpu-manufacturer=intel,karpenter.k8s.aws/instance-cpu=4,karpenter.k8s.aws/instance-ebs-bandwidth=750,karpenter.k8s.aws/instance-encryption-in-transit-supported=false,karpenter.k8s.aws/instance-family=c4,karpenter.k8s.aws/instance-generation=4,karpenter.k8s.aws/instance-hypervisor=xen,karpenter.k8s.aws/instance-memory=7680,karpenter.k8s.aws/instance-size=xlarge,karpenter.sh/capacity-type=spot,karpenter.sh/initialized=true,karpenter.sh/nodepool=default,karpenter.sh/registered=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-10-0-42-84.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c4.xlarge,team=checkout,topology.ebs.csi.aws.com/zone=us-west-2c,topology.k8s.aws/zone-id=usw2-az3,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2c
# karpenter 노드에 스케줄링된 애플리케이션 확인(checkout)
k get pod -A -o wide | grep ip-10-0-42-84.us-west-2.compute.internal
checkout checkout-558f7777c-rq7hd 1/1 Running 0 2d 10.0.46.82 ip-10-0-42-84.us-west-2.compute.internal <none> <none>
checkout checkout-redis-f54bf7cb5-84l44 1/1 Running 0 2d 10.0.40.168 ip-10-0-42-84.us-west-2.compute.internal <none> <none>
노드 교체 완료 후 상태 확인
NodePool에 지정한 스펙대로 새로운 노드들이 생성되고, 기존 노드에서 실행 중이던 파드들도 문제없이 마이그레이션 되었습니다.
kubectl get pod -n checkout -owide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
checkout-558f7777c-4cbwx 1/1 Running 0 2m48s 10.0.37.170 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-72tq9 1/1 Running 0 2m49s 10.0.42.203 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-gr5k8 1/1 Running 0 2m48s 10.0.32.144 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-m7v7w 1/1 Running 0 2m48s 10.0.35.39 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-mbn29 1/1 Running 0 2m49s 10.0.39.43 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-qsbww 1/1 Running 0 2m48s 10.0.34.246 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-t22mb 1/1 Running 0 2m49s 10.0.36.194 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-vzl2h 1/1 Running 0 2m48s 10.0.33.180 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-wjcn5 1/1 Running 0 2m48s 10.0.35.238 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-wsxw4 1/1 Running 0 2m48s 10.0.35.236 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-redis-f54bf7cb5-dtpvh 1/1 Running 0 2m49s <none> ip-10-0-34-121.us-west-2.compute.internal <none> <none>
새 노드에 안정적으로 파드가 재스케줄되고, 모든 컨테이너가 정상 작동(Running) 상태임을 확인할 수 있었습니다.
카펜터는 설정만 잘해두면 노드 업그레이드를 매우 유연하고 자동화된 방식으로 처리할 수 있어, 특히 자주 노드 사양을 변경해야 하는 환경에서 매우 유용합니다.
3. 파게이트(Fargate)
EKS에서 Fargate 프로파일을 사용하는 경우, 노드 업그레이드 방식은 다소 단순합니다. Fargate는 AWS가 완전히 관리하는 서버리스 실행 환경이기 때문에, 별도의 노드 그룹 설정이나 AMI 업데이트가 필요하지 않습니다.
Fargate의 버전은 새로 Pod이 생성되는 시점에 최신 버전의 런타임 환경으로 자동 프로비저닝되기 때문에, 디플로이먼트를 재시작하는 것만으로도 업그레이드가 가능합니다.
kubectl rollout restart deployment assets -n assets
노드 버전 확인 (업그레이드 전 → 후)
업그레이드 전, 기존 Fargate 노드의 쿠버네티스 버전을 확인해 보면 다음과 같습니다:
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-19-187.us-west-2.compute.internal Ready <none> 29h v1.25.16-eks-2d5f260 10.0.19.187 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25
kubectl rollout restart deployment assets -n assets
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-22-34.us-west-2.compute.internal Ready <none> 43s v1.26.15-eks-2d5f260 10.0.22.34 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25
최종 확인(전체 데이터플레인)
이렇게 모든 노드가 업그레이드된 클러스터 내에서 원하는 버전과 상태로 정상 동작하고 있음을 확인했다면, EKS 데이터플레인 업그레이드 성공적으로 완료!
모든 노드 상태 및 버전 확인**
#
kubectl get node
NAME STATUS ROLES AGE VERSION
fargate-ip-10-0-20-30.us-west-2.compute.internal Ready <none> 12m v1.26.15-eks-2d5f260
ip-10-0-19-132.us-west-2.compute.internal Ready <none> 11h v1.26.15-eks-59bf375
ip-10-0-3-241.us-west-2.compute.internal Ready <none> 14m v1.26.15-eks-59bf375
ip-10-0-33-62.us-west-2.compute.internal Ready <none> 3m21s v1.26.15-eks-1552ad0
ip-10-0-33-7.us-west-2.compute.internal Ready <none> 11h v1.26.15-eks-59bf375
ip-10-0-43-67.us-west-2.compute.internal Ready <none> 8m49s v1.26.15-eks-59bf375
ip-10-0-5-91.us-west-2.compute.internal Ready <none> 2m1s v1.26.15-eks-1552ad0
ip-10-0-6-214.us-west-2.compute.internal Ready <none> 36m v1.26.15-eks-59bf375
ip-10-0-7-148.us-west-2.compute.internal Ready <none> 10h v1.26.15-eks-59bf375
#
aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --output table
#
kubectl get node --label-columns=eks.amazonaws.com/capacityType,node.kubernetes.io/lifecycle,karpenter.sh/capacity-type,eks.amazonaws.com/compute-type
kubectl get node -L eks.amazonaws.com/nodegroup,karpenter.sh/nodepool
kubectl get node --label-columns=node.kubernetes.io/instance-type,kubernetes.io/arch,kubernetes.io/os,topology.kubernetes.io/zone
Amazon EKS Upgrades Workshop 실습 : BlueGreen Upgrade
들어가며
이번 실습에서는 기존 EKS 클러스터(Blue)를 유지한 상태에서, 신규 Green 클러스터를 생성하고 워크로드를 점진적으로 이전하는 Blue/Green 방식의 마이그레이션 전략을 다룹니다
신규 Green 클러스터를 1.30
버전 생성하여, In-place 업그레이드처럼 마이너 버전마다 단계적으로 올릴 필요 없이 한 번에 최신 버전으로 마이그레이션이 가능합니다.
신규 Green EKS 클러스터 생성
Terraform 코드 구조 확인
새로운 클러스터 구성 파일은 eksgreen-terraform 디렉터리에 포함되어 있으며, 아래와 같은 파일 구성으로 되어 있습니다:
cd ~/environment
unzip eksgreen.zip
eksgreen-terraform/
├── README.md
├── addons.tf # ArgoCD, EFS 등 애드온 구성
├── base.tf # EKS 클러스터 및 노드그룹 기본 설정
├── variables.tf # 입력 변수 정의
└── versions.tf # provider 버전 고정
ArgoCD 구성
Green 클러스터 역시 GitOps 기반으로 관리되기 때문에, addons.tf에서 ArgoCD 애드온 모듈을 설정해 자동 배포합니다.
Cluster Bootstrapping을 하기 위한 ArgoCD는 eks_blueprints의 addon을 통해 배포가 된다.
# addons.tf
module "eks_blueprints_addons" {
...
// ArgoCD 추가
argocd = {
set = [
{
name = "server.service.type"
value = "LoadBalancer"
}
]
wait = true
}
Green 클러스터 생성 실행
# 테라폼 배포
cd eksgreen-terraform
terraform init
terraform plan -var efs_id=$EFS_ID
terraform apply -var efs_id=$EFS_ID -auto-approve
AWS 콘솔 - Green 클러스터 확인

• ArgoCD Pod 상태 확인:
ec2-user:~/environment/eksgreen-terraform:$ kubectl get pod -n argocd
NAME READY STATUS RESTARTS AGE
argo-cd-argocd-application-controller-0 1/1 Running 0 18h
argo-cd-argocd-applicationset-controller-7b556db7d4-5g258 1/1 Running 0 18h
argo-cd-argocd-dex-server-86bddbd757-6jlqm 1/1 Running 0 18h
argo-cd-argocd-notifications-controller-7fff4884b6-rhmmf 1/1 Running 0 18h
argo-cd-argocd-redis-6d4d8d884-szj7v 1/1 Running 0 18h
argo-cd-argocd-repo-server-64cbf54678-6gx5m 1/1 Running 0 18h
argo-cd-argocd-server-575cdd9494-79jz6 1/1 Running 0 18h
Stateless Workload Migration
Stateless 애플리케이션은 영구적인 데이터 저장소에 의존하지 않기 때문에, Blue → Green 클러스터 간 마이그레이션이 비교적 간단합니다.
기존과 동일한 설정으로 Green 클러스터에 배포하고 트래픽만 전환하면 되기 때문에 마이그레이션의 첫 단계로 적합합니다.
GitOps 기반 배포 준비(Repository Setup)
ArgoCD를 활용해 GitOps 방식으로 애플리케이션을 관리하고 있다면, 레포지토리의 브랜치만 전환해도 배포 대상 클러스터를 유연하게 바꿀 수 있습니다.
# Green 브랜치 생성 및 전환
git switch -c green
git branch -a
* green
EC2 NodeClass 업데이트 (Karpenter)
Green 클러스터 환경에 맞게 AMI ID, IAM 역할, 보안 그룹, 서브넷 등 설정을 새롭게 구성해야 합니다.
# 최신 Amazon Linux 2023 기반 AMI 조회 (예: EKS 1.30)
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
default-ec2 nc.yaml 파일을 생성하고 Green 클러스터 설정에 맞게 작성합니다.
# 업데이트
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
⚠️ 마이그레이션 전 Deprecated 리소스 점검
Green 클러스터는 EKS 1.30 이상으로 설정되어 있으므로, 기존 애플리케이션이 사용하던 deprecated 된 K8S 리소스 버전이 호환되지 않을 수 있습니다. ( 컨트롤 플레인 업그레이드 이후, 발생한 API 호환 문제 해결 )

pluto 명령어를 사용하면 deprecated 버전을 확인할 수 있습니다. 쿠버네티스 API 버전이 올라감에 따라 HPA의 apiVersion은 v2beta2
-> v2
변경필요.

🤔 pluto vs kubectl convert
kubectl convert
- krew 플러그인으로, kubectl convert로 최신 API 버전으로 변환해 주는 도구(변환)
pluto
- deprecated 리소스를 감지하는 도구(검사)
브랜치 반영 및 Sync
Green 클러스터로의 배포를 위해, ArgoCD App of Apps 설정 파일에서 브랜치를 green으로 전환합니다.
# App of Apps 설정 변경
sed -i 's/targetRevision: main/targetRevision: green/' app-of-apps/values.yaml
# 변경 사항 커밋 및 푸시
git add .
git commit -m "1.30 compatible changes"
git push -u origin green
이후 ArgoCD에서 Sync 버튼을 누르거나 자동 동기화를 통해 Green 클러스터에 애플리케이션이 정상적으로 배포되는 것을 확인할 수 있습니다.

Stateful Workload Migration
Statefulset은 영구 데이터를 보존해야 하는 워크로드로, 업그레이드 시 더 세심한 마이그레이션 전략이 필요합니다.
이번 실습에서는 Amazon EFS를 활용한 Nginx(StatefulSet)을 기존 클러스터(Blue)에서 신규 클러스터(Green)로 데이터를 유지한 채 마이그레이션 해보겠습니다.

Step 1. Blue 클러스터에 StatefulSet 배포
먼저, Blue 클러스터에 EFS 기반의 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
resources:
requests:
storage: 1Gi
EOF
# 리소스 확인
ec2-user:~/environment/eks-gitops-repo:$ kubectl get sts,pvc
NAME READY AGE
statefulset.apps/efs-example 1/1 38s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/efs-storage-efs-example-0 Bound pvc-3b5e8a18-451e-4e48-b18c-af44bd5fe907 1Gi RWX efs 38s
EFS CSI 드라이버에 의해 자동으로 PersistentVolumeClaim (PVC) 이 바인딩되고, efs 스토리지 클래스가 적용됩니다
efs
스토리지 클래스 확인 -> fileSystemId


Step 2. EFS에 파일 생성 및 데이터 보존 테스트
# nginx 디렉토리에 index.html 생성
kubectl exec -it <efs-example-pod> -- bash -c 'echo "aews study 9w end!" > /usr/share/nginx/html/index.html'
이후 파드를 삭제한 뒤 재생성되는 파드에서도 데이터가 유지되는지 확인합니다.
kubectl delete pod -l app=efs-example
kubectl exec -it <efs-example-pod> -- cat /usr/share/nginx/html/index.html
# 출력: aews study 9w end!
Step 3. Green 클러스터에 동일 StatefulSet 배포
이제 Green 클러스터에서도 동일한 이름과 네임스페이스로 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
resources:
requests:
storage: 1Gi
EOF
EFS는 다중 클러스터에서 공유 가능하기 때문에, Green 클러스터에서도 Blue에서 만든 파일이 보여야 합니다.
kubectl apply -f efs-example-statefulset.yaml
kubectl exec -it <efs-example-pod> -- cat /usr/share/nginx/html/index.html
# 출력: aews study 9w end!
📌 실제로는 같은 EFS의 경로를 다른 클러스터에서 동시에 참조하고 있으며, 이는 EFS CSI Driver가 자동으로 액세스 포인트를 생성하여 처리합니다.
액세스 포인트 구조 분석
EFS 내부를 확인하면 다음과 같은 경로로 접근되고 있음을 알 수 있습니다:
/dynamic_provisioning/{namespace}/{pvc-name}
# 예시
/dynamic_provisioning/default/efs-storage-efs-example-0 ← Blue/Green 동일 PVC
/dynamic_provisioning/test/efs-storage-efs-example-0 ← 서로 다른 네임스페이스일 경우
즉, 네임스페이스 및 파드 이름이 같을 경우 동일한 위치에 접근하게 됩니다.

네임스페이스가 다르거나, PVC 명이 다르면 다른 위치가 생성되어 파일이 보이지 않을 수 있습니다.

액세스 포인트의 경로가 달라져, 파일이 존재하지 않는 것을 확인할 수 있습니다.
# 확인
k exec -it -n test efs-example-0 -- ls /usr/share/nginx/html
.
# index.html 파일이 존재하지 않는 응답
ec2-user:~/environment/eksgreen-terraform:$ k exec -it -n test efs-example-0 -- curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.4</center>
</body>
</html>
🚫 POSIX 권한 이슈
EFS는 NFS 기반 스토리지이므로, POSIX 권한체계를 따릅니다.
POSIX(Portable Operating System Interface for UNIX)
유닉스(리눅스)에서 파일 시스템, 권한, 사용자 관리 등 OS 수준의 표준 Amazon EKS는 NFS 기반으로 동작하기 때문에 Linux처럼 POSIX 방식의 UID/GID/Permission 체계를 따름
즉, 최초 PVC를 생성한 클러스터(예: Blue)에서 파일을 생성하면, 해당 UID/GID 권한으로 마운트 됩니다.

PV의 volueHandler
의 액세스 포인트 ID가 매핑되어 습니다. EFS CSI Driver에 의해 매핑되며 해당 PV를 파드가 볼륨으로 사용하는 것으로 보입니다.
ec2-user:~/environment/eksgreen-terraform:$ k get pv pvc-fe8520ff-c1d5-4f4a-a3d9-a3257e4c133e -o yaml | grep -i 'fsap-'
volumeHandle: fs-0a54fe6e0528b1fc1::fsap-0cd0984aaae23a3b8
첫 생성된 스토리지의 주체(blue)에서만 write가 되고, 이후 스토리지를 공유하는 파드(green)에서는 write 권한이 차단됩니다.
# blue 파드(초기 생성 주체)
root@efs-example-0:/usr/share/nginx/html# touch a
root@efs-example-0:/usr/share/nginx/html# ls
a index.html
# green 파드
root@efs-example-0:/usr/share/nginx/html# touch b
touch: cannot touch 'b': Permission denied
# green 파드 재확인 시, 스토리지 공유 동작 확인.
root@efs-example-0:/usr/share/nginx/html# ls
a index.html
이는 EFS에 저장된 파일들이 특정 UID (예: 100) 사용자만 쓰기 권한을 가지고 있기 때문입니다.
⚠️ 중요: Amazon EFS에서는 특정 파드가 마운트 한 access point 기준으로 UID/GID 권한이 부여되며, 이를 명시적으로 지정하지 않으면 root가 아닌 사용자로 접근할 수 없습니다.

데이터 마이그레이션 완료 후 Blue 클러스터 리소스 제거
모든 데이터 동기화가 확인되면 Blue 클러스터의 스테이트 풀셋을 삭제
kubectl delete statefulset efs-example --context blue
'AWS > EKS' 카테고리의 다른 글
EKS 서버리스 서비스 간략히 알아보기(Fargate & EKS AutoMode) (0) | 2025.03.23 |
---|---|
EKS Karpenter 기본 사용(Node AutoScaling) (1) | 2025.03.05 |
EKS 기본 스토리지(EBS + EFS CSI Driver, Instance Store) (0) | 2025.02.23 |
EKS 기본 네트워크(AWS VPC CNI + AWS LoadBalancer Controller) (0) | 2025.02.16 |
EKS 설치 및 클러스터 엔드포인트(EKS Cluster Endpoint) (2) | 2025.02.09 |
📌 해당 글은 가시다님의 AEWS 스터디 중, AWS EKS Upgrade Workshop에 대한 실습 정리 글입니다.
실습환경을 제공해주신 최영락 님에게 감사드립니다.
먼저, 쿠버네티스 업그레이드 이해하기
Amazon EKS 업그레이드를 논하기 전에, 먼저 Kubernetes 업그레이드의 기본 개념부터 살펴봅니다.
쿠버네티스는 여러 컴포넌트가 서로 상호작용하는 분산 시스템으로, 단순히 버전만 올리는 작업이 아니라, 구성요소 간의 호환성과 순서를 고려해야 합니다.
지원 되는 버전
- Kubernetes는 가장 최근의 3개 마이너 버전만 공식 패치를 제공합니다.
- 예를 들어 현재 시점 기준으로는
v1.30
v1.31
v1.32
가 패치 대상이며,v1.29
이하의 버전에서는 보안 패치조차 지원되지 않습니다. - 참고로, EKS에서는 지원 기간이 지난 Kubernetes 버전을 계속 사용하는 경우, 추가 요금이 부과됩니다.
업그레이드 시 반드시 고려해야 할 구성 요소들
쿠버네티스 핵심 컴포넌트
- Kubernetes의 핵심 컴포넌트 간 버전 차이를 어느 정도까지 허용하는지 확인 - Version Skew Policy
- 업그레이드를 진행할 때는 Kubernetes 주요 구성요소 간의 버전 호환성을 반드시 검토해야 합니다.
컨테이너 런타임 & CNI
- 클러스터와 호환되는 써드파티들의 버전 확인
- cilium - https://docs.cilium.io/en/stable/network/kubernetes/compatibility/
- conatainerd - https://containerd.io/releases/
업그레이드 방식
Kubernetes 클러스터를 업그레이드하는 방식에는 크게 2가지가 있습니다.
1.In-Place Upgrade
- 기존 클러스터 위에서 직접 버전을 올리는 방식입니다.
- 다운타임을 최소화할 수 있지만, 실수 시 롤백이 어려울 수 있습니다.
- 주요 컴포넌트를 하나씩 업그레이드하며 조심스럽게 진행해야 합니다.
2.Blue-Green Upgrade
- 동일한 신규 클러스터를 구성한 뒤, 워크로드와 트래픽을 점진적으로 전환합니다.
- 무중단 배포가 가능하며, 문제가 생기면 빠르게 이전 상태로 롤백 가능합니다.
- 비용이 크며, 복잡하다는 단점이 있으나, 운영 안정성을 확보할 수 있습니다.
Amazon EKS Upgrades
무엇이 다를까?
Kubernetes 업그레이드는 일반적으로 컨트롤 플레인, 노드, 애드온을 수동으로 업그레이드해야 하는 복잡한 작업입니다.
Amazon EKS는 이를 아래와 같이 단순화해 줍니다.
컨트롤 플레인 자동 관리
컨트롤 플레인은 AWS에서 완전 관리(Managed)되며, 사용자는 버튼 클릭 또는 Terraform 등 IaC 도구를 통해 단일 명령어로 업그레이드 가능합니다.
애드온 버전 제공
각 Kubernetes 버전에 맞는 Addon 버전을 AWS CLI 또는 eksctl로 조회할 수 있어, **호환성 검증이 쉽습니다.
유연한 업그레이드 전략
기존 클러스터에서 점진적 In-place 업그레이드
또는 신규 클러스터로 전환하는 Blue/Green 방식 모두 지원
Amazon EKS는 컨트롤 플레인을 관리해 주기 때문에, 복잡한 업그레이드 과정을 안정적이고 안전하게 운영할 수 있습니다.사용자는 노드 그룹 / 애드온 / 애플리케이션에만 집중하면 됩니다.
Amazon EKS Upgrades Workshop 실습 : In-place Upgrade
들어가며
EKS 역시 쿠버네티스 기반 플랫폼인 만큼, 여러 핵심 컴포넌트들이 유기적으로 연결되어 있어 단계적인 업그레이드 절차가 필요합니다.
AWS 공식 문서에서는 다음과 같은 업그레이드 순서를 권장합니다:
- 컨트롤 플레인 (Control Plane)
- API Server, Controller Manager 등 핵심 K8S 컴포넌트 버전 업그레이드
- 애드온(Addons)
- CoreDNS, kube-proxy, CNI, ALB Controller, Karpenter 등
- 데이터 플레인 (Data Plane)
- 워커 노드 또는 노드 그룹의 업그레이드 (관리형 / 셀프 관리형 노드 포함)
이번 실습에서는 Terraform을 활용하여 In-place 방식으로 EKS 클러스터를 업그레이드하였습니다
- 업그레이드 버전:
1.25
->1.26
- 샘플 애플리케이션을 통한 ArgoCD를 통한 GitOps 패턴을 유지한 채 샘플 애플리케이션도 함께 업그레이드
컨트롤 플레인(Control Plane) 업그레이드
EKS 클러스터의 현재 Kubernetes 버전(1.25)을 AWS 콘솔에서 확인합니다.

variable.tf 파일 수정
- EKS 모듈에서 사용할
cluster_version
변수 값을 변경합니다.

테라폼 배포: Control Plane 업그레이드 실행
# 변경 사항 사전 확인
terraform plan
...
# module.eks_blueprints_addons.data.aws_eks_addon_version.this["aws-ebs-csi-driver"] will be read during apply # (depends on a resource or a module with changes pending) <= data "aws_eks_addon_version" "this" { + addon_name = "aws-ebs-csi-driver" + id = (known after apply) + kubernetes_version = "1.26" + most_recent = true + version = (known after apply) }
# 자동 승인 후 배포 실행
terraform apply -auto-approve




업그레이드 완료 후 상태 확인

Cluster Insight
EKS Insights를 통해 호환성 및 문제점 사전 확인할 수도 있습니다.

컨트롤 플레인 업그레이드 이후 문제 발생 - ArgoCD 에러 해결 - OutofSync
업그레이드 이후, ArgoCD에서 일부 리소스에 OutOfSync 상태가 발생했습니다. 이는 apiVersion이 더 이상 지원되지 않아서 생긴 오류입니다. 뒤에서 다른 방법으로 문제 해결 예정입니다.


애드온(Addons)
EKS 클러스터의 마이너 버전을 올린 후에는, 그에 호환되는 Addon 버전도 함께 업그레이드해야 합니다CoreDNS
, kube-proxy
, VPC CNI
, EBS CSI Driver
등은 클러스터 동작에 필수적인 컴포넌트이기 때문에, 버전 불일치 시, 오류가 발생할 수 있습니다.
아래 명령어로 현재 클러스터의 Addon 버전과 업그레이드 가능한 버전 목록을 확인할 수 있습니다.
# 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::271345173787:role/eksworkshop-eksctl-ebs-csi-driver-2025032502294618580000001d
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
# 쿠버네티스 버전에 따라 호환되는 Addon 상세 정보 확인 - CoreDNS
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 |
+-----------------+----------------------+
addons.tf 파일 수정core-dns
, kube-proxy
업그레이드 할 버전을 명시합니다.

이후 아래 명령으로 변경 사항을 적용합니다:
terraform plan
terraform apply -auto-approve
EKS는 Addon 업그레이드도 Blue/Green 롤링 방식으로 처리합니다. 기존 리소스를 점진적으로 교체하면서 서비스에 영향이 없도록 합니다.

업그레이드 후 버전 확인
업데이트된 컨테이너 이미지 버전은 다음 명령어로 확인할 수 있습니다:
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
2 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.9.3-eksbuild.22
6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.26.15-minimal-eksbuild.24
업그레이드 결과
• CoreDNS: v1.8.7-eksbuild.10
→ v1.9.3-eksbuild.22
• kube-proxy: v1.25.16-eksbuild.8
→ v1.26.15-eksbuild.24
데이터플레인(Data Plane)
EKS 업그레이드의 마지막 단계는 데이터 플레인(Node Group)입니다. 클러스터 내에서 실제 워크로드를 수행하는 노드들은 다양한 방식으로 구성할 수 있으며, Amazon EKS는 다음과 같은 방식들을 지원합니다.
- 관리형 노드 그룹(Managed Node Group)
- Karpenter 기반의 자동 노드 프로비저닝
- Fargate 기반 서버리스 노드
- 셀프노드(Skip!)
1. 관리형 노드그룹(ASG:Auto Scaling Group)
1.1 신규 관리 노드 그룹 추가(Custom)
variables.tf 작성
새로운 노드 그룹에서 사용할 AMI ID를 명시적으로 지정합니다.
# ami 추가
variable "ami_id" {
description = "EKS AMI ID for node groups"
type = string
default = "ami-0078a0f78fafda978"
}
base.tf 작성
새로운 노드 그룹(Custom)을 명시합니다.

Terraform을 실행하여 새로운 노드 그룹을 배포합니다.
terraform apply -auto-approve
AWS 콘솔 - 신규 Custom 노드 관리 그룹 확인


kubectl get nodes 명령으로 신규 노드들이 잘 등록되었는지 확인합니다.

커스텀 노드도 동일하게, 1.26으로 업그레이드를 진행합니다.

업그레이드는 롤링 방식으로 진행되며, 파드가 축출되고 노드가 교체되는 과정에서 시간이 오래 소요될 수도 있습니다.(약 20분 정도)

Custom 노드 업그레이드 완료

Custom 노드 업그레이드 확인

1.2 관리형 노드그룹 : 블루-그린 업그레이드
이번 단계에서는 기존 노드 그룹(Blue)을 유지한 상태에서 새로운 노드 그룹(Green)을 생성하고, 점진적으로 워크로드를 이전하는 블루-그린 업그레이드 전략을 적용합니다. 이 방식은 다운타임 없이 안정적으로 노드를 교체할 수 있다는 장점이 있습니다.
기존 Blue Node Group은 삭제하고, 새로운 Green Node Group을 Terraform으로 생성합니다.
Green 노드 그룹 생성
base.tf 파일 수정: 노드 그룹(Green)을 정의합니다.

이 노드 그룹은PV(EBS)를사용하는 파드를 위해 반드시 특정 서브넷에 위치해야 합니다. 기존 PV는 프라이빗 서브넷 1에 생성된 EBS 볼륨을 사용 중입니다. 따라서 새로 생성되는 Green 노드 그룹도 module.vpc.private_subnets[0]
고정 배치해야 합니다.
EBS는 AZ(Local Zone) 종속성이 강하기 때문에, 다른 서브넷(AZ)에 위치한 노드에서는 기존 EBS 볼륨을 마운트 할 수 없습니다.
동일한 서브넷에 노드를 위치시키지 않으면 VolumeAttachment 오류가 발생할 수 있습니다.
테라폼 배포 : Green 노드 그룹 생성
terraform apply -auto-approve

Green 노드 확인
# 신규 노드 확인(Green)
kubectl get node -l eks.amazonaws.com/nodegroup=$GREEN_MNG
NAME STATUS ROLES AGE VERSION
ip-10-0-4-73.us-west-2.compute.internal Ready <none> 17h v1.26.15-eks-59bf375
AWS 콘솔 - ASG 확인

기존 Blue 노드 그룹 제거
base.tf 파일 수정
기존(Blue-mng) 관리 노드 그룹을 삭제합니다.

노드 그룹 리소스를 제거하고 다시 apply를 수행합니다
terraform apply -auto-approve
워크로드가 모두 Green 노드로 정상적으로 이전되었는지 확인해야 합니다
- 안정적인 전환을 위해서는 Pod Disruption Budget(PDB) 설정을 통해 동시에 내려갈 수 있는 파드 수를 제어하고,
- replica 수를 일시적으로 늘려 이중화를 강화하면 보다 원활한 롤링 업데이트 및 비상시 롤백이 쉬워집니다.

2. 카펜터(Karpenter)
이번 단계에서는 Karpenter 기반의 동적 노드 프로비저닝 방식에서 노드를 새롭게 교체하고, 애플리케이션이 새로운 노드로 마이그레이션 되도록 구성합니다. 기존 노드는 점진적으로 종료되고, 새로운 노드는 수정된 템플릿(AMI 버전 등)을 기반으로 자동 생성됩니다.
Karpenter는 자체적으로 스케일링과 노드 수명을 조절하므로 비교적 간단하게 노드 업그레이드를 구현할 수 있습니다.
Karpenter 리소스 변경
먼저, Karpenter가 새로운 버전의 AMI를 기준으로 노드를 생성할 수 있도록 EC2 NodeClass와 NodePool 설정을 업데이트합니다.
EC2 NodeClass의 최신 AMI로 amiSelectorTerms를 지정

NodePool의 필요한 만큼 노드를 유지하도록 budget 설정

Drift 감지 및 동기화
ArgoCD를 통해 리소스 변경 사항이 감지되며, 상태가 Drift로 표시됩니다. 이후 Sync 버튼을 눌러 동기화를 수행하면, 기존 노드는 점진적으로 정리되고, 새로운 노드가 자동으로 생성됩니다.
Karpenter 애플리케이션을 Sync 합니다.

Karpenter Pod 상태 확인
# Karpenter Pod 상태 확인
k get pod -n karpenter -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
karpenter-6b746879cb-db5vw 1/1 Running 0 2d 10.0.24.173 ip-10-0-16-77.us-west-2.compute.internal <none> <none>
karpenter-6b746879cb-g8h89 1/1 Running 0 2d 10.0.4.54 ip-10-0-14-97.us-west-2.compute.internal <none> <none>
# 스케줄링된 노드 확인
kubectl get nodes --show-labels | grep karpenter
ip-10-0-42-84.us-west-2.compute.internal Ready <none> 2d v1.25.16-eks-59bf375 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c4.xlarge,beta.kubernetes.io/os=linux,env=dev,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,k8s.io/cloud-provider-aws=a94967527effcefb5f5829f529c0a1b9,karpenter.k8s.aws/instance-category=c,karpenter.k8s.aws/instance-cpu-manufacturer=intel,karpenter.k8s.aws/instance-cpu=4,karpenter.k8s.aws/instance-ebs-bandwidth=750,karpenter.k8s.aws/instance-encryption-in-transit-supported=false,karpenter.k8s.aws/instance-family=c4,karpenter.k8s.aws/instance-generation=4,karpenter.k8s.aws/instance-hypervisor=xen,karpenter.k8s.aws/instance-memory=7680,karpenter.k8s.aws/instance-size=xlarge,karpenter.sh/capacity-type=spot,karpenter.sh/initialized=true,karpenter.sh/nodepool=default,karpenter.sh/registered=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-10-0-42-84.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c4.xlarge,team=checkout,topology.ebs.csi.aws.com/zone=us-west-2c,topology.k8s.aws/zone-id=usw2-az3,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2c
# karpenter 노드에 스케줄링된 애플리케이션 확인(checkout)
k get pod -A -o wide | grep ip-10-0-42-84.us-west-2.compute.internal
checkout checkout-558f7777c-rq7hd 1/1 Running 0 2d 10.0.46.82 ip-10-0-42-84.us-west-2.compute.internal <none> <none>
checkout checkout-redis-f54bf7cb5-84l44 1/1 Running 0 2d 10.0.40.168 ip-10-0-42-84.us-west-2.compute.internal <none> <none>
노드 교체 완료 후 상태 확인
NodePool에 지정한 스펙대로 새로운 노드들이 생성되고, 기존 노드에서 실행 중이던 파드들도 문제없이 마이그레이션 되었습니다.
kubectl get pod -n checkout -owide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
checkout-558f7777c-4cbwx 1/1 Running 0 2m48s 10.0.37.170 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-72tq9 1/1 Running 0 2m49s 10.0.42.203 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-gr5k8 1/1 Running 0 2m48s 10.0.32.144 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-m7v7w 1/1 Running 0 2m48s 10.0.35.39 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-mbn29 1/1 Running 0 2m49s 10.0.39.43 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-qsbww 1/1 Running 0 2m48s 10.0.34.246 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-t22mb 1/1 Running 0 2m49s 10.0.36.194 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-vzl2h 1/1 Running 0 2m48s 10.0.33.180 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-wjcn5 1/1 Running 0 2m48s 10.0.35.238 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-558f7777c-wsxw4 1/1 Running 0 2m48s 10.0.35.236 ip-10-0-34-121.us-west-2.compute.internal <none> <none>
checkout-redis-f54bf7cb5-dtpvh 1/1 Running 0 2m49s <none> ip-10-0-34-121.us-west-2.compute.internal <none> <none>
새 노드에 안정적으로 파드가 재스케줄되고, 모든 컨테이너가 정상 작동(Running) 상태임을 확인할 수 있었습니다.
카펜터는 설정만 잘해두면 노드 업그레이드를 매우 유연하고 자동화된 방식으로 처리할 수 있어, 특히 자주 노드 사양을 변경해야 하는 환경에서 매우 유용합니다.
3. 파게이트(Fargate)
EKS에서 Fargate 프로파일을 사용하는 경우, 노드 업그레이드 방식은 다소 단순합니다. Fargate는 AWS가 완전히 관리하는 서버리스 실행 환경이기 때문에, 별도의 노드 그룹 설정이나 AMI 업데이트가 필요하지 않습니다.
Fargate의 버전은 새로 Pod이 생성되는 시점에 최신 버전의 런타임 환경으로 자동 프로비저닝되기 때문에, 디플로이먼트를 재시작하는 것만으로도 업그레이드가 가능합니다.
kubectl rollout restart deployment assets -n assets
노드 버전 확인 (업그레이드 전 → 후)
업그레이드 전, 기존 Fargate 노드의 쿠버네티스 버전을 확인해 보면 다음과 같습니다:
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-19-187.us-west-2.compute.internal Ready <none> 29h v1.25.16-eks-2d5f260 10.0.19.187 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25
kubectl rollout restart deployment assets -n assets
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-22-34.us-west-2.compute.internal Ready <none> 43s v1.26.15-eks-2d5f260 10.0.22.34 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25
최종 확인(전체 데이터플레인)
이렇게 모든 노드가 업그레이드된 클러스터 내에서 원하는 버전과 상태로 정상 동작하고 있음을 확인했다면, EKS 데이터플레인 업그레이드 성공적으로 완료!
모든 노드 상태 및 버전 확인**
#
kubectl get node
NAME STATUS ROLES AGE VERSION
fargate-ip-10-0-20-30.us-west-2.compute.internal Ready <none> 12m v1.26.15-eks-2d5f260
ip-10-0-19-132.us-west-2.compute.internal Ready <none> 11h v1.26.15-eks-59bf375
ip-10-0-3-241.us-west-2.compute.internal Ready <none> 14m v1.26.15-eks-59bf375
ip-10-0-33-62.us-west-2.compute.internal Ready <none> 3m21s v1.26.15-eks-1552ad0
ip-10-0-33-7.us-west-2.compute.internal Ready <none> 11h v1.26.15-eks-59bf375
ip-10-0-43-67.us-west-2.compute.internal Ready <none> 8m49s v1.26.15-eks-59bf375
ip-10-0-5-91.us-west-2.compute.internal Ready <none> 2m1s v1.26.15-eks-1552ad0
ip-10-0-6-214.us-west-2.compute.internal Ready <none> 36m v1.26.15-eks-59bf375
ip-10-0-7-148.us-west-2.compute.internal Ready <none> 10h v1.26.15-eks-59bf375
#
aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --output table
#
kubectl get node --label-columns=eks.amazonaws.com/capacityType,node.kubernetes.io/lifecycle,karpenter.sh/capacity-type,eks.amazonaws.com/compute-type
kubectl get node -L eks.amazonaws.com/nodegroup,karpenter.sh/nodepool
kubectl get node --label-columns=node.kubernetes.io/instance-type,kubernetes.io/arch,kubernetes.io/os,topology.kubernetes.io/zone
Amazon EKS Upgrades Workshop 실습 : BlueGreen Upgrade
들어가며
이번 실습에서는 기존 EKS 클러스터(Blue)를 유지한 상태에서, 신규 Green 클러스터를 생성하고 워크로드를 점진적으로 이전하는 Blue/Green 방식의 마이그레이션 전략을 다룹니다
신규 Green 클러스터를 1.30
버전 생성하여, In-place 업그레이드처럼 마이너 버전마다 단계적으로 올릴 필요 없이 한 번에 최신 버전으로 마이그레이션이 가능합니다.
신규 Green EKS 클러스터 생성
Terraform 코드 구조 확인
새로운 클러스터 구성 파일은 eksgreen-terraform 디렉터리에 포함되어 있으며, 아래와 같은 파일 구성으로 되어 있습니다:
cd ~/environment
unzip eksgreen.zip
eksgreen-terraform/
├── README.md
├── addons.tf # ArgoCD, EFS 등 애드온 구성
├── base.tf # EKS 클러스터 및 노드그룹 기본 설정
├── variables.tf # 입력 변수 정의
└── versions.tf # provider 버전 고정
ArgoCD 구성
Green 클러스터 역시 GitOps 기반으로 관리되기 때문에, addons.tf에서 ArgoCD 애드온 모듈을 설정해 자동 배포합니다.
Cluster Bootstrapping을 하기 위한 ArgoCD는 eks_blueprints의 addon을 통해 배포가 된다.
# addons.tf
module "eks_blueprints_addons" {
...
// ArgoCD 추가
argocd = {
set = [
{
name = "server.service.type"
value = "LoadBalancer"
}
]
wait = true
}
Green 클러스터 생성 실행
# 테라폼 배포
cd eksgreen-terraform
terraform init
terraform plan -var efs_id=$EFS_ID
terraform apply -var efs_id=$EFS_ID -auto-approve
AWS 콘솔 - Green 클러스터 확인

• ArgoCD Pod 상태 확인:
ec2-user:~/environment/eksgreen-terraform:$ kubectl get pod -n argocd
NAME READY STATUS RESTARTS AGE
argo-cd-argocd-application-controller-0 1/1 Running 0 18h
argo-cd-argocd-applicationset-controller-7b556db7d4-5g258 1/1 Running 0 18h
argo-cd-argocd-dex-server-86bddbd757-6jlqm 1/1 Running 0 18h
argo-cd-argocd-notifications-controller-7fff4884b6-rhmmf 1/1 Running 0 18h
argo-cd-argocd-redis-6d4d8d884-szj7v 1/1 Running 0 18h
argo-cd-argocd-repo-server-64cbf54678-6gx5m 1/1 Running 0 18h
argo-cd-argocd-server-575cdd9494-79jz6 1/1 Running 0 18h
Stateless Workload Migration
Stateless 애플리케이션은 영구적인 데이터 저장소에 의존하지 않기 때문에, Blue → Green 클러스터 간 마이그레이션이 비교적 간단합니다.
기존과 동일한 설정으로 Green 클러스터에 배포하고 트래픽만 전환하면 되기 때문에 마이그레이션의 첫 단계로 적합합니다.
GitOps 기반 배포 준비(Repository Setup)
ArgoCD를 활용해 GitOps 방식으로 애플리케이션을 관리하고 있다면, 레포지토리의 브랜치만 전환해도 배포 대상 클러스터를 유연하게 바꿀 수 있습니다.
# Green 브랜치 생성 및 전환
git switch -c green
git branch -a
* green
EC2 NodeClass 업데이트 (Karpenter)
Green 클러스터 환경에 맞게 AMI ID, IAM 역할, 보안 그룹, 서브넷 등 설정을 새롭게 구성해야 합니다.
# 최신 Amazon Linux 2023 기반 AMI 조회 (예: EKS 1.30)
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
default-ec2 nc.yaml 파일을 생성하고 Green 클러스터 설정에 맞게 작성합니다.
# 업데이트
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
⚠️ 마이그레이션 전 Deprecated 리소스 점검
Green 클러스터는 EKS 1.30 이상으로 설정되어 있으므로, 기존 애플리케이션이 사용하던 deprecated 된 K8S 리소스 버전이 호환되지 않을 수 있습니다. ( 컨트롤 플레인 업그레이드 이후, 발생한 API 호환 문제 해결 )

pluto 명령어를 사용하면 deprecated 버전을 확인할 수 있습니다. 쿠버네티스 API 버전이 올라감에 따라 HPA의 apiVersion은 v2beta2
-> v2
변경필요.

🤔 pluto vs kubectl convert
kubectl convert
- krew 플러그인으로, kubectl convert로 최신 API 버전으로 변환해 주는 도구(변환)
pluto
- deprecated 리소스를 감지하는 도구(검사)
브랜치 반영 및 Sync
Green 클러스터로의 배포를 위해, ArgoCD App of Apps 설정 파일에서 브랜치를 green으로 전환합니다.
# App of Apps 설정 변경
sed -i 's/targetRevision: main/targetRevision: green/' app-of-apps/values.yaml
# 변경 사항 커밋 및 푸시
git add .
git commit -m "1.30 compatible changes"
git push -u origin green
이후 ArgoCD에서 Sync 버튼을 누르거나 자동 동기화를 통해 Green 클러스터에 애플리케이션이 정상적으로 배포되는 것을 확인할 수 있습니다.

Stateful Workload Migration
Statefulset은 영구 데이터를 보존해야 하는 워크로드로, 업그레이드 시 더 세심한 마이그레이션 전략이 필요합니다.
이번 실습에서는 Amazon EFS를 활용한 Nginx(StatefulSet)을 기존 클러스터(Blue)에서 신규 클러스터(Green)로 데이터를 유지한 채 마이그레이션 해보겠습니다.

Step 1. Blue 클러스터에 StatefulSet 배포
먼저, Blue 클러스터에 EFS 기반의 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
resources:
requests:
storage: 1Gi
EOF
# 리소스 확인
ec2-user:~/environment/eks-gitops-repo:$ kubectl get sts,pvc
NAME READY AGE
statefulset.apps/efs-example 1/1 38s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/efs-storage-efs-example-0 Bound pvc-3b5e8a18-451e-4e48-b18c-af44bd5fe907 1Gi RWX efs 38s
EFS CSI 드라이버에 의해 자동으로 PersistentVolumeClaim (PVC) 이 바인딩되고, efs 스토리지 클래스가 적용됩니다
efs
스토리지 클래스 확인 -> fileSystemId


Step 2. EFS에 파일 생성 및 데이터 보존 테스트
# nginx 디렉토리에 index.html 생성
kubectl exec -it <efs-example-pod> -- bash -c 'echo "aews study 9w end!" > /usr/share/nginx/html/index.html'
이후 파드를 삭제한 뒤 재생성되는 파드에서도 데이터가 유지되는지 확인합니다.
kubectl delete pod -l app=efs-example
kubectl exec -it <efs-example-pod> -- cat /usr/share/nginx/html/index.html
# 출력: aews study 9w end!
Step 3. Green 클러스터에 동일 StatefulSet 배포
이제 Green 클러스터에서도 동일한 이름과 네임스페이스로 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
resources:
requests:
storage: 1Gi
EOF
EFS는 다중 클러스터에서 공유 가능하기 때문에, Green 클러스터에서도 Blue에서 만든 파일이 보여야 합니다.
kubectl apply -f efs-example-statefulset.yaml
kubectl exec -it <efs-example-pod> -- cat /usr/share/nginx/html/index.html
# 출력: aews study 9w end!
📌 실제로는 같은 EFS의 경로를 다른 클러스터에서 동시에 참조하고 있으며, 이는 EFS CSI Driver가 자동으로 액세스 포인트를 생성하여 처리합니다.
액세스 포인트 구조 분석
EFS 내부를 확인하면 다음과 같은 경로로 접근되고 있음을 알 수 있습니다:
/dynamic_provisioning/{namespace}/{pvc-name}
# 예시
/dynamic_provisioning/default/efs-storage-efs-example-0 ← Blue/Green 동일 PVC
/dynamic_provisioning/test/efs-storage-efs-example-0 ← 서로 다른 네임스페이스일 경우
즉, 네임스페이스 및 파드 이름이 같을 경우 동일한 위치에 접근하게 됩니다.

네임스페이스가 다르거나, PVC 명이 다르면 다른 위치가 생성되어 파일이 보이지 않을 수 있습니다.

액세스 포인트의 경로가 달라져, 파일이 존재하지 않는 것을 확인할 수 있습니다.
# 확인
k exec -it -n test efs-example-0 -- ls /usr/share/nginx/html
.
# index.html 파일이 존재하지 않는 응답
ec2-user:~/environment/eksgreen-terraform:$ k exec -it -n test efs-example-0 -- curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.4</center>
</body>
</html>
🚫 POSIX 권한 이슈
EFS는 NFS 기반 스토리지이므로, POSIX 권한체계를 따릅니다.
POSIX(Portable Operating System Interface for UNIX)
유닉스(리눅스)에서 파일 시스템, 권한, 사용자 관리 등 OS 수준의 표준 Amazon EKS는 NFS 기반으로 동작하기 때문에 Linux처럼 POSIX 방식의 UID/GID/Permission 체계를 따름
즉, 최초 PVC를 생성한 클러스터(예: Blue)에서 파일을 생성하면, 해당 UID/GID 권한으로 마운트 됩니다.

PV의 volueHandler
의 액세스 포인트 ID가 매핑되어 습니다. EFS CSI Driver에 의해 매핑되며 해당 PV를 파드가 볼륨으로 사용하는 것으로 보입니다.
ec2-user:~/environment/eksgreen-terraform:$ k get pv pvc-fe8520ff-c1d5-4f4a-a3d9-a3257e4c133e -o yaml | grep -i 'fsap-'
volumeHandle: fs-0a54fe6e0528b1fc1::fsap-0cd0984aaae23a3b8
첫 생성된 스토리지의 주체(blue)에서만 write가 되고, 이후 스토리지를 공유하는 파드(green)에서는 write 권한이 차단됩니다.
# blue 파드(초기 생성 주체)
root@efs-example-0:/usr/share/nginx/html# touch a
root@efs-example-0:/usr/share/nginx/html# ls
a index.html
# green 파드
root@efs-example-0:/usr/share/nginx/html# touch b
touch: cannot touch 'b': Permission denied
# green 파드 재확인 시, 스토리지 공유 동작 확인.
root@efs-example-0:/usr/share/nginx/html# ls
a index.html
이는 EFS에 저장된 파일들이 특정 UID (예: 100) 사용자만 쓰기 권한을 가지고 있기 때문입니다.
⚠️ 중요: Amazon EFS에서는 특정 파드가 마운트 한 access point 기준으로 UID/GID 권한이 부여되며, 이를 명시적으로 지정하지 않으면 root가 아닌 사용자로 접근할 수 없습니다.

데이터 마이그레이션 완료 후 Blue 클러스터 리소스 제거
모든 데이터 동기화가 확인되면 Blue 클러스터의 스테이트 풀셋을 삭제
kubectl delete statefulset efs-example --context blue
'AWS > EKS' 카테고리의 다른 글
EKS 서버리스 서비스 간략히 알아보기(Fargate & EKS AutoMode) (0) | 2025.03.23 |
---|---|
EKS Karpenter 기본 사용(Node AutoScaling) (1) | 2025.03.05 |
EKS 기본 스토리지(EBS + EFS CSI Driver, Instance Store) (0) | 2025.02.23 |
EKS 기본 네트워크(AWS VPC CNI + AWS LoadBalancer Controller) (0) | 2025.02.16 |
EKS 설치 및 클러스터 엔드포인트(EKS Cluster Endpoint) (2) | 2025.02.09 |