-
[AEWS 3기] 9주차 - EKS UpgradeAWS 2025. 4. 2. 20:10
본 포스팅은 AWS 워크샵을 기반으로 작성되었으며, 해당 workshop에 대한 이론적인 내용과 직접 진행한 실습에 대해서 정리하였습니다.
1. EKS Upgrade 실습
1.2. Introduction : 소개
K8S(+AWS EKS) Release Cycles- Kubernetes 프로젝트는 새로운 기능, 최신 보안 패치 및 버그 수정을 통해 지속적으로 업데이트되고 있습니다. Kubernetes 버전의 의미론을 처음 접하는 경우 Semantic Versioning 용어를 따르며 일반적으로 x.y.z로 표현됩니다. 여기서 x는 주요 버전, y는 마이너 버전, z는 패치 버전입니다. 새로운 Kubernetes 마이너 버전(y)은 대략 4개월마다 출시되며, 모든 버전 >=v1.19는 12개월 동안 표준 지원을 제공하며, 한 번에 최소 3개의 마이너 버전을 지원합니다. Kubernetes 프로젝트는 최신 세 가지 마이너 버전에 대한 릴리스 브랜치를 유지하며, 최신 Kubernetes 릴리스와 관련된 자세한 정보는 여기에서 확인할 수 있습니다.
- Amazon Elastic Kubernetes Service(EKS)는 Kubernetes 프로젝트 릴리스 주기를 따르지만, 버전이 Amazon EKS에서 처음 제공된 후 14개월 동안 한 번에 4개의 마이너 버전에 대한 표준 지원을 제공합니다. 이는 업스트림 Kubernetes가 더 이상 Amazon EKS에서 제공되는 버전을 지원하지 않더라도 마찬가지입니다. Amazon EKS에서 지원되는 Kubernetes 버전에 적용되는 보안 패치를 백포트합니다.
- Amazon EKS Kubernetes 릴리스 캘린더에는 Amazon EKS에서 지원되는 각 Kubernetes 버전에 대한 중요한 릴리스 및 지원 날짜가 있습니다. 최신 EKS 버전의 릴리스가 해당 버전의 Kubernetes보다 몇 주 뒤처지는 이유가 궁금하다면, 이는 Amazon이 새로운 버전의 Kubernetes를 Amazon EKS에서 제공하기 전에 다른 AWS 서비스 및 도구와의 안정성과 호환성을 철저히 테스트하기 때문입니다. 새 버전이 얼마나 빨리 지원될지에 대한 구체적인 날짜나 SLA는 제공하지 않지만, Amazon EKS 팀은 업스트림 릴리스와 EKS 지원 착륙 사이의 격차를 줄이기 위해 노력하고 있습니다.
- [총 26개월 = 14개월 + 12개월] 표준 지원 외에도 Amazon EKS는 최근 확장 지원 기능(출시 발표)을 출시했습니다. 이제 모든 Kubernetes 버전 1.21 이상이 Amazon EKS에서 확장 지원을 받을 수 있습니다. 확장 지원은 표준 지원 종료 후 즉시 자동으로 시작되며 추가로 12개월 동안 계속되어 각 Kubernetes 마이너 버전에 대한 지원이 총 26개월로 늘어납니다. 확장 지원 기간이 끝나기 전에 클러스터가 업데이트되지 않으면 현재 지원되는 가장 오래된 확장 버전으로 자동 업그레이드됩니다. 자세한 내용은 Amazon EKS의 Kubernetes 버전 확장 지원을 참조하세요.
- 확장 지원 기간 동안 Kubernetes 버전을 실행하는 클러스터의 가격은 2024년 4월 1일부터 클러스터당 시간당 총 $0.60의 요금이 부과되며, 비용 표준 지원은 변경되지 않습니다(클러스터당 시간당 $0.10).
- 2024년 7월 23일, Amazon EKS는 Kubernetes 버전 정책을 발표했습니다(출시 발표). Kubernetes 버전 정책에 대한 Amazon EKS 제어를 통해 클러스터 관리자는 EKS 클러스터에 대한 표준 지원 동작 종료를 선택할 수 있습니다. 이러한 제어를 통해 어떤 클러스터가 확장 지원을 받아야 하는지와 Kubernetes 버전에 대한 표준 지원 종료 시 자동으로 업그레이드되어야 하는지 결정할 수 있습니다. 이 제어는 클러스터별로 실행되는 환경이나 애플리케이션에 따라 버전 업그레이드를 비즈니스 요구 사항과 균형 있게 조정할 수 있는 유연성을 제공합니다.
- supportType 속성을 사용하여 새 클러스터와 기존 클러스터 모두에 대한 버전 정책을 설정할 수 있습니다. 버전 지원 정책을 설정하는 데 사용할 수 있는 두 가지 옵션이 있습니다:
- 이 동작은 EKS 콘솔과 CLI를 통해 쉽게 설정할 수 있습니다. 자세한 내용은 클러스터 업그레이드 정책을 참조하세요.
Why Upgrade?- Amazon EKS 버전을 업데이트하는 것은 Kubernetes 클러스터의 보안, 안정성, 성능 및 호환성을 유지하는 데 중요하며, 플랫폼에서 제공하는 최신 기능과 역량을 활용할 수 있도록 보장
- Kubernetes 버전은 Control Plane과 데이터 평면을 모두 포함합니다.
- AWS가 Control Plane을 관리하고 업그레이드하는 동안, 사용자(클러스터 소유자/고객)는 클러스터 Control Plane과 데이터 평면 모두에 대한 업그레이드를 시작할 책임을 집니다.
- 클러스터 업그레이드를 시작할 때, AWS는 Control Plane을 관리하며 데이터 평면의 업그레이드를 시작할 책임이 있습니다.
- 여기에는 자가 관리 노드 그룹, 관리 노드 그룹, Fargate 및 기타 애드온을 통해 프로비저닝된 Worker Node가 포함됩니다.
- Worker Node가 Karpenter Controller를 통해 프로비저닝된 경우, 자동 노드 재활용 및 업그레이드를 위해 드리프트 또는 디스럽션 컨트롤러 기능(spec.expireAfter)을 활용할 수 있습니다.
- 또한 클러스터 업그레이드를 계획할 때 작업 부하의 애플리케이션 가용성을 보장해야 하며, 데이터 평면이 업그레이드되는 동안 작업 부하의 가용성을 보장하기 위해서는 적절한 PodDisruptionBudgets와 topologySpreadConstraint가 필수적입니다.
- Kubernetes 마이너 버전 외에도 Amazon EKS는 새로운 Kubernetes 컨트롤 플레인 설정을 가능하게 하고 보안 수정을 제공하기 위해 주기적으로 새로운 플랫폼 버전을 출시합니다.
- 각 Amazon EKS 마이너 버전은 하나 이상의 관련 플랫폼 버전을 가질 수 있습니다.
- 1.30과 같이 Amazon EKS에서 새로운 Kubernetes 마이너 버전을 사용할 수 있는 경우, 해당 Kubernetes 마이너 버전의 초기 플랫폼 버전은 eks.1부터 시작되며 새로운 버전이 출시될 때마다 플랫폼 버전이 증가합니다(eks.n+1).
- 아래 표는 이를 더 잘 시각화하는 데 도움이 될 수 있으며, Amazon EKS 플랫폼 버전에서 더 자세한 내용을 확인할 수 있습니다. - Docs
- 좋은 소식은 Amazon EKS가 해당 Kubernetes 마이너 버전에 대해 모든 기존 클러스터를 최신 Amazon EKS 플랫폼 버전으로 자동 업그레이드하며, 사용자 측에서 명시적인 조치가 필요하지 않다는 것입니다.
- 따라서 Kubernetes 업데이트 관점에서 볼 때, 안전하고 효율적인 EKS 환경을 위해서는 현재 마이너 버전으로 최신 상태를 유지하는 것이 매우 중요하며, 이는 Amazon EKS의 공유 책임 모델을 반영합니다. 이를 통해 클러스터가 최신 보안 패치 및 버그 수정을 실행하고 있는지 확인하여 보안 취약점의 위험을 줄일 수 있습니다. 또한 성능, 확장성 및 신뢰성을 향상시켜 애플리케이션과 고객에게 더 나은 서비스를 제공합니다.
Amazon EKS Upgrades- 이 워크숍을 진행하면서 클러스터 내 업그레이드 및 청록색 업그레이드와 같은 다양한 업그레이드 전략에 대해 배우게 됩니다.
- 또한 업그레이드 전략을 결정하는 기준과 각 단계에 대해 자세히 알아보세요.
- 아래는 인플레이스 클러스터 업그레이드의 고급 워크플로우이며, 다음 모듈에서 이에 대해 자세히 살펴보겠습니다.
- Amazon EKS 클러스터를 in-place upgrade 제자리에서 업그레이드하려면 다음과 같은 조치를 취해야 합니다:
- 위의 단계는 높은 수준의 시퀀스만 나타내며, API 사용 중단/수정, 버전 왜곡 검사 등과 같은 다른 검사가 있을 수 있습니다.
- 자세한 내용은 여기에서 확인할 수 있습니다. - Docs
- 또한, 아마존 EKS 클러스터 업그레이드에 대한 모범 사례 및 지침은 EKS 모범 사례 가이드의 클러스터 업그레이드 섹션을 참조하시기 바랍니다.
- 이제 다음 섹션에서 EKS 클러스터 업그레이드를 준비하는 과정을 시작해 보겠습니다.
1.3. Preparing for Cluster Upgrades : 업그레이드 전 준비
준비- 클러스터 업그레이드를 시작하기 전에 다음 요구 사항을 확인하세요.
- 업그레이드 워크플로
EKS Upgrade Insights- 배경
- Amazon EKS가 Control Plane 업그레이드를 자동화하는 반면, 업그레이드로 인해 영향을 받을 가능성이 있는 리소스나 애플리케이션을 식별하는 것은 수동 프로세스였습니다.
- 여기에는 릴리스 노트를 검토하여 더 이상 사용되지 않거나 제거된 Kubernetes API를 확인한 다음 해당 API를 사용하는 애플리케이션을 검색하여 수정하는 작업이 포함됩니다.
- EKS Upgrade Insights
- Amazon EKS 클러스터 인사이트는 Amazon EKS 및 Kubernetes 모범 사례를 따르는 데 도움이 되는 권장 사항을 제공합니다.
- 모든 Amazon EKS 클러스터는 Amazon EKS가 선별한 인사이트 목록에 대해 자동으로 반복적으로 검사를 받습니다.
- 이러한 인사이트 검사는 Amazon EKS에서 완전히 관리하며 모든 결과를 해결하는 방법에 대한 권장 사항을 제공합니다.
- Cluster 인사이트를 활용하면 최신 Kubernetes 버전으로 업그레이드하는 데 드는 노력을 최소화할 수 있습니다.
- 매일 클러스터 감사 로그를 스캔하여 사용되지 않는 리소스를 찾고 EKS 콘솔에 결과를 표시하거나 API 또는 CLI를 통해 프로그래밍 방식으로 검색할 수 있습니다.
- Amazon EKS는 Kubernetes 버전 업그레이드 준비와 관련된 insight만 출력.
- 클러스터 인사이트는 주기적으로 업데이트됩니다. 클러스터 인사이트를 수동으로 새로 고칠 수 없습니다. 클러스터 문제를 해결하면 클러스터 인사이트가 업데이트되는 데 시간이 걸립니다.
- Each insight includes
- 권장 사항: 문제를 해결하기 위한 단계.
- 링크: 릴리스 노트, 블로그 게시물과 같은 추가 정보입니다.
- 리소스 목록: 심각도를 반영하는 상태(통과, 경고, 오류, 알 수 없음)가 있는 Kubernetes 리소스 유형(예: CronJobs)입니다.
- 전체 상태: 인사이트의 모든 리소스 중에서 가장 높은 심각도 상태입니다. 이를 통해 업그레이드하기 전에 클러스터에 수정이 필요한지 빠르게 확인할 수 있습니다.
Amazon EKS 클러스터를 버전 1.25에서 1.26으로 업그레이드하는 방법을 알아보겠습니다.
- 대상 버전인 1.26과 관련된 클러스터 인사이트를 가져오는 것으로 시작하겠습니다. EKS 클러스터의 통찰력을 보려면 다음 명령을 실행할 수 있습니다.
# aws eks list-insights --filter kubernetesVersions=1.26 --cluster-name $CLUSTER_NAME | jq . { "insights": [ { "id": "00d5cb0c-45ef-4a1a-9324-d499a143baad", "name": "Deprecated APIs removed in Kubernetes v1.26", "category": "UPGRADE_READINESS", "kubernetesVersion": "1.26", "lastRefreshTime": "2025-03-29T08:28:13+00:00", "lastTransitionTime": "2025-03-29T08:27:52+00:00", "description": "Checks for usage of deprecated APIs that are scheduled for removal in Kubernetes v1.26. Upgrading your cluster before migrating to the updated APIs supported by v1.26 could cause application impact.", "insightStatus": { "status": "ERROR", "reason": "Deprecated API usage detected within last 30 days and your cluster is on Kubernetes v1.25." } }, ... # 상세 설명 확인 aws eks describe-insight --region $AWS_REGION --id 00d5cb0c-45ef-4a1a-9324-d499a143baad --cluster-name $CLUSTER_NAME | jq { "insight": { "id": "00d5cb0c-45ef-4a1a-9324-d499a143baad", "name": "Deprecated APIs removed in Kubernetes v1.26", "category": "UPGRADE_READINESS", "kubernetesVersion": "1.26", "lastRefreshTime": "2025-03-29T08:28:13+00:00", "lastTransitionTime": "2025-03-29T08:27:52+00:00", "description": "Checks for usage of deprecated APIs that are scheduled for removal in Kubernetes v1.26. Upgrading your cluster before migrating to the updated APIs supported by v1.26 could cause application impact.", "insightStatus": { "status": "ERROR", "reason": "Deprecated API usage detected within last 30 days and your cluster is on Kubernetes v1.25." }, "recommendation": "Update manifests and API clients to use newer Kubernetes APIs if applicable before upgrading to Kubernetes v1.26.", "additionalInfo": { "EKS update cluster documentation": "https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html", "Kubernetes v1.26 deprecation guide": "https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-26" }, "resources": [ { "insightStatus": { "status": "ERROR" }, "kubernetesResourceUri": "/apis/autoscaling/v2beta2/namespaces/ui/horizontalpodautoscalers/ui" } ], "categorySpecificSummary": { "deprecationDetails": [ { "usage": "/apis/flowcontrol.apiserver.k8s.io/v1beta1/flowschemas", "replacedWith": "/apis/flowcontrol.apiserver.k8s.io/v1beta3/flowschemas", "stopServingVersion": "1.26", "startServingReplacementVersion": "1.26", "clientStats": [] }, { "usage": "/apis/flowcontrol.apiserver.k8s.io/v1beta1/prioritylevelconfigurations", "replacedWith": "/apis/flowcontrol.apiserver.k8s.io/v1beta3/prioritylevelconfigurations", "stopServingVersion": "1.26", "startServingReplacementVersion": "1.26", "clientStats": [] }, { "usage": "/apis/autoscaling/v2beta2/horizontalpodautoscalers", "replacedWith": "/apis/autoscaling/v2/horizontalpodautoscalers", "stopServingVersion": "1.26", "startServingReplacementVersion": "1.23", "clientStats": [ { "userAgent": "argocd-application-controller", "numberOfRequestsLast30Days": 43077, "lastRequestTime": "2025-03-29T08:17:37+00:00" } ] } ], "addonCompatibilityDetails": [] } } }- AWS 관리 콘솔 확인

(Optional) Illustrative Scenario- 예시 시나리오
- 다음은 업그레이드 인사이트 탭에서 API 상태가 ERROR로 표시되는 예이며, 이는 해당 API가 v1.25에서 지원 중단될 예정임을 나타냅니다.
- 이 API 지원 중단에 대한 자세한 정보를 보려면 인사이트 이름을 클릭하세요.
- 이 이미지에서 우리는 업그레이드 인사이트가 Kubernetes 버전 1.25로 업그레이드할 때 지원 중단으로 인해 API를 활용하는 클러스터에서 실행 중인 리소스 유형을 식별하는 데 도움이 된다는 것을 알 수 있습니다.
- 리소스 유형은 동일하지만 API 버전을 업데이트해야 하는 경우 kubectl-convert 명령을 사용하여 매니페스트 파일을 자동으로 변환할 수 있습니다.
- kubectl-convert : 매니페스트 마이그레이션 도구
- kubectl-convert는 Kubernetes 매니페스트를 최신 API 버전에서 작동하도록 마이그레이션하는 데 편리한 유틸리티입니다. 이는 API가 최신 Kubernetes 릴리스에서 더 이상 사용되지 않거나 제거될 때 중요해집니다. 도움이 될 수 있습니다.
- 메모 : kubectl-convert는 플러그인입니다. 이전 버전의 kubectl에는 kubectl-convert가 내장되어 있었지만, 이제는 별도의 플러그인입니다. 사용하기 전에 설치 - Docs
> EKS Upgrade Checklist- 들어가며
- EKS 문서를 사용하여 업그레이드 체크리스트를 만듭니다. - Docs*
- EKS 버전 업그레이드에 대한 구체적인 지침은 설명서를 참조하여 각 버전의 주요 변경 사항과 고려 사항을 확인하세요.
- Upgrading K8S Add-ons and Components with the API- 주요한 요소 미리 확인 : 종종 주요 요소는 *-system 네임스페이스에 설치
- 호환성을 위해 설명서를 확인하세요
- 애드온 및 타사 도구 업그레이드
일반적인 추가 기능의 다음 예제와 관련 업그레이드 설명서를 참조하세요.
- Amazon VPC CNI: 각 클러스터 버전에 대한 Amazon VPC CNI 추가 기능의 권장 버전은 Kubernetes 자체 관리형 추가 기능에 대한 Amazon VPC CNI 플러그인 업데이트를 참조하세요. Amazon EKS 추가 기능으로 설치된 경우 한 번에 하나의 마이너 버전만 업그레이드할 수 있습니다.
- kube-proxy: Kubernetes kube-proxy 자체 관리형 추가 기능 업데이트를 참조하세요.
- CoreDNS: CoreDNS 자체 관리형 추가 기능 업데이트를 참조하세요.
- AWS Load Balancer 컨트롤러: AWS Load Balancer 컨트롤러는 배포한 EKS 버전과 호환되어야 합니다. 자세한 내용은 설치 안내서를 참조하세요.
- Amazon Elastic Block Store(Amazon EBS) 컨테이너 스토리지 인터페이스(CSI) 드라이버: 설치 및 업그레이드 정보는 Amazon EBS CSI 드라이버를 Amazon EKS 추가 기능으로 관리를 참조하세요.
- Amazon Elastic File System(Amazon EFS) 컨테이너 스토리지 인터페이스(CSI) 드라이버: 설치 및 업그레이드 정보는 Amazon EFS CSI 드라이버를 참조하세요.
- Kubernetes Metrics Server: 자세한 내용은 GitHub의 metrics-server를 참조하세요.
- Kubernetes 클러스터 오토스케일러: Kubernetes 클러스터 오토스케일러의 버전을 업그레이드하려면 배포에서 이미지의 버전을 변경합니다. Cluster Autoscaler는 Kubernetes 스케줄러와 긴밀하게 연결됩니다. 클러스터를 업그레이드할 때는 항상 업그레이드해야 합니다. GitHub 릴리스를 검토하여 Kubernetes 마이너 버전에 해당하는 최신 릴리스의 주소를 찾습니다.
- Karpenter: 설치 및 업그레이드 정보는 Karpenter 설명서를 참조하세요.
추가 팁 : Velero 와 같은 백업 툴로 클러스터의 주요 데이터를 미리 백업 해두기, 테스트 환경에서 충분히 사전 테스트 해보기
- EKS ControlPlane 업그레이드 전 기본 요구 사항 확인AWS는 업그레이드 프로세스를 완료하기 위해 계정의 특정 리소스를 요구합니다. 이러한 리소스가 없으면 클러스터를 업그레이드할 수 없습니다. Control Plane 업그레이드에는 다음 리소스가 필요합니다.
- 사용 가능한 IP 주소 확인
- Amazon EKS 클러스터를 업그레이드하려면 원래 클러스터 생성 시 지정한 서브넷 내에 최소 5개의 여유 IP 주소가 필요합니다. 서브넷에 충분한 여유 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-0aeb12f673d69f7c5 | us-west-2c | 4038 | | subnet-047ab61ad85c50486 | us-west-2b | 4069 | | subnet-01bbd11a892aec6ee | us-west-2a | 4030 | +---------------------------+--------------+-------+- 기존 서브넷에 충분한 사용 가능한 IP가 없는 경우 Amazon에서는 UpdateClusterConfiguration을 사용하는 것이 좋습니다.
- 업그레이드를 진행하기 전에 클러스터 구성을 새로운 서브넷으로 업데이트하기 위한 API입니다.
- 새로운 서브넷 요구 사항
- 가용성 영역(AZ) : 새 서브넷은 클러스터 생성 중에 원래 선택한 동일한 AZ 집합 내에 있어야 합니다.
- VPC 멤버십 : 새 서브넷은 클러스터와 연결된 동일한 VPC에 속해야 합니다.
- IP 풀 확장(선택 사항)
- 서브넷 업데이트 후에도 충분한 IP가 없다면 추가 CIDR 블록을 VPC에 연결하는 것을 고려하세요. 이렇게 하면 기본적으로 사용 가능한 IP 주소 풀이 늘어납니다. 할 수 있는 일은 다음과 같습니다.
- 이러한 지침을 따르면 EKS 클러스터가 원활한 Kubernetes 버전 업그레이드를 수행하는 데 필요한 IP 리소스를 확보할 수 있습니다.
- EKS IAM Role 확인
IAM 역할을 사용할 수 있는지, 그리고 계정에 올바른 assume role policy이 있는지 확인하려면 다음 명령을 실행할 수 있습니다.
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' | jq { "Version": "2012-10-17", "Statement": [ { "Sid": "EKSClusterAssumeRole", "Effect": "Allow", "Principal": { "Service": "eks.amazonaws.com" }, "Action": [ "sts:TagSession", "sts:AssumeRole" ] } ] } aws iam get-role --role-name ${ROLE_ARN##*/} | jq ...- EKS Security Groups: What You Need to Know
- 클러스터를 만들면 Amazon EKS는 eks-cluster-sg-my-cluster-uniqueID라는 이름의 보안 그룹을 만듭니다.
- 이 보안 그룹에는 다음과 같은 기본 규칙이 있습니다.
- Amazon EKS 보안 그룹: 연결 및 규칙
Amazon EKS가 보안 그룹을 활용하는 방식에 대한 세부 내용은 다음과 같습니다.
- 자동 태그
- 리소스 연결
- 기본 보안 규칙
- 사용자 지정 보안 그룹(선택 사항)
기본적으로 EKS는 광범위한 권한을 가진 기본 보안 그룹을 제공하지만, 사용자가 사용자 정의 그룹을 사용하여 더 엄격한 보안 정책을 구현할 수 있도록 합니다.

- EKS 클러스터의 보안 강화
EKS 클러스터 내에서 트래픽 흐름을 제한하고 싶으신가요? 알아야 할 사항은 다음과 같습니다.
- 기본 규칙은 개방적입니다. 기본적으로 EKS는 클러스터 구성 요소 간의 무제한 통신을 허용합니다.
- 아웃바운드 트래픽 사용자 지정: 열려 있는 포트를 제한하려면 기본 아웃바운드 규칙을 제거하고 다음 최소 요구 사항을 구현합니다.
- 인바운드 규칙 지속성: EKS는 업데이트 중에 기본 인바운드 규칙을 제거한 후에 해당 규칙을 자동으로 다시 생성합니다.
- 추가 고려 사항
- 아웃바운드 인터넷 액세스(선택 사항)
- 컨테이너 이미지 액세스
- IPv4/IPv6에 대한 별도 규칙
테스트는 매우 중요합니다. 프로덕션 클러스터에 변경 사항을 배포하기 전에 모든 Pod를 철저히 테스트하여 새로운 보안 규칙에 따라 올바르게 작동하는지 확인하세요.

- EKS Cluster Upgrade High Availability (HA) Strategies
1.4. Choosing an Upgrade Strategy : 업그레이드 전략 선택 (In-Place vs Blue-Green)
- 적절한 업그레이드 전략이 없는 경우의 일반적인 문제- 명확하게 정의된 EKS 업그레이드 전략이 없는 고객은 다음을 포함한 여러 가지 어려움에 직면할 수 있습니다.
- 계획 되지 않은 가동 중지
- 호환성 문제
- 롤백의 어려움
- 보안 취약점
- 놓친 기회
- 이러한 과제를 해결하려면 잘 정의된 업그레이드 전략을 수립하는 것이 중요합니다. EKS 업그레이드를 계획할 때 고려해야 할 두 가지 주요 전략이 있습니다. 인플레이스 업그레이드와 블루그린 업그레이드입니다. 각 전략에는 고유한 장점, 단점 및 고려 사항이 있으며, 특정 요구 사항과 제약 조건에 따라 신중하게 평가해야 합니다.
- 이 모듈에서는 두 업그레이드 전략을 자세히 살펴보고 장단점을 논의합니다. 또한 특정 요구 사항과 제약 조건에 따라 가장 적합한 전략을 선택하는 방법에 대한 지침도 제공합니다. 이 모듈을 마치면 In-Place와 Blue-Green 업그레이드의 차이점을 명확하게 이해하고 EKS 클러스터 업그레이드를 계획할 때 정보에 입각한 결정을 내릴 수 있게 됩니다.
- In-place 업그레이드 전략 : 기존 EKS 클러스터를 최신 Kubernetes 버전으로 업그레이드내부 업그레이드 프로세스에는 일반적으로 다음 단계가 포함됩니다.
- EKS Control Plane을 대상 Kubernetes 버전으로 업그레이드합니다.
- 새로운 Kubernetes 버전과 일치하도록 Worker Node AMI를 업데이트합니다.
- 애플리케이션 가동 중지 시간을 최소화하기 위해 Worker Node를 한 번에 하나씩 또는 소규모로 비우고 교체합니다.
- 새 버전과의 호환성을 보장하기 위해 모든 Kubernetes 매니페스트, 애드온 및 구성을 업데이트합니다.
- 철저한 테스트와 검증을 수행하여 애플리케이션과 서비스가 예상대로 작동하는지 확인합니다.
- 인플레이스 업그레이드의 장점
- VPC, 서브넷, 보안 그룹 등 기존 클러스터 리소스와 구성을 유지합니다.
- 동일한 클러스터 API 엔드포인트를 유지하므로 외부 통합 및 도구를 업데이트할 필요성이 최소화됩니다.
- 업그레이드 프로세스 중에 여러 클러스터를 관리하는 것에 비해 인프라 오버헤드가 덜 필요합니다.
- 클러스터 간에 상태 저장 애플리케이션과 지속형 데이터를 마이그레이션할 필요성을 최소화합니다.
- 인플레이스 업그레이드의 단점
- 업그레이드 과정에서 가동 중지 시간을 최소화하려면 신중한 계획과 조정이 필요합니다.
- 여러 Kubernetes 버전을 건너뛸 경우 연속적인 업그레이드가 여러 번 필요할 수 있으며, 업그레이드 프로세스가 길어질 수 있습니다.
- 업그레이드 중에 문제가 발생하면 롤백이 더 어렵고 시간이 많이 걸릴 수 있습니다. Control Plane이 업그레이드되면 롤백할 수 없습니다. → rollback 할 수 없으므로 updgrade에 신중해야함
- 호환성을 보장하기 위해 모든 구성 요소와 종속성에 대한 철저한 테스트와 검증이 필요합니다. → rollback이 안되므로 꼭 확인해야한다!
- Blue-Green 업그레이드 전략 : 새 EKS 클러스터(addon, apps)를 만들고 트래픽을 이전 클러스터에서 새 클러스터로 점진적으로 전환- 블루-그린 업그레이드 프로세스에는 일반적으로 다음 단계가 포함됩니다.
- 원하는 Kubernetes 버전 및 구성으로 새 EKS 클러스터(녹색)를 만듭니다.
- 새 클러스터에 애플리케이션, 애드온 및 구성을 배포합니다.
- 새 클러스터가 예상대로 작동하는지 확인하기 위해 철저한 테스트와 검증을 수행합니다.
- DNS 업데이트, 로드 밸런서 구성 또는 서비스 메시와 같은 기술을 사용하여 점진적으로 이전 클러스터(파란색)에서 새 클러스터(녹색)로 트래픽을 전환합니다.
- 새 클러스터를 면밀히 모니터링하여 트래픽을 처리하고 예상대로 성능이 발휘되는지 확인하세요.
- 모든 트래픽이 새 클러스터로 전환되면 이전 클러스터를 해제합니다.
- 블루-그린 업그레이드의 장점
- 새로운 클러스터를 프로덕션 트래픽으로 전환하기 전에 철저히 테스트할 수 있으므로, 보다 통제되고 안전한 업그레이드 프로세스가 가능합니다.
- 단일 업그레이드에서 여러 Kubernetes 버전을 건너뛸 수 있으므로 전체 업그레이드 시간과 노력이 줄어듭니다. ex) 1.27사용시 in-place의 경우 1.28 → 1.29 → 1.30 이렇게 순차적으로 upgrade해야 하지만, blue-green의 경우 한번에 1.31로 upgrade 할 수 있음
- 문제가 발생할 경우 트래픽을 이전 클러스터로 다시 전환하여 빠르고 쉬운 롤백 메커니즘을 제공합니다.
- 새 클러스터가 완전히 검증될 때까지 이전 클러스터가 계속 트래픽을 제공하므로 업그레이드 프로세스 동안 가동 중지 시간이 최소화됩니다.
- 블루-그린 업그레이드의 단점
- 두 개의 클러스터를 동시에 유지 관리해야 하므로 업그레이드 프로세스에 추가적인 인프라 리소스와 비용이 필요합니다.
- 클러스터 간 트래픽 이동에 대한 보다 복잡한 조정 및 관리가 필요합니다.
- CI/CD 파이프라인, 모니터링 시스템, 액세스 제어 등의 외부 통합을 업데이트하여 새 클러스터를 가리키도록 해야 합니다.
- 클러스터 간 데이터 마이그레이션이나 동기화가 필요한 상태 저장 애플리케이션의 경우 어려울 수 있습니다.
- EKS API Endpoint, OIDC Endpoint가 변경되어 IRSA의 정보를 업데이트 해줘야 한다.
- 상태 저장 워크로드에 대한 고려 사항
- 상태 저장 워크로드에 대한 블루-그린 업그레이드를 수행할 때는 데이터 마이그레이션 및 동기화 프로세스를 신중하게 계획하고 실행하세요.
- Velero와 같은 도구를 사용하여 영구 데이터를 마이그레이션하고 클러스터 간에 데이터를 동기화 상태로 유지하며 빠른 롤백을 활성화하세요.
- 새 클러스터에서 영구 볼륨 프로비저닝을 구성하여 이전 클러스터의 스토리지 클래스 또는 프로비저너와 일치시키세요.
- 애플리케이션 설명서를 참조하고 애플리케이션 소유자와 협력하여 데이터 마이그레이션 및 동기화에 대한 특정 요구 사항을 이해하세요.
- Velero와 같은 도구를 적절히 계획하고 활용하는 것은 위험을 최소화하고 상태 저장 애플리케이션에 대한 원활한 업그레이드 프로세스를 보장하는 데 중요합니다.
> In-place 와 Blue-Green 업그레이드 전략 중 선택- 전략을 선택할 때 고려해야 할 요소
- 가동 중지 허용 범위 : 업그레이드 프로세스 중에 애플리케이션과 서비스에 대한 허용 가능한 가동 중지 시간 수준을 고려하세요.
- 복잡성 업그레이드 : 애플리케이션 아키텍처, 종속성 및 상태 구성 요소의 복잡성을 평가합니다.
- Kubernetes 버전 차이 : 현재 Kubernetes 버전과 대상 버전 간의 차이와 애플리케이션 및 애드온의 호환성을 평가합니다.
- 리소스 제약 : 업그레이드 프로세스 중에 여러 클러스터를 유지하기 위한 사용 가능한 인프라 리소스와 예산을 고려하세요. 블루/그린과 유사한 카나리아 전략은 워크로드를 늘리는 동안 이전 클러스터를 확장하는 동안 새 클러스터를 확장하는 것을 제외하고는 이를 최소화합니다.
- 팀 전문성 : 여러 클러스터를 관리하고 트래픽 전환 전략을 구현하는 데 대한 팀의 전문성과 익숙함을 평가합니다.
- 의사 결정 차트 (예시)
- K8S Version Skew 를 이용한 Incremental In-place 업그레이드 전략허용되는 최대 버전 스큐에 도달할 때까지 Worker Node 업그레이드를 연기하면서 EKS Control Plane을 점진적으로 업그레이드
업그레이드 프로세스:
- EKS Control Plane을 다음 마이너 버전으로 업그레이드합니다. Kubernetes는 Control Plane이 Worker Node보다 최대 2개의 마이너 버전(또는 Kubernetes 1.28부터 3개의 마이너 버전) 앞설 수 있는 버전 Skew를 지원합니다.
- Control Plane이 최대 허용 스큐를 초과하는 버전으로 업그레이드될 때까지 기존 버전에서 Worker Node를 유지합니다. 예를 들어, Control Plane을 1.21에서 시작하고 작Worker Node 1.21에서 시작하는 경우 작업Worker Node업그레이드하지 않고도 Control Plane을 1.22, 1.23 및 1.24로 업그레이드할 수 있습니다.
- Control Plane이 허용되는 최대 스큐를 초과하는 버전(예: 작업자가 여전히 1.21을 사용하고 있는 경우 1.24)에 도달하면 Control Plane을 추가로 업그레이드하기 전에 지원되는 스큐 범위 내의 버전(예: 1.22 또는 1.23)으로 Worker Node를 업그레이드합니다.
- Control Plane과 Worker Node 모두에서 원하는 Kubernetes 버전에 도달할 때까지 1~3단계를 반복합니다.
- 이상적인 사용 사례:
- 최신 Kubernetes 릴리스보다 여러 버전 뒤쳐져 있으며 점진적으로 따라잡고 싶어합니다.
- Worker Node에는 광범위한 테스트가 필요하고 빈번한 업그레이드를 어렵게 만드는 복잡하고 상태 저장형 워크로드가 있습니다.
- Worker Node의 중단을 최소화하면서 새로운 기능과 버그 수정에 액세스하기 위해 정기적으로 Control Plane 업그레이드를 수행하려고 합니다.
- 고려 사항:
- 워커 노드가 호환 버전으로 업그레이드될 때까지 일부 새로운 Kubernetes 기능, 성능 개선 및 버그 수정을 완전히 사용할 수 없을 수 있습니다.
- 여러 버전을 건너뛴 후 워커 노드를 업그레이드하는 경우 호환성을 보장하고 문제를 식별하기 위해 철저한 테스트가 중요합니다.
- 이 전략은 유연성을 제공하지만, 비호환성 위험을 최소화하고 클러스터 전체에서 일관된 기능 세트를 보장하기 위해 Control Plane과 Worker Node 버전을 최대한 가깝게 유지하는 것이 좋습니다.
Kubernetes의 버전 스큐 지원을 활용하면 이전 버전에서 시작하더라도 EKS 클러스터의 증분적 인플레이스 업그레이드를 수행할 수 있습니다. 이 접근 방식을 사용하면 워크로드 중단을 최소화하면서 Kubernetes 버전을 점진적으로 따라잡을 수 있습니다.
이러한 권장 사항은 일반적인 지침으로 사용되며, 선택하는 구체적인 접근 방식은 고유한 요구 사항, 제약 조건 및 위험 허용 범위에 따라 달라집니다. 업그레이드 전략을 결정할 때 클러스터의 특성, 작업 부하 요구 사항 및 조직의 우선순위를 신중하게 평가하는 것이 필수적입니다. 또한 선택한 업그레이드 접근 방식에 관계없이 잘 정의된 테스트 및 검증 계획을 수립하는 것이 중요합니다. 프로덕션 업그레이드를 진행하기 전에 비프로덕션 환경에서 애플리케이션, 애드온 및 통합을 철저히 테스트하여 잠재적인 문제를 식별하고 해결하세요.
마지막으로, 업그레이드 프로세스 중 및 이후에 발생할 수 있는 문제를 감지하고 문제를 해결하기 위한 포괄적인 모니터링 및 로깅 메커니즘이 있는지 확인하십시오. 습득한 교훈과 진화하는 모범 사례를 기반으로 업그레이드 전략을 정기적으로 검토하고 업데이트하여 EKS 클러스터 관리 관행을 지속적으로 개선하십시오.
- 결론Amazon EKS 클러스터를 업그레이드하는 것은 최신 Kubernetes 기능, 보안 패치 및 성능 개선을 활용할 수 있도록 하는 중요한 프로세스입니다. 적절한 업그레이드 전략을 선택하는 것은 다운타임을 최소화하고, 위험을 줄이며, 새로운 Kubernetes 버전으로의 원활한 전환을 보장하는 데 필수적입니다.
이 모듈에서는 두 가지 주요 업그레이드 전략인 In-Place 업그레이드와 Blue-Green 업그레이드를 살펴보았습니다. 각 접근 방식의 장단점을 논의하고 다운타임 허용 범위, 업그레이드 복잡성, 리소스 제약, 규제 요구 사항 등 다양한 시나리오와 요인에 따라 권장 사항을 제공했습니다.
이 모듈의 주요 내용은 다음과 같습니다.
- In-Place 업그레이드는 다운타임 허용 범위가 낮은 부 버전 업그레이드에 적합한 반면, Blue-Green 업그레이드는 주요 버전 업그레이드나 상태 복잡도가 높은 애플리케이션에 권장됩니다.
- 성공적인 업그레이드를 위해서는 선택한 전략에 관계없이 신중한 계획, 테스트 및 검증이 필수적입니다.
- 업그레이드 프로세스 중에 문제를 신속하게 식별하고 해결하려면 모니터링, 로깅 및 명확하게 정의된 롤백 계획이 필수적입니다.
- 습득한 교훈과 진화하는 모범 사례를 기반으로 업그레이드 전략을 지속적으로 평가하고 최적화하는 것은 EKS 클러스터 관리 관행을 개선하는 데 중요합니다.
EKS 클러스터 업그레이드를 계획할 때 다음 모범 사례를 고려하세요.
- 클러스터의 특성, 작업 부하 요구 사항, 조직의 우선순위를 철저히 평가하여 가장 적합한 업그레이드 전략을 선택하세요.
- 호환성을 보장하고 문제 위험을 최소화하기 위해 포괄적인 테스트 및 검증 계획을 개발합니다.
- 애플리케이션 소유자, 규정 준수 관리자, 사용자 등 관련 이해 관계자와 협력하여 업그레이드 계획을 해당 요구 사항과 기대치에 맞게 조정합니다.
- 자동화 및 IaC(Infrastructure as Code) 도구를 활용하여 업그레이드 프로세스를 간소화하고 다양한 환경의 일관성을 보장합니다.
- 이전 업그레이드에서 얻은 새로운 모범 사례와 교훈을 통합하여 업그레이드 전략을 정기적으로 검토하고 업데이트하세요.
1.5. (실습 1.) In-place Cluster Upgrade : 1.25 → 1.26 : 총 1시간 (예상) 소요 이상 실습 포함
> 들어가며- 사전 준비
- Kubernetes와 EKS의 릴리스 노트를 검토하세요.
- 추가 기능의 호환성을 검토하세요. Kubernetes 애드온과 사용자 정의 컨트롤러를 업그레이드하세요.
- 워크로드에서 더 이상 사용되지 않거나 삭제된 API 사용을 식별하고 수정합니다.
- 클러스터를 백업합니다(필요한 경우).
- 업그레이드 단계
- 클러스터 Control Plane 업그레이드
- Kubernetes 애드온 및 사용자 정의 컨트롤러를 업데이트하세요.
- 클러스터의 노드를 업그레이드하세요
필요한 경우 사용되지 않는 API를 제거하고 Kubernetes 매니페스트를 업데이트하여 적절한 리소스를 수정한 후, 위의 순서대로 클러스터를 업그레이드할 수 있습니다. 이러한 단계는 테스트 환경에서 완료하는 것이 가장 좋으므로 프로덕션 클러스터에서 업그레이드 작업을 시작하기 전에 클러스터 구성과 애플리케이션 매니페스트의 문제를 발견할 수 있습니다.
[1. 제어부] Control Plane Upgrade* 10분 소요 실습 포함Amazon EKS에서 클러스터를 실행하는 가장 큰 이점 중 하나는 클러스터 Control Plane의 업그레이드가 단일 완전 자동화된 작업이라는 것입니다. 업그레이드하는 동안 현재 제Control Plane구성 요소는 파란색/녹색 방식으로 업그레이드됩니다. 문제가 발생하면 업그레이드가 롤백되고 애플리케이션은 계속 작동하고 사용 가능합니다.
One of the great benefits of running your clusters in Amazon EKS is that the upgrade of the cluster control plane is a single fully-automated operation. During Upgrade, the current control plane components are upgraded in blue/green fashion. If any issues arise, the upgrade is rolled back, and your applications remain up and available.
인플레이스 업그레이드는 다음으로 높은 Kubernetes 마이너 버전까지 점진적으로 진행되므로 현재 버전과 대상 버전 사이에 여러 릴리스가 있는 경우 순서대로 각 릴리스를 거쳐야 합니다. 다양한 요소를 고려하고 특정 요구 사항과 제약 조건에 가장 적합한 접근 방식을 평가하는 것이 중요합니다. 인플레이스 업그레이드 전략과 블루그린 업그레이드 전략 선택 참조
In-place upgrades are incremental to the next highest Kubernetes minor version, which means if you have several releases between your current and target versions, you’ll need to move through each one in sequence. It's essential to consider various factors and evaluate which approach best suits your specific requirements and constraints. Please refer Choosing between In-Place vs Blue-Green Upgrade Strategy before moving ahead with upgrades.
Control Plane을 업그레이드하기 전의 기본 Amazon EKS 요구 사항입니다.
- Amazon EKS는 클러스터를 업데이트하기 위해 클러스터를 생성할 때 지정한 서브넷에서 최대 5개의 사용 가능한 IP 주소가 필요합니다. IP를 사용할 수 없는 경우 버전 업데이트를 수행하기 전에 "UpdateClusterConfiguration" API를 사용하여 클러스터 구성을 업데이트하여 새 클러스터 서브넷을 포함하거나 기존 VPC CIDR 블록의 IP 주소가 부족하면 추가 CIDR 블록을 연결하는 것을 고려하세요.
- Control Plane IAM 역할은 필요한 권한이 있는 계정에 있어야 합니다.
- 클러스터에 비밀 암호화가 활성화된 경우 클러스터 IAM 역할에 AWS Key Management Service(AWS KMS) 키를 사용할 수 있는 권한이 있는지 확인해야 합니다.
업그레이드를 시작하면 AWS가 EKS Control Plane을 업그레이드하는 단계에 대한 자세한 분석은 다음과 같습니다.
- 업그레이드 사전 검사:
- Control Plane 구성 요소 업그레이드:
- 이전 Control Plane 구성 요소 종료: 업그레이드가 완료되면 이전 제Control Plane구성 요소가 종료됩니다. The old control plane components are terminated once the upgrade is complete.
업그레이드는 블루/그린 방식으로 이루어지므로 EKS 업그레이드가 실패할 경우 중단을 최소화할 수 있습니다.
- 실패 감지: AWS는 업그레이드 프로세스를 지속적으로 모니터링하여 문제를 감지합니다. Control Plane 업그레이드 중에 문제가 발생하면 프로세스가 즉시 중단됩니다.
- 새로운 Control Plane 구성 요소 종료: AWS는 업그레이드 중에 발생하는 새로운 제Control Plane구성 요소를 종료합니다.
- 롤백 후 평가: AWS는 업그레이드 실패의 이유를 평가하고 문제를 해결하는 방법에 대한 지침을 제공합니다. 고객은 업그레이드를 다시 시도하기 전에 문제를 해결하고 해결해야 합니다.
방법 1 : eksctl 아래 실행하지 않음!
이 명령에서 대상 버전을 지정할 수 있지만 --version에 허용되는 값은 클러스터의 현재 버전 또는 한 버전 더 높은 버전입니다. 현재 두 개 이상의 Kubernetes 버전 업그레이드는 지원되지 않습니다.
Copyeksctl upgrade cluster --name $EKS_CLUSTER_NAME --approve방법 2 : AWS 관리 콘솔 : skip , 아래 실행하지 않음!

방법 3 : aws cli 아래 실행하지 않음!
클러스터에 관리되는 노드 그룹이 연결되어 있는 경우, 클러스터를 새로운 Kubernetes 버전으로 업데이트하려면 모든 노드 그룹의 Kubernetes 버전이 클러스터의 Kubernetes 버전과 일치해야 합니다.
Copyaws eks update-cluster-version --region ${AWS_REGION} --name $EKS_CLUSTER_NAME --kubernetes-version 1.26 { "update": { "id": "b5f0ba18-9a87-4450-b5a0-825e6e84496f", "status": "InProgress", "type": "VersionUpdate", "params": [ { "type": "Version", "value": "1.26" }, { "type": "PlatformVersion", "value": "eks.1" } ], [...] "errors": [] } } # 다음 명령으로 클러스터 업데이트 상태를 모니터링할 수 있습니다. 이전 명령에서 반환한 클러스터 이름과 업데이트 ID를 사용합니다. # Successful 상태가 표시되면 업데이트가 완료된 것입니다. aws eks describe-update --region ${AWS_REGION} --name $EKS_CLUSTER_NAME --update-id b5f0ba18-9a87-4450-b5a0-825e6e84496f방법 4 : Terraform , 해당 방법으로 실제 업그레이드 실행!
이 랩에서는 terraform을 사용하여 클러스터를 업그레이드합니다. EKS 클러스터는 이미 terraform을 통해 이 랩에 프로비저닝되었습니다. terraform init, plan 및 apply를 수행하여 리소스 상태를 새로 고칩니다.
Copy# cd ~/environment/terraform terraform state list모니터링을 위한 작업 추가
Copy# 현재 버전 확인 : 파일로 저장해두기 kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c > 1.25.txt kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c 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 # IDE-Server 혹은 자신의 PC에서 반복 접속 해두자! export UI_WEB=$(kubectl get svc -n ui ui-nlb -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'/actuator/health/liveness) curl -s $UI_WEB ; echo {"status":"UP"} # 반복 접속 1 UI_WEB=k8s-ui-uinlb-9f78cb369a-4ad811d8831bea96.elb.us-west-2.amazonaws.com/actuator/health/liveness while true; do curl -s $UI_WEB ; date; sleep 1; echo; done # 반복 접속 2 : aws cli 자격증명 설정 필요 aws eks describe-cluster --name $EKS_CLUSTER_NAME | egrep 'version|endpoint"|issuer|platformVersion' "version": "1.25", "endpoint": "https://A77BDC5EEBAE5EC887F1747B6AE965B3.gr7.us-west-2.eks.amazonaws.com", "issuer": "https://oidc.eks.us-west-2.amazonaws.com/id/A77BDC5EEBAE5EC887F1747B6AE965B3" "platformVersion": "eks.44", # 반복 접속 2 while true; do curl -s $UI_WEB; date; aws eks describe-cluster --name eksworkshop-eksctl | egrep 'version|endpoint"|issuer|platformVersion'; echo ; sleep 2; echo; done # 테스트용 파드 netshoot 디플로이먼트,pdb 생성 cat <https://B852364D70EA6D62672481D278A15059.gr7.us-west-2.eks.amazonaws.com", "issuer": "https://oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059" "platformVersion": "eks.44", # 반복 접속 2 while true; do kubectl exec deploy/netshoot -it -n ui -- curl -s -L -o /dev/null -w "%{http_code}\n" http://ui; date; aws eks describe-cluster --name $EKS_CLUSTER_NAME | egrep 'endpoint"|issuer|platformVersion'; echo ; sleep 2; echo; doneeks 모듈에서 eks 클러스터 구성을 볼 수 있습니다 base.tf. cluster_version의 값은 variable.tf의 변수 cluster_version에 정의되어 있습니다. 현재는 .으로 설정되어 있습니다 1.25.
variable.tf의 cluster_version 변수를 에서 로 변경하고 terraform plan을 실행해 1.25보겠습니다 .1.26
variables.tf아래에 보이는 것처럼 파일 에 다음과 같은 변경 사항을 만들었습니다 .


# 기본 정보 aws eks describe-cluster --name $EKS_CLUSTER_NAME | egrep 'version|endpoint"|issuer|platformVersion' # Plan을 적용하면 Terraform이 어떤 변경을 하는지 볼 수 있습니다. terraform plan terraform plan -no-color > plan-output.txt # IDE에서 열어볼것 ... <= data "tls_certificate" "this" { + certificates = (known after apply) + id = (known after apply) + url = "https://oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059" } # module.eks.aws_iam_openid_connect_provider.oidc_provider[0] will be updated in-place ~ resource "aws_iam_openid_connect_provider" "oidc_provider" { id = "arn:aws:iam::271345173787:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059" tags = { "Blueprint" = "eksworkshop-eksctl" "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" "Name" = "eksworkshop-eksctl-eks-irsa" "karpenter.sh/discovery" = "eksworkshop-eksctl" } ~ thumbprint_list = [ - "9e99a48a9960b14926bb7f3b02e22da2b0ab7280", ] -> (known after apply) # (4 unchanged attributes hidden) } # 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) } # module.eks_blueprints_addons.aws_eks_addon.this["vpc-cni"] will be updated in-place ~ resource "aws_eks_addon" "this" { ~ addon_version = "v1.19.3-eksbuild.1" -> (known after apply) id = "eksworkshop-eksctl:vpc-cni" tags = { "Blueprint" = "eksworkshop-eksctl" "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" } # (11 unchanged attributes hidden) # (1 unchanged block hidden) } # module.eks_blueprints_addons.aws_iam_role_policy_attachment.karpenter["AmazonEC2ContainerRegistryReadOnly"] must be replaced -/+ resource "aws_iam_role_policy_attachment" "karpenter" { ~ id = "karpenter-eksworkshop-eksctl-20250325094537762400000002" -> (known after apply) ~ policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" -> (known after apply) # forces replacement # (1 unchanged attribute hidden) } # module.eks_blueprints_addons.module.aws_efs_csi_driver.data.aws_iam_policy_document.assume[0] will be read during apply # (depends on a resource or a module with changes pending) <= data "aws_iam_policy_document" "assume" { + id = (known after apply) + json = (known after apply) + minified_json = (known after apply) + statement { + actions = [ + "sts:AssumeRoleWithWebIdentity", ] + effect = "Allow" + condition { + test = "StringEquals" + values = [ + "sts.amazonaws.com", ] + variable = "oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059:aud" } + condition { + test = "StringEquals" + values = [ + "system:serviceaccount:kube-system:efs-csi-controller-sa", ] + variable = "oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059:sub" } + principals { + identifiers = [ + "arn:aws:iam::271345173787:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059", ] + type = "Federated" } } + statement { + actions = [ + "sts:AssumeRoleWithWebIdentity", ] + effect = "Allow" + condition { + test = "StringEquals" + values = [ + "sts.amazonaws.com", ] + variable = "oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059:aud" } + condition { + test = "StringEquals" + values = [ + "system:serviceaccount:kube-system:efs-csi-node-sa", ] + variable = "oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059:sub" } + principals { + identifiers = [ + "arn:aws:iam::271345173787:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/B852364D70EA6D62672481D278A15059", ] + type = "Federated" } } }Copy# 기본 정보 aws eks describe-cluster --name $EKS_CLUSTER_NAME | egrep 'version|endpoint"|issuer|platformVersion' # 클러스터 버전을 변경하면 테라폼 계획에 표시된 것처럼, 관리 노드 그룹에 대한 특정 버전이나 AMI가 테라폼 파일에 정의되지 않은 경우, # eks 클러스터 Control Plane과 관리 노드 그룹 및 애드온과 같은 관련 리소스를 업데이트하게 됩니다. # 이 계획을 적용하여 제Control Plane버전을 업데이트해 보겠습니다. terraform apply -auto-approve # 10분 소요 # eks control plane 1.26 업글 확인 aws eks describe-cluster --name $EKS_CLUSTER_NAME | jq ... "version": "1.26", # endpoint, issuer, platformVersion 동일 => IRSA 를 사용하는 4개의 App 동작에 문제 없음! aws eks describe-cluster --name $EKS_CLUSTER_NAME | egrep 'version|endpoint"|issuer|platformVersion' # 파드 컨테이너 이미지 버전 모두 동일 kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c > 1.26.txt kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c diff 1.26.txt 1.25.txt # 동일함 # 파드 AGE 정보 확인 : 재생성된 파드 없음! kubectl get pod -A ...
EKS Control Plane 업그레이드를 성공적으로 완료했습니다. 이제 애드온 소프트웨어 업그레이드를 진행해 보겠습니다.
Control Plane Upgrade 후 상태 확인Cluster insights

Insight: EKS add-on version compatibility

Insight: Kubelet version skew

Insight: kube-proxy version skew

Insight: Deprecated APIs removed in Kubernetes v1.26


Argo CD 에 ui app(HPA 리소스) 상태 확인



# kubectl get hpa -n ui ui -o yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"autoscaling/v2beta2","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{},"labels":{"argocd.argoproj.io/instance":"ui"},"name":"ui","namespace":"ui"},"spec":{"maxReplicas":4,"minReplicas":1,"scaleTargetRef":{"apiVersion":"apps/v1","kind":"Deployment","name":"ui"},"targetCPUUtilizationPercentage":80}} creationTimestamp: "2025-03-25T02:40:17Z" labels: argocd.argoproj.io/instance: ui ... kubectl get hpa -n ui ui -o json | jq -r '.metadata.annotations."kubectl.kubernetes.io/last-applied-configuration"' | jq { "apiVersion": "autoscaling/v2beta2", "kind": "HorizontalPodAutoscaler", "metadata": { "annotations": {}, "labels": { "argocd.argoproj.io/instance": "ui" }, "name": "ui", "namespace": "ui" }, "spec": { "maxReplicas": 4, "minReplicas": 1, "scaleTargetRef": { "apiVersion": "apps/v1", "kind": "Deployment", "name": "ui" }, "targetCPUUtilizationPercentage": 80 } } # kubectl get hpa -n ui ui -o yaml | kubectl neat > hpa-ui.yaml kubectl convert -f hpa-ui.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: creationTimestamp: null labels: argocd.argoproj.io/instance: ui name: ui namespace: ui spec: maxReplicas: 4 metrics: - resource: name: cpu target: averageUtilization: 80 type: Utilization type: Resource minReplicas: 1 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: ui status: currentMetrics: null desiredReplicas: 0[2. 애드온] Upgrading EKS Addons*EKS 업그레이드의 일부로 클러스터에 설치된 애드온을 업그레이드해야 합니다. 애드온은 K8s 애플리케이션에 지원 운영 기능을 제공하는 소프트웨어로, 네트워킹, 컴퓨팅 및 스토리지를 위해 클러스터가 기본 AWS 리소스와 상호 작용할 수 있도록 하는 관찰 에이전트 또는 Kubernetes 드라이버와 같은 소프트웨어가 포함됩니다. 애드온 소프트웨어는 일반적으로 Kubernetes 커뮤니티, AWS와 같은 클라우드 공급자 또는 타사 공급업체에서 빌드하고 유지 관리합니다.
Amazon EKS 애드온을 사용하면 Amazon EKS 클러스터가 안전하고 안정적임을 지속적으로 보장하고 애드온을 설치, 구성 및 업데이트하는 데 필요한 작업량을 줄일 수 있습니다. Amazon EKS의 Amazon EKS 애드온 목록
이 섹션에서는 아래 추가 기능을 업그레이드합니다.
eksctl을 사용하여 EKS 1.25의 기존 애드온을 보려면 : 가능한 업그레이드 버전 정보 확인!
Copy# 가능한 업그레이드 버전 정보 확인 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 0terraform을 사용하여 CoreDNS , kube-proxy 및 VPC CNI 의 업그레이드를 살펴보겠습니다. 이를 위해 파일에서 CoreDNS, kube-proxy 및 VPC CNI의 버전을 업데이트하기만 하면 됩니다 /home/ec2-user/environment/terraform/addons.tf.
Copyeks_addons = { coredns = { addon_version = "v1.8.7-eksbuild.10" } kube-proxy = { addon_version = "v1.25.16-eksbuild.8" } vpc-cni = { most_recent = true } aws-ebs-csi-driver = { service_account_role_arn = module.ebs_csi_driver_irsa.iam_role_arn } }Amazon EKS는 AWS Managed Addons에 대한 주어진 K8s 버전에 대한 호환되는 애드온 버전을 나열하는 API를 제공합니다. 다음 명령을 사용하여 1.26 호환되는 coredns애드온 버전을 찾을 수 있습니다.
Copy# kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c 6 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.19.3-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-provisioner:v5.2.0-eks-1-32-7 6 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.25.16-minimal-eksbuild.8 8 amazon/aws-efs-csi-driver:v1.7.6 2 public.ecr.aws/eks/aws-load-balancer-controller:v2.7.1 # 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 | +-----------------+----------------------+ # aws eks describe-addon-versions --addon-name kube-proxy --kubernetes-version 1.26 --output table \ --query "addons[].addonVersions[:10].{Version:addonVersion,DefaultVersion:compatibilities[0].defaultVersion}" -------------------------------------------- | DescribeAddonVersions | +-----------------+------------------------+ | DefaultVersion | Version | +-----------------+------------------------+ | False | v1.26.15-eksbuild.24 | | False | v1.26.15-eksbuild.19 | | False | v1.26.15-eksbuild.18 | | False | v1.26.15-eksbuild.14 | | False | v1.26.15-eksbuild.10 | | False | v1.26.15-eksbuild.5 | | False | v1.26.15-eksbuild.2 | | False | v1.26.13-eksbuild.2 | | False | v1.26.11-eksbuild.4 | | False | v1.26.11-eksbuild.1 | +-----------------+------------------------+- 참고로 나머지 Addon 인 VPC CNI, EBS CSI Driver 는 현재 최신 버전 사용 중임 - 콘솔에서 addon 에서 Edit 로 버전 정보 확인.
위의 출력에서 최신 버전을 선택하여 addons.tf아래에 표시된 대로 파일에 업데이트합니다.
/home/ec2-user/environment/terraform/addons.tf
Copyeks_addons = { coredns = { addon_version = "v1.9.3-eksbuild.22" # Recommended version for EKS 1.26 } kube_proxy = { addon_version = "v1.26.15-eksbuild.24" # Recommended version for EKS 1.26 } vpc-cni = { most_recent = true } aws-ebs-csi-driver = { service_account_role_arn = module.ebs_csi_driver_irsa.iam_role_arn } }/home/ec2-user/environment/terraform/addons.tf변경 사항을 저장 하고 적용합니다.
Copy# 반복 접속 : 아래 coredns, kube-proxy addon 업그레이드 시 ui 무중단 통신 확인! aws eks update-kubeconfig --name eksworkshop-eksctl # 자신의 집 PC일 경우 kubectl get pod -n kube-system -l k8s-app=kube-dns kubectl get pod -n kube-system -l k8s-app=kube-proxy kubectl get pod -n kube-system -l 'k8s-app in (kube-dns, kube-proxy)' while true; do curl -s $UI_WEB ; date; kubectl get pod -n kube-system -l 'k8s-app in (kube-dns, kube-proxy)'; echo ; sleep 2; done # cd ~/environment/terraform/ terraform plan -no-color | tee addon.txt ... # module.eks_blueprints_addons.aws_eks_addon.this["coredns"] will be updated in-place ~ resource "aws_eks_addon" "this" { ~ addon_version = "v1.8.7-eksbuild.10" -> "v1.9.3-eksbuild.22" id = "eksworkshop-eksctl:coredns" tags = { "Blueprint" = "eksworkshop-eksctl" "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" } # (11 unchanged attributes hidden) # (1 unchanged block hidden) } # module.eks_blueprints_addons.aws_eks_addon.this["kube-proxy"] will be updated in-place ~ resource "aws_eks_addon" "this" { ~ addon_version = "v1.25.16-eksbuild.8" -> "v1.26.15-eksbuild.24" id = "eksworkshop-eksctl:kube-proxy" tags = { "Blueprint" = "eksworkshop-eksctl" "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" } ... Plan: 0 to add, 2 to change, 0 to destroy. # 1분 정도 이내로 롤링 업데이트 완료! terraform apply -auto-approve while true; do curl -s $UI_WEB ; date; kubectl get pod -n kube-system -l 'k8s-app in (kube-dns, kube-proxy)'; echo ; sleep 2; done ... {"status":"UP"}Tue Apr 1 16:28:31 UTC 2025 NAME READY STATUS RESTARTS AGE coredns-58cc4d964b-dknjc 1/1 Running 0 5s coredns-58cc4d964b-vmrfs 1/1 Running 0 5s kube-proxy-4sd9k 1/1 Running 0 5s kube-proxy-dqmdd 1/1 Running 0 2d10h kube-proxy-rdlrg 0/1 ContainerCreating 0 2s kube-proxy-t8p5x 1/1 Running 0 2d10h kube-proxy-w2sj8 1/1 Running 0 2d10h kube-proxy-wm2fs 1/1 Running 0 2d10h ... # kubectl get pod -n kube-system -l 'k8s-app in (kube-dns, kube-proxy)' NAME READY STATUS RESTARTS AGE coredns-58cc4d964b-dknjc 1/1 Running 0 50s coredns-58cc4d964b-vmrfs 1/1 Running 0 50s kube-proxy-4l4kh 1/1 Running 0 37s kube-proxy-4sd9k 1/1 Running 0 50s kube-proxy-7gx22 1/1 Running 0 43s kube-proxy-fz5hx 1/1 Running 0 41s kube-proxy-rdlrg 1/1 Running 0 47s kube-proxy-tcmrc 1/1 Running 0 34s # 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 ...[3.1 데이터부 - 관리형노드그룹] Upgrading EKS Managed Node groups** 총 30분 소요 이상 실습 포함‣관리형 노드 그룹 : 업그레이드 전략 - 기존 EKS 관리 노드 그룹 업데이드(인플레이스) vs 새로운 EKS 관리 노드 그룹으로 마이그레이션(블루-그린)‣- Amazon EKS 관리형 노드 그룹은 Amazon EKS 클러스터의 노드(Amazon EC2 인스턴스) 프로비저닝 및 수명 주기 관리를 자동화합니다.
- Amazon EKS 관리형 노드 그룹을 사용하면 Kubernetes 애플리케이션을 실행하기 위한 컴퓨팅 용량을 제공하는 Amazon EC2 인스턴스를 별도로 프로비저닝하거나 등록할 필요가 없습니다. 단일 작업으로 클러스터에 대한 노드를 생성, 자동 업데이트 또는 종료할 수 있습니다. 노드 업데이트 및 종료는 노드를 자동으로 비워 애플리케이션이 계속 사용 가능한 상태를 유지하도록 합니다.
- 모든 관리 노드는 Amazon EKS에서 관리하는 Amazon EC2 Auto Scaling 그룹의 일부로 프로비저닝됩니다. 인스턴스와 Auto Scaling 그룹을 포함한 모든 리소스는 AWS 계정 내에서 실행됩니다. 각 노드 그룹은 사용자가 정의한 여러 가용성 영역에서 실행됩니다.
[3.1-1 데이터부 - 관리형노드그룹 : 인플레이스 업그레이드] In-Place Managed Node group Upgrade* 20분 소요 실습 포함‣관리 노드 그룹 업그레이드도 완전히 자동화되어 점진적인 롤링 업데이트로 구현됩니다.
새 노드는 EC2 자동 스케일링 그룹에 프로비저닝되고 클러스터에 합류하며, as old nodes는 cordoned, drained, and removed
기본적으로 새 노드는 최신 EKS 최적화 AMI(Amazon Machine Image) 또는 선택적으로 사용자 지정 AMI를 사용합니다.
참고로, 사용자 지정 AMI를 사용할 때는 업데이트된 이미지를 직접 만들어야 하므로 노드 그룹 업그레이드의 일환으로 업데이트된 Launch Template 버전이 필요합니다.
관리형 노드 그룹 업데이트를 시작하면 Amazon EKS가 자동으로 노드를 업데이트하여 아래 설명된 대로 4가지 단계를 완료합니다.- 설정 단계:
- 확장 단계: 확장 단계에는 다음 단계가 있습니다.
- 업그레이드 단계*: 업그레이드 단계는 다음과 같은 단계로 구성됩니다.
- 축소 단계: 축소 단계에서는 Auto Scaling Group의 최대 크기와 원하는 크기를 하나씩 감소시켜 업데이트가 시작되기 전 값으로 돌아갑니다.
방법 : Terraform , 해당 방법으로 실제 업그레이드 실행! 20분 소요 실습 포함이제 우리는 마지막 랩에서 eks 클러스터 Control Plane을 버전 1.26으로 업그레이드했습니다. 다음 단계로, 우리는 워커 노드를 업그레이드해야 합니다. 이 랩에서 우리는 이 클러스터에 대해 프로비저닝된 관리 노드 그룹을 업그레이드할 것입니다. 우리는 접두사가 있는 두 개의 관리 노드 그룹을 가지고 있습니다:
- initial-<random_identifier>
blue-mng-<random_identifier>
eks 모듈인 eks_managed_node_groups 아래의 base.tf 에서 두 관리 노드 그룹의 구성을 볼 수 있습니다.
# cat base.tf ... eks_managed_node_group_defaults = { cluster_version = var.mng_cluster_version } eks_managed_node_groups = { # 버전 명시가 없으면, 상단 default 버전 사용 -> variables.tf 확인 initial = { instance_types = ["m5.large", "m6a.large", "m6i.large"] min_size = 2 max_size = 10 desired_size = 2 update_config = { max_unavailable_percentage = 35 } } 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" } ] }

관리 노드 그룹 업데이트를 수행할 때 다음 시나리오를 보여드리겠습니다.
- 특정 AMI ID 사용(사용자 정의 AMI와 같음) Using specific AMI ID (like custom AMIs)
- 지정된 K8s 버전에 대한 기본 AMI 사용 Using default AMI for given K8s version
이 실험실의 전제 조건으로 먼저 사용자 지정 AMI를 사용하여 신규 관리 노드 그룹을 생성해 보겠습니다.
이를 위해 kubernetes 버전 1.25의 ami_id를 가져오고 variable.tf 파일의 변수 ami_id를 결과 값으로 대체해 보겠습니다.
# aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --filters "Name=tag:Blueprint,Values=eksworkshop-eksctl" --output table ---------------------------------------------- | DescribeInstances | +------------------+-------------------------+ | blue-mng | ami-0078a0f78fafda978 | | initial | ami-0078a0f78fafda978 | | default-selfmng | ami-0ee947a6f4880da75 | | default-selfmng | ami-0ee947a6f4880da75 | | initial | ami-0078a0f78fafda978 | +------------------+-------------------------+ # kubectl get node --label-columns=eks.amazonaws.com/capacityType,node.kubernetes.io/lifecycle,karpenter.sh/capacity-type,eks.amazonaws.com/compute-type NAME STATUS ROLES AGE VERSION CAPACITYTYPE LIFECYCLE CAPACITY-TYPE COMPUTE-TYPE fargate-ip-10-0-14-140.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-2d5f260 fargate ip-10-0-14-113.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 spot ip-10-0-31-95.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ON_DEMAND ip-10-0-31-98.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 self-managed ip-10-0-41-47.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 self-managed ip-10-0-43-194.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ON_DEMAND ip-10-0-5-150.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ON_DEMAND kubectl get node -L eks.amazonaws.com/nodegroup,karpenter.sh/nodepool NAME STATUS ROLES AGE VERSION NODEGROUP NODEPOOL fargate-ip-10-0-14-140.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-2d5f260 ip-10-0-14-113.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 default ip-10-0-31-95.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 initial-20250330054903163800000029 ip-10-0-31-98.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ip-10-0-41-47.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ip-10-0-43-194.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 initial-20250330054903163800000029 ip-10-0-5-150.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 blue-mng-2025033005490317520000002b # kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami ip-10-0-31-95.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-43-194.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-5-150.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 # aws ssm get-parameter --name /aws/service/eks/optimized-ami/1.25/amazon-linux-2/recommended/image_id \ --region $AWS_REGION --query "Parameter.Value" --output text ami-0078a0f78fafda978 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아래와 같이 variable.tf 파일에서 ami_id를 업데이트합니다. custom ami id로 worker node를 upgrade한다.


base.tf사용자 정의 관리 노드 그룹을 프로비저닝하려면 다음 코드를 추가합니다 . → eks module > eks_managed_node_groups에 추가
custom = { instance_types = ["t3.medium"] min_size = 1 max_size = 2 desired_size = 1 update_config = { max_unavailable_percentage = 35 } ami_id = try(var.ami_id) enable_bootstrap_user_data = true }
Terraform Plan을 실행하고 적용합니다.
# 모니터링 aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq kubectl get node -L eks.amazonaws.com/nodegroup kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami while true; do aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; kubectl get node -L eks.amazonaws.com/nodegroup; echo; date ; echo ; kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami; echo; sleep 1; echo; done # 2분 정도 소요 terraform plan && terraform apply -auto-approve # while true; do aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; kubectl get node -L eks.amazonaws.com/nodegroup; echo; date ; echo ; kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami; echo; sleep 1; echo; done [ "default-selfmng-2025033005490319240000002d", "eks-blue-mng-2025033005490317520000002b-08caf2cc-56ba-c748-382a-af7f74831aef", "eks-custom-20250401164451243000000007-84caf91e-e66d-ee62-c230-74f9c78427f2", "eks-initial-20250330054903163800000029-c4caf2cc-56b2-1e0f-73c2-1fd4b5fd9aa0" ] NAME STATUS ROLES AGE VERSION NODEGROUP fargate-ip-10-0-14-140.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-2d5f260 ip-10-0-14-113.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ip-10-0-24-92.us-west-2.compute.internal Ready <none> 87s v1.25.16-eks-ae9a62a custom-20250401164451243000000007 ip-10-0-31-95.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 initial-20250330054903163800000029 ip-10-0-31-98.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ip-10-0-41-47.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 ip-10-0-43-194.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 initial-20250330054903163800000029 ip-10-0-5-150.us-west-2.compute.internal Ready <none> 2d10h v1.25.16-eks-59bf375 blue-mng-2025033005490317520000002b # kubectl describe node ip-10-0-24-92.us-west-2.compute.internal ... Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/instance-type=t3.medium beta.kubernetes.io/os=linux eks.amazonaws.com/capacityType=ON_DEMAND eks.amazonaws.com/nodegroup=custom-20250401164451243000000007 eks.amazonaws.com/nodegroup-image=ami-03db5eb228232c943 eks.amazonaws.com/sourceLaunchTemplateId=lt-013270b8fd9fa0e9f eks.amazonaws.com/sourceLaunchTemplateVersion=1 failure-domain.beta.kubernetes.io/region=us-west-2 failure-domain.beta.kubernetes.io/zone=us-west-2b k8s.io/cloud-provider-aws=a94967527effcefb5f5829f529c0a1b9 kubernetes.io/arch=amd64 kubernetes.io/hostname=ip-10-0-24-92.us-west-2.compute.internal kubernetes.io/os=linux node.kubernetes.io/instance-type=t3.medium ... kubectl get pod -A -owide | grep 10-0-24-92 kube-system aws-node-tt4lp 2/2 Running 0 4m20s 10.0.44.132 ip-10-0-44-132.us-west-2.compute.internal <none> <none> kube-system ebs-csi-node-msbmj 3/3 Running 0 4m20s 10.0.39.97 ip-10-0-44-132.us-west-2.compute.internal <none> <none> kube-system efs-csi-node-cb58m 3/3 Running 0 4m20s 10.0.44.132 ip-10-0-44-132.us-west-2.compute.internal <none> <none> kube-system kube-proxy-7ddnw 1/1 Running 0 4m20s 10.0.44.132 ip-10-0-44-132.us-west-2.compute.internal <none> <none>


초기 관리 노드그룹에는 정의된 클러스터 버전이 없으며 기본적으로 eks_managed_node_group_defaults에 정의된 클러스터 버전을 사용하도록 설정됩니다.
eks_managed_node_group_defaults 클러스터_버전의 값은 variable.tf 의 변수 mng_cluster_version에 정의되어 있습니다.
variable.tf 에서 변수 mng_cluster_version을 "1.25"에서 "1.26"으로 변경하고 테라폼을 실행하면 됩니다.

# terraform plan -no-color > plan-output.txt # plan-output.txt 내용 확인 # module.eks.module.eks_managed_node_group["initial"].aws_eks_node_group.this[0] will be updated in-place ~ resource "aws_eks_node_group" "this" { id = "eksworkshop-eksctl:initial-2025032502302076080000002c" tags = { "Blueprint" = "eksworkshop-eksctl" "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" "Name" = "initial" "karpenter.sh/discovery" = "eksworkshop-eksctl" } ~ version = "1.25" -> "1.26" ...이 계획에 따라 initial managed node group은 1.26 버전으로 업그레이드되지만, custom managed nodegroup 을 프로비저닝하는 동안 특정 AMI를 정의했기 때문에 업그레이드 되지 않습니다.
따라서 커스텀 관리 노드 그룹과 같이 커스텀 AMI로 구성된 관리 노드 그룹이 있는 경우 업그레이드된 Kubernetes 버전에 커스텀 AMI를 제공하여 관리 노드 그룹을 업그레이드할 수 있습니다.
Lets upgrade the initial and custom managed node groups to latest cluster version.
kubernetes 버전 1.26에 대해 ami_id를 검색한 후 variable.tf 에서 다음과 같은 변경 사항을 적용합니다.
# 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-086414611b43bb691mng_cluster_version 변수를 에서 . 1.25 -> 1.26 으로 변경합니다.
ami_id 변수를 ami-0078a0f78fafda978에서 ami-086414611b43bb691로 변경합니다.

Terraform 계획을 실행하고 적용하세요

Copy# 모니터링 while true; do aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; kubectl get node -L eks.amazonaws.com/nodegroup; echo; date ; echo ; kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami; echo; sleep 1; echo; done ... ip-10-0-10-86.us-west-2.compute.internal Ready <none> 95s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-13-217.us-west-2.compute.internal Ready,SchedulingDisabled <none> 26h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-17-199.us-west-2.compute.internal Ready <none> 3m41s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-19-132.us-west-2.compute.internal Ready <none> 5m53s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-2-59.us-west-2.compute.internal Ready,SchedulingDisabled <none> 22m v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-26-240.us-west-2.compute.internal Ready <none> 4m46s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-29-245.us-west-2.compute.internal Ready <none> 5m51s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-3-168.us-west-2.compute.internal Ready <none> 26h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-33-7.us-west-2.compute.internal Ready <none> 4m56s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-40-197.us-west-2.compute.internal Ready <none> 2m45s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-41-92.us-west-2.compute.internal Ready <none> 5m54s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-42-84.us-west-2.compute.internal Ready,SchedulingDisabled <none> 26h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-9-129.us-west-2.compute.internal Ready <none> 3m47s v1.26.15-eks-59bf375 ami-086414611b43bb691 ... ... ip-10-0-2-59.us-west-2.compute.internal NotReady,SchedulingDisabled <none> 23m v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ... # 20분 소요 : UI 웹과 liveness 반복 접속도 해보자, 노드에 labels 와 taint 변화도 모니터링 해보자. terraform plan && terraform apply -auto-approve ...
완료되면 Amazon EKS 콘솔에서 initial and custom manage node groups의 변경 사항을 확인할 수 있습니다.
초기 및 맞춤형 관리 노드그룹 kubernetes 버전이 1.26임을 알 수 있습니다.

custom 은 실습 동작 확인했으니, 다음 실습을 위해서 제거하자.
다음 변경 사항을 적용 base.tf하고 terraform plan과 terraform apply를 실행합니다.
Copyterraform plan && terraform apply -auto-approve[3.1-2 데이터부 - 관리형노드그룹 : 블루-그린 업그레이드] Blue Green approach for Managed Node group Upgrade* 10분 소요 실습 포함관리 노드 그룹을 업데이트하기 위해 Blue / Green 전략을 사용할 수도 있습니다.
우리는 eks Control Plane 버전을 업데이트한 후 새로운 관리 노드 그룹을 생성함으로써 이를 수행합니다.
지난 실험[3.1-1]에서는 Blue-mng 관리 노드 그룹을 업데이트하지 않았습니다.
Blue-mng 관리 노드 그룹의 구성을 보면, 이 노드 그룹에 할당된 노드들이 특정 테인트와 라벨을 가지고 있으며, 하나의 특정 가용성 구역에 할당되도록 구성되어 있음을 알 수 있습니다.
Here we have followed the recommended best practice to provision managed node group for stateful workloads, i.e.
상태 저장 워크로드를 위한 관리 노드 그룹은 가용 영역(AZ)별로 프로비저닝되어야 합니다. Managed node groups for stateful workloads should be provisioned per availability zone (AZ).
이 실험실에서는 stateful 워크로드의 마이그레이션을 시연하고 있습니다.
Blue-mng 관리 노드 그룹의 노드에서 실행되는 my-sql 포드로 구성된 Orders 애플리케이션 포드가 있습니다.
우리는 blue-mng와 유사한 구성을 가진 새로운 관리 노드 그룹 green-mng을 만들 것입니다.
Green-mng는 eks_managed_node_group_defaults에 제공된 클러스터 버전(즉, 1.26)과 Blue-mng과 동일한 가용성 영역에서 프로비저닝됩니다.
그 후에, 우리는 blue-mng을 삭제할 것입니다.
blue-mng가 자동으로 cordoned되고 drained되며, 주문 앱 포드가 green-mng에서 프로비저닝되는 것을 볼 수 있습니다.
It will automatically cordoned and drained blue-mng nodes and we will see orders app pods will get provisioned on green-mng.
다음 Terraform 구성에서 찾을 수 base.tf있습니다 blue-mng.
Copyblue-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]] # 해당 MNG은 프라이빗서브넷1 에서 동작(ebs pv 사용 중) taints = [ { key = "dedicated" value = "OrdersApp" effect = "NO_SCHEDULE" } ] } # terraform state show 'module.vpc.aws_subnet.private[0]' terraform state show 'module.vpc.aws_subnet.private[1]' terraform state show 'modle.vpc.aws_subnet.private[2]'Lets get the node provisioned for this node group.
# kubectl get nodes -l type=OrdersMNG NAME STATUS ROLES AGE VERSION ip-10-0-5-150.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 # Check if the node have specific taints applied to it. kubectl get nodes -l type=OrdersMNG -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints[?(@.effect=='NoSchedule')]}{\"\n\"}{end}" ip-10-0-5-150.us-west-2.compute.internal {"effect":"NoSchedule","key":"dedicated","value":"OrdersApp"} # Check which pods are running on this node. # Non-terminated Pods: in above output, kube-system pods and orders app pods running on this node. kubectl describe node -l type=OrdersMNG ... Labels: beta.kubernetes.io/arch=amd64 ... type=OrdersMNG Taints: dedicated=OrdersApp:NoSchedule ... Non-terminated Pods: (6 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age --------- ---- ------------ ---------- --------------- ------------- --- kube-system aws-node-pnx48 50m (2%) 0 (0%) 0 (0%) 0 (0%) 21h kube-system ebs-csi-node-qqmsh 30m (1%) 0 (0%) 120Mi (1%) 768Mi (11%) 21h kube-system efs-csi-node-rcggq 0 (0%) 0 (0%) 0 (0%) 0 (0%) 21h kube-system kube-proxy-kxvh5 100m (5%) 0 (0%) 0 (0%) 0 (0%) 9h orders orders-5b97745747-mxg72 250m (12%) 0 (0%) 1Gi (14%) 1Gi (14%) 21h orders orders-mysql-b9b997d9d-hdt9m 0 (0%) 0 (0%) 0 (0%) 0 (0%) 15h ... # kubectl get pvc -n orders NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE order-mysql-pvc Bound pvc-c464ccf7-e93c-4311-a772-7dcb529d3f51 4Gi RWO gp3 2d11h # order deployment에는 아래와 같이 toleration을 주어서, OrdersMNG Node에 배포 될 수 있게한다. cat eks-gitops-repo/apps/orders/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: orders ... spec: nodeSelector: type: OrdersMNG tolerations: - key: "dedicated" operator: "Equal" value: "OrdersApp" effect: "NoSchedule" # order의 mysql deployment 역시 toleration을 통해서 OrderMNG Node에 배포 될 수 있게한다. cat eks-gitops-repo/apps/orders/deployment-mysql.yaml apiVersion: apps/v1 kind: Deployment metadata: name: orders-mysql ... spec: nodeSelector: type: OrdersMNG tolerations: - key: "dedicated" operator: "Equal" value: "OrdersApp" effect: "NoSchedule"Now Lets create a new managed node group green-mng by adding below code in base.tf file under eks module, eks_managed_node_groups
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" } ] } # 위에서 variables를 변경하여 green-mng는 version을 설정하지 않았으므로 1.26으로 생성된다. green-mng={ instance_types = ["m5.large", "m6a.large", "m6i.large"] subnet_ids = [module.vpc.private_subnets[0]] min_size = 1 max_size = 2 desired_size = 1 update_config = { max_unavailable_percentage = 35 } labels = { type = "OrdersMNG" } taints = [ { key = "dedicated" value = "OrdersApp" effect = "NO_SCHEDULE" } ] } }We have made following changes in base.tf file. Run terraform plan and apply after making the changes
Copy# 모니터링 while true; do aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; kubectl get node -L eks.amazonaws.com/nodegroup; echo; date ; echo ; kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami; echo; sleep 1; echo; done # 3분 소요 terraform plan && terraform apply -auto-approve
You will see green-mng will be created with latest control plane version in Amazon EKS console .
# Lets get the nodes with labels type=OrdersMNG. kubectl get node -l type=OrdersMNG -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME ip-10-0-10-196.us-west-2.compute.internal Ready <none> 2m25s v1.26.15-eks-59bf375 10.0.10.196 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25 ip-10-0-3-199.us-west-2.compute.internal Ready <none> 21h v1.25.16-eks-59bf375 10.0.3.199 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25 kubectl get node -l type=OrdersMNG -L topology.kubernetes.io/zone NAME STATUS ROLES AGE VERSION ZONE ip-10-0-10-196.us-west-2.compute.internal Ready <none> 3m21s v1.26.15-eks-59bf375 us-west-2a ip-10-0-3-199.us-west-2.compute.internal Ready <none> 21h v1.25.16-eks-59bf375 us-west-2a # Check if this node have same taints applied to it. kubectl get nodes -l type=OrdersMNG -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints[?(@.effect=='NoSchedule')]}{\"\n\"}{end}" ip-10-0-10-196.us-west-2.compute.internal {"effect":"NoSchedule","key":"dedicated","value":"OrdersApp"} ip-10-0-3-199.us-west-2.compute.internal {"effect":"NoSchedule","key":"dedicated","value":"OrdersApp"}동일한 레이블과 테인트를 가진 두 개의 노드가 있습니다. Blue-mng 관리 노드 그룹 노드는 버전 v1.25.16-eks-ae9a62a에 있고 Green-mng 관리 노드 그룹 노드는 버전 v1.26.15-eks-ae9a62a에 있습니다.
Copy# Blue-mng과 Green-mng 관리 그룹 이름을 각각 BLUE_MNG 변수와 GREEN_MNG 변수로 내보냅니다. export BLUE_MNG=$(aws eks list-nodegroups --cluster-name eksworkshop-eksctl | jq -c .[] | jq -r 'to_entries[] | select( .value| test("blue-mng*")) | .value') echo $BLUE_MNG blue-mng-20250325023020754500000029 export GREEN_MNG=$(aws eks list-nodegroups --cluster-name eksworkshop-eksctl | jq -c .[] | jq -r 'to_entries[] | select( .value| test("green-mng*")) | .value') echo $GREEN_MNG green-mng-20250401173250155100000007Blue-mng 관리 노드 그룹을 삭제합니다. It will automatically cordon and drain the blue managed node group nodes and orders app pods will get scheduled on to green managed node group nodes.
클러스터 업그레이드 준비 실험실에서 주문 시 PodDisruptionBudget(PDB)을 생성했다면, 배포가 1개의 복제본으로 설정되고 PDB가 minAvailable=1로 설정될 때 노드 그룹 삭제 프로세스가 차단됩니다. 따라서 이 문제를 해결하기 위해 복제본을 2개로 늘립니다.
# kubectl get pdb -n orders NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE orders-pdb 1 N/A 0 15h # 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 # sync 를 해도 HPA로 무시로 인해 파드는 1개 유지 상태 argocd app sync orders # apps 설정에 deploy replicas 무시 설정되어 있으니, 아래처럼 직접 증가해둘것 (이미 위에서 코드상에는 2로 변경) # (실행 과정 중) orders 파드가 다른 노드로 옮겨감.. 실행 전에 replicas=2로 실행해두어서 좀 더 안정성 확보 kubectl scale deploy -n orders orders --replicas 2 # kubectl get deploy -n orders kubectl get pod -n orders -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES orders-5b97745747-b5ssr 1/1 Running 2 (2d11h ago) 2d11h 10.0.8.119 ip-10-0-5-150.us-west-2.compute.internal <none> <none> orders-5b97745747-r66kj 0/1 Running 0 15s 10.0.13.122 ip-10-0-15-147.us-west-2.compute.internal <none> <none>Make the following changes in base.tf and run terraform plan and apply

# kubectl get node -l type=OrdersMNG kubectl get pod -n orders -l app.kubernetes.io/component=service -owide kubectl get deploy -n orders orders kubectl get pdb -n orders aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq while true; do kubectl get node -l type=OrdersMNG; echo ; kubectl get pod -n orders -l app.kubernetes.io/component=service -owide ; echo ; kubectl get deploy -n orders orders; echo ; kubectl get pdb -n orders; echo ; aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; date ; done # 10분 정도 소요 cd ~/environment/terraform/ terraform plan && terraform apply -auto-approve # 신규(버전) 노드 확인 kubectl get node -l eks.amazonaws.com/nodegroup=$GREEN_MNG NAME STATUS ROLES AGE VERSION ip-10-0-15-147.us-west-2.compute.internal Ready <none> 6m24s v1.26.15-eks-59bf375 aws eks list-nodegroups --cluster-name eksworkshop-eksctl { "nodegroups": [ "green-mng-20250325235742179300000007", "initial-2025032502302076080000002c" ] } # 기존 노드 스케줄 중지 NAME STATUS ROLES AGE VERSION NODEGROUP fargate-ip-10-0-14-140.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-2d5f260 ip-10-0-14-113.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-15-147.us-west-2.compute.internal Ready <none> 7m16s v1.26.15-eks-59bf375 green-mng-20250401173250155100000007 ip-10-0-31-98.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-41-47.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-43-237.us-west-2.compute.internal Ready <none> 46m v1.26.15-eks-59bf375 initial-20250330054903163800000029 ip-10-0-5-150.us-west-2.compute.internal Ready,SchedulingDisabled <none> 2d11h v1.25.16-eks-59bf375 blue-mng-2025033005490317520000002b ip-10-0-5-3.us-west-2.compute.internal Ready <none> 47m v1.26.15-eks-59bf375 initial-20250330054903163800000029 Tue Apr 1 17:41:16 UTC 2025 ip-10-0-15-147.us-west-2.compute.internal Ready <none> 7m18s v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-43-237.us-west-2.compute.internal Ready <none> 46m v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-5-150.us-west-2.compute.internal Ready,SchedulingDisabled <none> 2d11h v1.25.16-eks-59bf375 ami-0078a0f78fafda978 ip-10-0-5-3.us-west-2.compute.internal Ready <none> 47m v1.26.15-eks-59bf375 ami-086414611b43bb691 # ip-10-0-5-150.us-west-2.compute.internal(=Blue-mng)는 cordon -> drain되어 사라져서 현재 모두 ip-10-0-15-147.us-west-2.compute.internal(=Green-mng) node로 옮겨졌다. kubectl get po -n orders -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES orders-5b97745747-lrgm8 1/1 Running 2 (98s ago) 117s 10.0.12.7 ip-10-0-15-147.us-west-2.compute.internal <none> <none> orders-5b97745747-r66kj 1/1 Running 0 4m39s 10.0.13.122 ip-10-0-15-147.us-west-2.compute.internal <none> <none> orders-mysql-b9b997d9d-l8ns8 1/1 Running 0 117s 10.0.4.58 ip-10-0-15-147.us-west-2.compute.internal <none> <none> kubectl get deploy -n orders NAME READY UP-TO-DATE AVAILABLE AGE orders 2/2 2 2 2d11h orders-mysql 1/1 1 1 2d11h kubectl get pdb -n orders NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE orders-pdb 1 N/A 1 118m # 이제 blue-mng node는 SchedulingDisabled(=cordon) NotReady(=drain) 상태를 지나 완전히 삭제되었다. while true; do aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[*].AutoScalingGroupName' --output json | jq; echo ; kubectl get node -L eks.amazonaws.com/nodegroup; echo; date ; echo ; kubectl get node -L eks.amazonaws.com/nodegroup-image | grep ami; echo; sleep 1; echo; done NAME STATUS ROLES AGE VERSION NODEGROUP fargate-ip-10-0-14-140.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-2d5f260 ip-10-0-14-113.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-15-147.us-west-2.compute.internal Ready <none> 11m v1.26.15-eks-59bf375 green-mng-20250401173250155100000007 ip-10-0-31-98.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-41-47.us-west-2.compute.internal Ready <none> 2d11h v1.25.16-eks-59bf375 ip-10-0-43-237.us-west-2.compute.internal Ready <none> 51m v1.26.15-eks-59bf375 initial-20250330054903163800000029 ip-10-0-5-3.us-west-2.compute.internal Ready <none> 52m v1.26.15-eks-59bf375 initial-20250330054903163800000029 Tue Apr 1 17:45:43 UTC 2025 ip-10-0-15-147.us-west-2.compute.internal Ready <none> 11m v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-43-237.us-west-2.compute.internal Ready <none> 51m v1.26.15-eks-59bf375 ami-086414611b43bb691 ip-10-0-5-3.us-west-2.compute.internal Ready <none> 52m v1.26.15-eks-59bf375 ami-086414611b43bb691 [ "default-selfmng-2025033005490319240000002d", "eks-green-mng-20250401173250155100000007-dccaf934-dd6f-f455-4294-7f7401c30641", "eks-initial-20250330054903163800000029-c4caf2cc-56b2-1e0f-73c2-1fd4b5fd9aa0" ] # 이벤트 로그 확인 kubectl get events --sort-by='.lastTimestamp' --watch 7m34s Normal Unconsolidatable node/ip-10-0-14-113.us-west-2.compute.internal SpotToSpotConsolidation is disabled, can't replace a spot node with a spot node 7m34s Normal NodeNotSchedulable node/ip-10-0-5-150.us-west-2.compute.internal Node ip-10-0-5-150.us-west-2.compute.internal status is now: NodeNotSchedulable 7m34s Normal Unconsolidatable nodeclaim/default-lwqjd SpotToSpotConsolidation is disabled, can't replace a spot node with a spot node 5m46s Normal NodeNotReady node/ip-10-0-5-150.us-west-2.compute.internal Node ip-10-0-5-150.us-west-2.compute.internal status is now: NodeNotReady 5m43s Normal DeletingNode node/ip-10-0-5-150.us-west-2.compute.internal Deleting node ip-10-0-5-150.us-west-2.compute.internal because it does not exist in the cloud provider 5m41s Normal RemovingNode node/ip-10-0-5-150.us-west-2.compute.internal Node ip-10-0-5-150.us-west-2.compute.internal event: Removing Node ip-10-0-5-150.us-west-2.compute.inter이 Lab에서는 1.26 EKS AMI를 가진 새로운 Green-mng 관리 노드 그룹을 생성하고 기존 Blue-mng 노드 그룹을 삭제하여 포드를 새로운 노드 그룹으로 이동시켰습니다. EKS 관리 노드 그룹 서비스는 자동으로 노드를 코드화하고 배수하며, 포드 중단 예산을 사용하여 애플리케이션 다운타임을 최소화했습니다.
In this lab, we started with creating a new green-mng managed node group with 1.26 EKS AMI and deleted existing blue-mng node group to move the pods to the new node group. EKS Managed node group service automatically cordoned and drained the nodes and Pod Disruption Budgets are used to minimize the application downtime.

- (옵션) 혹시 catalog-mysql-0 파드(EBS PVC)가 배포된 노드들의 AZ와 맞지 않을 경우, 그냥 임시로 ASG를 3대로 늘려서 해결해두자.
[3.2 데이터부 - 카펜터노드] Upgrading Karpenter managed nodes** 10분 소요 (예상) 실습 포함Karpenter는 집계된 CPU, 메모리, 볼륨 요청 및 기타 Kubernetes 스케줄링 제약(예: 친화도 및 포드 토폴로지 확산 제약)을 기반으로 스케줄링 불가능한 포드에 대응하여 적절한 크기의 노드를 제공하는 오픈 소스 클러스터 오토스케일러로, 인프라 관리를 간소화합니다.
또한 Karpenter는 노드 그룹 및 Amazon EC2 Auto Scaling Group과 같은 외부 인프라와 용량 관리를 조정하지 않기 때문에 운영 프로세스에 대한 다른 관점을 도입하여 작업자 노드 구성 요소와 운영 체제를 최신 보안 패치 및 기능으로 최신 상태로 유지합니다.
AWS는 새로운 Kubernetes 버전뿐만 아니라 패치 및 CVE(일반 취약점 및 노출)를 위한 AMI를 출시합니다. 다양한 Amazon EKS에 최적화된 AMI 중에서 선택할 수 있습니다. 또는 자신만의 맞춤형 AMI를 사용할 수도 있습니다.
현재 Karpenter에서는 EC2NodeClass 리소스가 amiFamily 값 AL2, AL2023, Bottlerocket, Ubuntu, Windows2019, Windows2022 및 Custom을 지원합니다. amiFamily of Custom을 선택하면 어떤 사용자 지정 AMI를 사용할지 Karpenter에 알려주는 amiSelectorTerms를 지정해야 합니다.
Karpenter는 Karpenter를 통해 프로비저닝된 Kubernetes 작업자 노드를 패치하는 데 Drift 또는 타이머(expireAfter)와 같은 기능을 사용합니다.
- Drift
Karpenter는 롤링 배포 후 Drift를 사용하여 Kubernetes 노드를 업그레이드합니다.
Karpenter를 통해 프로비저닝된 Kubernetes 노드가 원하는 사양에서 벗어난 경우, Karpenter는 먼저 새로운 노드를 프로비저닝하고 이전 노드에서 포드를 제거한 다음 종료합니다.
노드가 디프로비전됨에 따라 노드는 새로운 포드 스케줄링을 방지하기 위해 코드화되고 Kubernetes Eviction API를 사용하여 포드가 퇴거됩니다.
EC2NodeClass에서는 amiFamily가 필수 필드이며, 자신의 AMI 값인 EKS 최적화 AMI를 사용할 수 있습니다.
AMI의 드리프트는 두 가지 동작이 있으며, 아래에 자세히 설명되어 있습니다.
- Drift with specified AMI values 지정된 AMI 값을 사용한 드리프트:
- Drift with Amazon EKS optimized AMIs Amazon EKS 최적화 AMI를 사용한 드리프트:
TTL (expireAfter) to automatically delete nodes from the cluster 클러스터에서 노드를 자동으로 삭제
프로비저닝된 노드에서 ttl을 사용하여 워크로드 포드가 없거나 만료 시간에 도달한 노드를 삭제할 시기를 설정할 수 있습니다. 노드 만료는 업그레이드 수단으로 사용할 수 있으므로 노드가 폐기되고 업데이트된 버전으로 대체될 수 있습니다.
Karpenter는 NodePool의 spec.druption.expireAfter 값에 따라 노드가 만료된 것으로 표시하고 설정된 시간(초)이 지나면 노드를 중단합니다.
보안 문제로 인해 노드 만료를 사용하여 주기적으로 노드를 재활용할 수 있습니다.
Copykubectl get nodepools default -o jsonpath={.spec.disruption} | jq { "budgets": [ { "nodes": "10%" } ], "consolidationPolicy": "WhenUnderutilized", "expireAfter": "Never" }- Disruption Budgets
이러한 karpenter 중단을 제어하려는 특정 시나리오가 있습니다. 예를 들어:
- 미션 크리티컬 워크로드를 실행 중인데 자발적인 중단으로 인해 노드를 재활용하고 싶지 않을 때.
- 100개의 드리프트 또는 만료가 한 번에 정렬되어 모든 활성 노드를 함께 회전하는 시나리오의 경우. 이러한 시나리오에서는 중단되는 활성 노드의 수와 중단 시점을 제어해야 합니다.
우리는 NodePool의 spec.disruption.budgets를 통해 Karpenter disruption 를 rate limit 할 수 있습니다.
Disruption Budgets 을 사용하면 새로운 AMI를 가진 노드로의 업그레이드 속도를 늦추거나(일정을 사용하여) 선택된 날짜와 시간 동안에만 업그레이드가 이루어지도록 할 수 있습니다.
이렇게 하면 나쁜 AMI가 배포되는 것을 방지할 수는 없지만, 노드가 업그레이드되는 시기를 제어할 수 있지만, 롤아웃 문제에 더 많은 시간을 대응할 수 있습니다.
Disruption Budgets은 노드가 중단될 수 있는 시기와 정도를 제한합니다. 노드(한 번에 중단될 수 있는 노드의 비율 또는 수)와 일정(노드 중단으로 인한 특정 시간 제외)에 따라 중단을 방지할 수 있습니다.
정의되지 않으면 Karpenter는 노드가 있는 budgets 10%로 기본 설정됩니다.
budgets은 어떤 이유로든 적극적으로 삭제되는 노드를 고려하며, 만료, 드리프트, 공백 및 통합을 통해 자발적으로 노드를 방해하지 못하도록 Karpenter를 차단합니다.
예시)
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: - nodes: 0이 budgets으로 karpenter는 이 노드풀을 통해 프로비저닝된 노드가 자발적인 중단으로 간주되는 것을 방지할 수 있습니다.
This budget allow karpenter to disrupt active nodes one at a time. 한번에 1대씩 노드만 중단.
CopyapiVersion: 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: - nodes: "1"이러한 예산으로 인해 karpenter는 평일 영업 시간 동안 노드의 프로비저닝을 해제할 수 없습니다. 그외 시간에 10개의 노드만 동시에 프로비저닝을 해제할 수 있습니다
With these budgets, karpenter is not allowed to de-provision any node on weekdays during business hours. Every other time, only allow 10 nodes to be de-provisioned simultaneously
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: 10As prerequisite for this lab, lets clone codecommit repo eks-gitops-rep (if you haven't already)
# In this lab, we have already installed karpenter and applied default NodePool and EC2NodeClass on the cluster. 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-25T02:40:15Z Generation: 1 Resource Version: 6130 UID: 7e081e92-bcfb-4e88-a611-026349b02dd9 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: 25 Cpu: 4 Ephemeral - Storage: 20959212Ki Memory: 7766420Ki Pods: 58 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-25T02:40:15Z Finalizers: karpenter.k8s.aws/termination Generation: 1 Resource Version: 531983 UID: 1dc1bfc4-adfe-4889-84c5-05d57c7e768d 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-25T02:40:16Z Message: Reason: Ready Status: True Type: Ready Instance Profile: eksworkshop-eksctl_4067990795380418201 Security Groups: Id: sg-009b495bdf238c9dd Name: eksworkshop-eksctl-node-2025032502202294260000000c Id: sg-09f8b41af6cadd619 Name: eks-cluster-sg-eksworkshop-eksctl-1769733817 Id: sg-0ef166af090e168d5 Name: eksworkshop-eksctl-cluster-2025032502202287160000000b Subnets: Id: subnet-047ab61ad85c50486 Zone: us-west-2b Zone ID: usw2-az1 Id: subnet-01bbd11a892aec6ee Zone: us-west-2a Zone ID: usw2-az2 Id: subnet-0aeb12f673d69f7c5 Zone: us-west-2c Zone ID: usw2-az3 Events: <none>기본 노드풀 및 ec2 nod 클래스의 출력에서 다음을 확인할 수 있습니다:
- 이 노드풀을 사용하면 Spec.Druption.Budgets에 따라 중단 시 10% 노드가 재활용되는 기본 예산이 적용됩니다.
- 이 노드풀에 대해 karpenter를 통해 프로비저닝된 노드에는 Team: 체크아웃 라벨이 Spec.Template.Metadata.Labels에 따라 표시되며, 이들 노드에는 Spec.Template.Spec.Taints에 따라 태그가 적용됩니다.
- 이 노드풀은 Spec.Template.Spec.NodeClass Ref에 따라 기본 EC2NodeClass를 사용하고 있습니다.
- 이 기본 EC2NodeClass 사양을 사용하여 노드풀은 아미드 ami-03db5eb 228232c943을 사용하여 노드를 프로비저닝하고 있습니다.
node selector label team=checkou와 default nodepool을 통해 프로비저닝된 노드에 tolerations to tolerate taints를 가진 체크아웃 앱 포드를 프로비저닝했습니다.
Checkout 앱은 포드에 지속적인 볼륨이 부착된 stateful 애플리케이션입니다.
이 실험실에서는 상태 저장 워크로드를 실행하는 카펜터를 통해 프로비저닝된 노드를 업그레이드하는 방법을 시연할 것입니다.
이를 위해 kubernetes 버전 1.26용으로 빌드된 AMI ID를 가진 eks-gitops-repo/apps/karpenter 폴더의 기본 eks-ec2nc.yaml 파일에서 AMI ID를 변경하고 eks-gitops-repo의 변경 사항을 푸시할 것입니다.
Argo-CD를 통해 변경 사항이 동기화되면 Karpenter 컨트롤러는 노드가 드리프트되었음을 자동으로 감지하여 드리프트된 노드를 최신 구성의 노드로 프로비저닝하는 데 방해가 될 것입니다.
논의한 바와 같이, 중단되는 노드의 수를 제어하거나 특정 시간에만 노드를 중단시키는 시나리오가 있습니다.
이 실험실에서는 Karpenter가 다른 노드를 프로비저닝하여 예정에 없던 체크아웃 포드를 실행할 수 있도록 체크아웃 앱을 확장할 것입니다. 그
런 다음 한 번에 하나씩 노드를 중단시키기 위한 중단 예산을 정의합니다.
Karpenter 컨트롤러는 한 번에 하나씩 드리프트를 통해 노드를 중단합니다.
이 노드풀에 대해 카펜터를 통해 노드를 프로비저닝해 보겠습니다
# aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --filters "Name=tag:Blueprint,Values=eksworkshop-eksctl" --output table # 기본 노드풀을 통해 프로비저닝된 노드가 버전 v1.25.16-eks-59bf375에 있는 것을 확인할 수 있습니다. kubectl get nodes -l team=checkout NAME STATUS ROLES AGE VERSION ip-10-0-39-95.us-west-2.compute.internal Ready <none> 24h v1.25.16-eks-59bf375 # Check taints applied on the nodes. kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints}{\"\n\"}{end}" kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints[?(@.effect=='NoSchedule')]}{\"\n\"}{end}" ip-10-0-39-95.us-west-2.compute.internal {"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"} # kubectl get pods -n checkout -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES checkout-558f7777c-fs8dk 1/1 Running 0 24h 10.0.39.105 ip-10-0-39-95.us-west-2.compute.internal <none> <none> checkout-redis-f54bf7cb5-whk4r 1/1 Running 0 24h 10.0.41.7 ip-10-0-39-95.us-west-2.compute.internal <none> <none> # 모니터링 kubectl get nodeclaim kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints}{\"\n\"}{end}" kubectl get pods -n checkout -o wide while true; do kubectl get nodeclaim; echo ; kubectl get nodes -l team=checkout; echo ; kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints}{\"\n\"}{end}"; echo ; kubectl get pods -n checkout -o wide; echo ; date; sleep 1; echo; done결제 앱 포드가 카펜터에서 프로비저닝한 노드에서 실행되고 있는 것을 볼 수 있습니다.
체크아웃 애플리케이션을 확장해 보겠습니다. 이를 위해 아래와 같이 eks-gitops-repo/apps/checkout 폴더의 deposition.yaml 파일에서 복제본을 1에서 15으로 변경합니다.

변경이 완료되면 저장소에 변경 사항을 커밋하고 푸시한 후 Argo-cd가 변경 사항을 동기화할 때까지 기다립니다.
# while true; do kubectl get nodeclaim; echo ; kubectl get nodes -l team=checkout; echo ; kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints}{\"\n\"}{end}"; echo ; kubectl get pods -n checkout -o wide; echo ; date; sleep 1; echo; done # cd ~/environment/eks-gitops-repo git add apps/checkout/deployment.yaml git commit -m "scale checkout app" git push --set-upstream origin main # You can force the sync using ArgoCD console or following command: argocd app sync checkout # LIVE(k8s)에 직접 scale 실행 kubectl scale deploy checkout -n checkout --replicas 10 # 현재는 1.25.16 2대 사용 중 확인 # Karpenter will scale looking at the aggregate resource requirements of unscheduled pods. We will see we have now two nodes provisioned via karpenter. kubectl get nodes -l team=checkout NAME STATUS ROLES AGE VERSION ip-10-0-24-213.us-west-2.compute.internal Ready <none> 62s v1.25.16-eks-59bf375 ip-10-0-39-95.us-west-2.compute.internal Ready <none> 24h v1.25.16-eks-59bf375 # Lets get the ami id for the AMI build for kubernetes version 1.26. 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
[파일 수정] We are making following changes in the default-ec2nc.yaml and default-np.yaml in eks-gitops-repo/app/karpenter folder as shown below.
우리는 spec.amiSelectorTerms의 AMI ID를 default-ec2nc.yaml파일의 위 출력으로 대체할 것입니다 We will add below code snippet under spec.disruption to add disruption budgets to disrupt all nodes at once.
budgets: - nodes: "1"Changes in default-ec2nc.yaml file.
kubectl get ec2nodeclass default -o yaml | grep 'id: ami-' | uniq - id: ami-0ee947a6f4880da75

Changes in default-np.yaml file
kubectl get nodepool default -o yaml ... spec: disruption: budgets: - nodes: "1" consolidationPolicy: WhenUnderutilized expireAfter: Never limits: ...

To apply these changes we will commit and push these changes to the repository.

# while true; do kubectl get nodeclaim; echo ; kubectl get nodes -l team=checkout; echo ; kubectl get nodes -l team=checkout -o jsonpath="{range .items[*]}{.metadata.name} {.spec.taints}{\"\n\"}{end}"; echo ; kubectl get pods -n checkout -o wide; echo ; date; sleep 1; echo; done # 10분 소요 (예상) 실습 포함 cd ~/environment/eks-gitops-repo 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 # Once Argo CD sync the karpenter app, we can see the disruption event in karpenter controller logs. It will then provision new nodes with kubernetes version 1.26 and delete the old nodes. kubectl -n karpenter logs deployment/karpenter -c controller --tail=33 -f 혹은 kubectl stern -n karpenter deployment/karpenter -c controller # Lets get the ami id for the AMI build for kubernetes version 1.26. 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-086414611b43bb691karpenter 컨트롤러 로그에서 노드 ip-10-0-11-205.us -west-2.compute.internal과 ip-10-0-47-152.us -west-2.compute.internal이 하나씩 표류하는 것을 볼 수 있습니다.
새 노드를 가져와서 이 노드에서 체크아웃 앱 포드가 실행되고 있는지 확인해 보겠습니다. 이제 노드가 v1.26.15-eks-1552ad0 버전에 있는지 확인할 수 있습니다.
# 과정 중 상태 Wed Mar 26 03:52:39 UTC 2025 NAME TYPE ZONE NODE READY AGE default-m4bv4 m6a.large us-west-2b ip-10-0-24-213.us-west-2.compute.internal True 15m default-rpl9w c5.xlarge us-west-2c ip-10-0-39-95.us-west-2.compute.internal True 25h default-xxf6m c5.xlarge us-west-2c ip-10-0-36-63.us-west-2.compute.internal True 45s ip-10-0-24-213.us-west-2.compute.internal [{"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"}] ip-10-0-36-63.us-west-2.compute.internal [{"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"}] ip-10-0-39-95.us-west-2.compute.internal [{"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"}, >> {"effect":"NoSchedule","key":"karpenter.sh/disruption","value":"disrupting"}] NAME STATUS ROLES AGE VERSION ip-10-0-24-213.us-west-2.compute.internal Ready <none> 14m v1.25.16-eks-59bf375 ip-10-0-36-63.us-west-2.compute.internal Ready <none> 22s v1.26.15-eks-59bf375 ip-10-0-39-95.us-west-2.compute.internal Ready <none> 25h v1.25.16-eks-59bf375 # Wed Mar 26 03:54:15 UTC 2025 NAME TYPE ZONE NODE READY AGE default-rngwl m6a.large us-west-2b ip-10-0-21-135.us-west-2.compute.internal True 79s default-xxf6m c5.xlarge us-west-2c ip-10-0-36-63.us-west-2.compute.internal True 2m22s ip-10-0-21-135.us-west-2.compute.internal [{"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"}] ip-10-0-36-63.us-west-2.compute.internal [{"effect":"NoSchedule","key":"dedicated","value":"CheckoutApp"}] NAME STATUS ROLES AGE VERSION ip-10-0-21-135.us-west-2.compute.internal Ready <none> 55s v1.26.15-eks-59bf375 ip-10-0-36-63.us-west-2.compute.internal Ready <none> 119s v1.26.15-eks-59bf375 # 카펜터 동작 로그 확인 kubectl -n karpenter logs deployment/karpenter -c controller --tail=33 -f 혹은 kubectl stern -n karpenter deployment/karpenter -c controller # kubectl get nodes -l team=checkout # 파드 신규 노드로 이전 완료 kubectl get pods -n checkout -o wide ...- checkout-redis PVC 가 이미 다른 곳에 연결되었있다고 하고 신규 파드가 연결되지 않을 경우 : AWS EBS에서 해당 볼륨 Force detach 로 해결
--------------------------------- 이후 실습은 직접 진행은 못했지만, 내용은 첨부 -------------------------------------------
[3.3 데이터부 - 셀프노드] Upgrading EKS Self-managed Nodes 10분 소요 (예상) 실습 포함기본 정보 확인
# Lets explore the self-managed nodes. kubectl get nodes --show-labels | grep self-managed ip-10-0-26-119.us-west-2.compute.internal Ready <none> 30h v1.25.16-eks-59bf375 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2b,k8s.io/cloud-provider-aws=a94967527effcefb5f5829f529c0a1b9,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-10-0-26-119.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=m5.large,node.kubernetes.io/lifecycle=self-managed,team=carts,topology.ebs.csi.aws.com/zone=us-west-2b,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2b ip-10-0-6-184.us-west-2.compute.internal Ready <none> 30h v1.25.16-eks-59bf375 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2a,k8s.io/cloud-provider-aws=a94967527effcefb5f5829f529c0a1b9,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-10-0-6-184.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=m5.large,node.kubernetes.io/lifecycle=self-managed,team=carts,topology.ebs.csi.aws.com/zone=us-west-2a,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2a # Verify if the pods are scheduled on self-managed nodes. kubectl get pods -n carts -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES carts-7ddbc698d8-zts9k 1/1 Running 0 30h 10.0.31.72 ip-10-0-26-119.us-west-2.compute.internal <none> <none> carts-dynamodb-6594f86bb9-8pzk5 1/1 Running 0 30h 10.0.30.122 ip-10-0-26-119.us-west-2.compute.internal <none> <none> # lets perform in-place upgrade on the self-managed nodes. 자가 관리 노드를 업그레이드하려면 실행 템플릿에서 AMI를 업데이트해야 합니다. 이 워크숍에서는 테라폼을 사용하여 자가 관리 노드를 생성했습니다. 이를 통해 /home/ec2-user/Environment/terraform/base.tf 파일에서 AMI를 업데이트하고 변경 사항을 적용할 수 있습니다. 하지만 먼저 Kubernetes 버전 1.26에 해당하는 최신 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-086414611b43bb691Update /home/ec2-user/environment/terraform/base.tf file with the AMI obtained from the previous command.
Copyself_managed_node_groups = { self-managed-group = { instance_type = "m5.large" . . . # Additional configurations ami_id = "ami-086414611b43bb691" # Replaced the latest AMI ID for EKS 1.26 subnet_ids = module.vpc.private_subnets . . . launch_template_use_name_prefix = true } }
Apply terraform changes.
Copy# while true; do kubectl get nodes -l node.kubernetes.io/lifecycle=self-managed; echo ; aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --filters "Name=tag:Name,Values=default-selfmng" --output table; echo ; date; sleep 1; echo; done # cd ~/environment/terraform/ terraform plan && terraform apply -auto-approveOnce it is completed. Now validate the nodes with the below command to make sure the version is v1.26:
신규 버전 EC2 1대가 Ready되고 나서 5분 Refresh 시간 이후에 기존 버전 EC2 1대를 종료 실행하면서, 동시에 추가 신규 버전 EC2 1대 생성.
Copy# kubectl get nodes -l node.kubernetes.io/lifecycle=self-managed NAME STATUS ROLES AGE VERSION ip-10-0-19-69.us-west-2.compute.internal Ready <none> 23m v1.26.15-eks-1552ad0 ip-10-0-46-19.us-west-2.compute.internal Ready <none> 28m v1.26.15-eks-1552ad0 # aws ec2 describe-instances --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value | [0], ImageId]" --filters "Name=tag:Name,Values=default-selfmng" --output table ...[3.4 데이터부 - 파게이트노드] Upgrading AWS Fargate Nodes‣Fargate는 컨테이너에 필요에 따라 적절한 크기의 컴퓨팅 용량을 제공하는 기술입니다.
Fargate를 사용하면 컨테이너를 실행하기 위해 가상 머신 그룹을 직접 프로비저닝, 구성 또는 확장할 필요가 없습니다.
서버 유형을 선택하거나 노드 그룹을 확장할 시기를 결정하거나 클러스터 패킹을 최적화할 필요도 없습니다.
Fargate에서 실행되는 기준을 충족하는 Pod를 시작하면 클러스터에서 실행 중인 Fargate 컨트롤러가 Pod를 Fargate로 인식, 업데이트 및 예약합니다.
AWS Fargate 노드를 업그레이드하려면 K8s 배포를 다시 시작하여 새로운 포드가 최신 Kubernetes 버전에서 자동으로 예약되도록 할 수 있습니다.
기본 정보 확인
Copy# kubectl get pods -n assets -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES assets-7ccc84cb4d-s8wwb 1/1 Running 0 31h 10.0.41.147 fargate-ip-10-0-41-147.us-west-2.compute.internal <none> <none> # Now, lets describe the node to see its version. 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-41-147.us-west-2.compute.internal Ready <none> 31h v1.25.16-eks-2d5f260 10.0.41.147 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25디플로이먼트 재시작 Restart 으로 신규 버전 마이그레이션!
Copy# 디플로이먼트 재시작 Restart kubectl rollout restart deployment assets -n assets # Lets wait for the new pods to become ready. kubectl wait --for=condition=Ready pods --all -n assets --timeout=180s # Once the new pods reach ready state, check the version of the new fargate node. kubectl get pods -n assets -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES assets-569dcdcf9-xwscf 1/1 Running 0 72s 10.0.21.44 fargate-ip-10-0-21-44.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-21-44.us-west-2.compute.internal Ready <none> 38s v1.26.15-eks-2d5f260 10.0.21.44 <none> Amazon Linux 2 5.10.234-225.910.amzn2.x86_64 containerd://1.7.25- [3. 데이터부] 제어부와 동일한 데이터부 버전 업그레이드 최종 확인
'AWS' 카테고리의 다른 글
[AEWS 3기] 11주차 - ML Infra(GPU) on EKS (0) 2025.04.20 [AEWS 3기] 10주차 - K8S 시크릿 관리 (1) 2025.04.12 [AEWS 3기] 8주차 - K8S CI/CD (0) 2025.03.30 [AEWS 3기] 7주차 - EKS Mode/Nodes (0) 2025.03.23 [AEWS 3기] 6주차 - EKS Security (0) 2025.03.15