EKS 1.32 업데이트 그리고 새로운 업데이트 방식
안녕하세요, 비브로스 DevOps 박진홍입니다.
23년도에 EKS 업데이트 방식을 소개한 적이 있는데, 어김없이 찾아온 EKS 1.29버전의 지원 종료로 인해 업데이트를 진행해야 했습니다.
기존 CDK를 통해 EKS를 배포하고 In-place 업데이트하던 방식에서 EKSCTL을 통한 Blue-Green/Record 변경 방식으로 운영하다가 약 2년이 지나 해당 업데이트의 문제점을 파악하고 새로운 업데이트 방식을 검토하고 도입하기로 한 여정을 소개하고자 합니다.
이번 글에서는 EKS 업데이트시 고려했던 부분 과 도입 과정 을 중점적으로 다루고, 똑닥 인프라의 고도화 과정 을 일부 추가하여 작성하였습니다.
EKS 업데이트 또 너야?
현재 똑닥 인프라에서 사용하는 클러스터는 3대로 구성되어 있으며, 해당 EKS 버전은 모두 1.29 버전을 사용하고 있습니다. EKS 1.29 버전은 2025년 03월 23일에 표준 지원 종료일이여서 3개의 클러스터를 모두 업데이트 대상이므로 업데이트 방법에 기획하고 테스트 후 적용합니다. 매니지먼트 클러스터를 먼저 업데이트하고, 개발환경 클러스터 그리고 운영환경 클러스터를 업데이트 합니다.
업데이트 방식의 고민
작년 EKS 1.25에서 1.29로 업데이트를 진행하면서 OSS 업데이트 및 테라폼 도입으로 인해 표준 지원 종료 일정을 맞추지 못하고 기간이 연장되어 비용이 추가로 발생하였습니다. 이번 업데이트에는 표준 지원 종료 일정을 맞추기 위해 종료 3주 전에 업데이트를 진행하고, 준비기간도 약 4주정도로 준비하였습니다.
또한 2023~2024년에는 Blue-Green/Route53 Record 가중치 변경을 통해 업데이트를 진행하였는데, 이때 DNS 전파 시간으로 인해 ASIS 클러스터로 트래픽이 전달되는 경우가 발생하여 문제가 발생하였습니다. 해당 DNS 전파 시간을 개선할 수 있는 방법을 고민하였을 때 1안) TargetGroup 변경 방식 과 2안) Multi Target 방식을 통한 가중치 전환을 검토하였습니다.
업데이트 전략 이전 EKS 1.32에는 무슨 변경사항이 있었는가?
EKS 1.32 업데이트시 Kubernetes, 3rd-party, pipeline 등 고려해야하는 사항들이 있습니다. 이번 업데이트시 변경 사항을 참고하여 업데이트를 준비합니다.
EKS 변경 사항
- 기존 EKSCTL를 통해 관리하던 부분은 Terraform 을 통해 관리하게 변경
- Terraform Cloud 구조 개선 및 코드 고도화를 통해 재사용 및 가독성 강화
- 쿠버네티스 신규 기능 테스트 및 도입 검토(Readiness Gate ...)
OSS 변경 사항
- Karpenter Beta 버전에서 Stable 버전으로 업데이트
- 3rd-party, Add-on 등 약 40여개를 EKS 1.32 버전에 맞춰 최신 버전으로 업데이트 및 마이그레이션
- Github 공통 Workflow 등을 도입하여 EKS 업데이트에 따른 자동화 구성 및 옵저버빌리티 구성
업데이트 방식
EKS 업데이트 방식에 대해 장단점을 비교해봅니다.
In-place 업데이트 방식
설명 : 현재 버전 EKS에서 버전 업데이트를 진행하는 방법
장점
- 별도 인프라 리소스 없이, 기존 리소스에서 업데이트 가능(비용 효율)
- 각 컴포넌트 업데이트시 문제가 발생할 경우 업데이트가 적용되지 않고 롤백 가능
- 클러스터 업데이트를 제외한 나머지 리소스에 대한 오버헤드가 적다
- 클러스터 API 엔드포인트를 변경하지 않고, CI/CD , 모니터링, 로깅 등 신규 파이프라인을 구성하지 않아도 됨
단점
- Control Plane 업데이트 이후 롤백이 불가능함, Data Plane 롤백 발생시 서비스 중 일부 인스턴스에 영향을 받을 수 있음
- EKS 버전을 1개씩 올려야 하며, 3rd-party 와 EKS 버전간에 연관성이 있는 경우 3rd-party는 업데이트 불가
- 업데이트시 K8s 설정(Pod 최소 갯수 2개, 노드별 분산, PODB 값에 의한 갯수 조정, ReadinessProbe, Pod Readiness Gate, Pod GraceFulshutdown ...)에 따라 서비스에 영향이 발생할 수 있음.
Blue-Green Record 업데이트 방식
설명 : Route53에서 도메인 레코드(Alias 또는 Cname)을 기존 ELB/CF에서 신규 ELB/CF로 가중치 기반으로 변경하는 방법
장점
- DNS 레코드 변경을 통해 빠른 롤백으로 서비스 안정성을 보장할 수 있음
- EKS 와 Add-on, 3rd-party 간의 버전의 종속성 제한없이 완전 격리 가능
단점
- In-place 업데이트보다 비용이 2배 발생(EKS,ELB/CF)
- DNS TTL 및 Cache의 영향으로 전환속도가 즉시 적용되지 않을 수 있음
- CI/CD, 모니터링, 로깅 등 새로운 클러스터에 대해 구성 필요
Blue-Green TargetGroup 업데이트 방식
설명 : ELB에서 기존 Targetgroup에서 신규 TargetGroup으로 즉시 변경하는 방법
장점
- DNS TTL 및 Cache의 영향없이 즉시 적용할 수 있음
- EKS 와 Add-on, 3rd-party 간의 버전의 종속성 제한없이 완전 격리 가능
단점
- In-place 업데이트보다 비용이 2배 발생(EKS)
- CI/CD, 모니터링, 로깅 등 새로운 클러스터에 대해 구성 필요
- AWS Controller를 Dynamic으로 구성하였을때 바로 마이그레이션이 불가능함
- AWS Controller를 통한 구성이 아닌, 별도의 TargetGroup과 TargetGroupBinding 구성이 필요함
Blue-Green Multi Target 업데이트 방식
설명 : ELB에서 기존 Targetgroup에서 신규 TargetGroup으로 가중치 기반으로 변경하는 방법
장점
- DNS TTL 및 Cache의 영향없이 즉시 적용할 수 있음
- EKS 와 Add-on, 3rd-party 간의 버전의 종속성 제한없이 완전 격리 가능
- AWS Controller를 사용할 경우 그대로 유지할 수 있음
- 신규 클러스터에 일정 트래픽을 가중치 기반으로 보낼 수 있음
단점
- In-place 업데이트 보다 비용이 2배 발생(EKS)
- CI/CD, 모니터링, 로깅 등 새로운 클러스터에 대해 구성 필요
- TargetGroup과 TargetGroupBinding을 별도로 구성이 필요함
업데이트 방식 선택
DevOps 팀에서는 위 4가지 방법중에 기존 사용하였던 In-place 방식
과 Blue-Green Record
변경방식을 제외한 나머지 2개 방식에 대해 기술 검토를 진행하였습니다.
Blue-Green TargetGroup 업데이트 방식
의 경우 기존 클러스터(이하 ASIS 클러스터) 에서 AWS Controller를 통해 생성된 ELB는 클러스터 삭제시 ELB가 삭제되므로 별도 ELB를 구성하고, ASIS 클러스터를 해당 ELB에 연결하는 작업이 필요합니다. 그리고 변경 클러스터(이하 TOBE 클러스터)에서는 AWS Controller를 사용하지 않고 별도 Terraform 또는 CDK/CLI를 통해 별도 관리해야 합니다.
그래서 이번에는 Blue-Green Multi Target 업데이트 방식
을 선택하여 기술검토를 진행하였습니다.
- 기존 방식(Blue-Green Record 변경)
- 변경 방식(Blue-Green Multi Target 변경)
위 그림과 같이 1개의 ELB에서 ASIS 클러스터와 TOBE 클러스터간에 가중치 기반으로 트래픽을 변경하여 Blue-Green 방식으로 업데이트하는 방식을 선택하였습니다.
기술 검토
1. 사전 구성
Terraform 을 통해 ASIS 클러스터와 TOBE 클러스터를 배포합니다. Terraform 코드는 하기 AWS에서 제공하는 테라폼 코드를 참고하여 구성하였습니다. 해당 클러스터에는 AWS-Controller와 ELB에서 사용하는 Secuitry Group, Route53, ExternalDNS 사전에 구성되어 있습니다.
- ASIS 클러스터 :
ex-karpenter-asis
- TOBE 클러스터 :
ex-karpenter-tobe
- 공통 보안그룹 :
sg-0757f06c90cfeaab4
- 사용 도메인 :
eks-demo.hongetravel.store
2. ASIS 리소스 배포
ASIS 클러스터에서 테스트를 위해 Nginx Config, Deployment, Service, Ingress를 배포합니다.
## configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>EKS 1.32 Multi Target Demo</title>
</head>
<body>
<h1>Welcome to nginx on ASIS Cluster !</h1>
<p>If you see this page, ASIS Cluster .</p>
</body>
</html>
---
## deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: nginx-html
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: nginx-html
configMap:
name: nginx-config
---
## service
apiVersion: v1
kind: Service
metadata:
name: nginx-asis
labels:
app: nginx
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
---
## ingress-origin
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: dynamic-alb-group
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/success-codes: "200"
alb.ingress.kubernetes.io/security-groups: sg-0757f06c90cfeaab4
external-dns.alpha.kubernetes.io/hostname: eks-demo.hongetravel.store
labels:
app: nginx
namespace: default
spec:
ingressClassName: alb
rules:
- host: eks-demo.hongetravel.store
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-asis
port:
number: 80
3. TOBE 리소스 배포
TOBE 클러스터에서 테스트를 위해 Nginx Config, Deployment, Service, Ingress를 배포합니다.
## configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>EKS 1.32 Multi Target Demo</title>
</head>
<body>
<h1>Welcome to nginx on TOBE Cluster !</h1>
<p>If you see this page, TOBE Cluster .</p>
</body>
</html>
---
## deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: nginx-html
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: nginx-html
configMap:
name: nginx-config
---
## service
apiVersion: v1
kind: Service
metadata:
name: nginx-tobe
labels:
app: nginx
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
---
## ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: dynamic-alb-group
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/success-codes: "200"
alb.ingress.kubernetes.io/security-groups: sg-0757f06c90cfeaab4
alb.ingress.kubernetes.io/multi-cluster-target-group: "true"
labels:
app: nginx
namespace: default
spec:
ingressClassName: alb
rules:
- host: eks-demo.hongetravel.store
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-tobe
port:
number: 80
4. 트래픽 확인
현재 리소스는 Route53에서 레코드가 ASIS 클러스터로 설정되어 있으므로 해당 도메인으로 접근할 경우 ASIS 클러스터로 트래픽이 전달되는것을 확인할 수 있습니다.
## curl 명령어를 통해 확인
for i in {1..10}; do
echo "Request $i :"
status_code=$(curl -s -o response.txt -w "%{http_code}" http://eks-demo.hongetravel.store)
cat response.txt
echo "Status Code : $status_code"
echo "--------------------------------------------"
done
## 확인
Request 10 :
<!DOCTYPE html>
<html>
<head>
<title>EKS 1.32 Multi Target Demo</title>
</head>
<body>
<h1>Welcome to nginx on ASIS Cluster !</h1>
<p>If you see this page, ASIS Cluster .</p>
</body>
</html>
Status Code : 200
--------------------------------------------
5. 타겟 그룹 생성
TOBE Cluster로 트래픽 전달을 위해 TargetGroup을 AWSCLI를 통해 구성합니다. 실제 해당 타겟 그룹은 EKS 업데이트 이후 Route53 Record를 TOBE 클러스터로 변경후 제거될 예정입니다.
- TargetGroup Name : nginx-tobe-80
aws elbv2 create-target-group \
--name nginx-tobe-80 \
--protocol HTTP \
--port 80 \
--vpc-id vpc-044c228a857b793a2 \
--target-type ip \
--ip-address-type ipv4
생성후 해당 ARN을 조회합니다.
aws elbv2 describe-target-groups \
--names nginx-tobe-80 \
--query 'TargetGroups[0].TargetGroupArn' \
--output text
## ARN 확인
arn:aws:elasticloadbalancing:ap-northeast-2:{{ ACCOUNT ID }}:targetgroup/nginx-tobe-80/b51f7883c1e92ba5
6. 타겟 그룹 바인딩 생성
TOBE Cluster로 타겟 그룹 바인딩을 위해 TargetGroupBiding을 Yaml을 통해 구성합니다. 실제 해당 타겟 그룹 바인딩은 EKS 업데이트 이후 Route53 Record를 TOBE 클러스 터로 변경후 제거될 예정입니다.
- TargetGroupBinding Name : nginx-tobe-tg-binding
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: nginx-tobe-tg-binding
namespace: default
spec:
targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-2:{{ ACCOUNT ID }}:targetgroup/nginx-tobe-80/b51f7883c1e92ba5
targetType: ip
serviceRef:
name: nginx-tobe
port: 80
networking:
ingress:
- from:
- securityGroup:
groupID: sg-0757f06c90cfeaab4
ports:
- protocol: TCP
port: 80
7. 멀티 타겟 등록
ASIS Cluster에서 기존 Ingress의 Annotation에 Multi Target으로 등록 구성 변경합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: asis-eks
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/success-codes: "200"
alb.ingress.kubernetes.io/security-groups: sg-0757f06c90cfeaab4
alb.ingress.kubernetes.io/multi-cluster-target-group: "true" ## 설정 활성화
# 기존 Target Group 트래픽 0%, 새로운 Target Group 트래픽 100%
alb.ingress.kubernetes.io/actions.forward-multiple-tg: >
{"type":"forward","forwardConfig":{"targetGroups":[{"serviceName":"nginx-asis","servicePort":"80","weight":0},{"targetGroupARN":"arn:aws:elasticloadbalancing:ap-northeast-2:{{ ACCOUNT ID }}:targetgroup/nginx-tobe-80/b51f7883c1e92ba5","weight":100}],"targetGroupStickinessConfig":{"enabled":true,"durationSeconds":200}}}
labels:
app: nginx
namespace: default
spec:
ingressClassName: alb
rules:
- host: eks-demo.hongetravel.store
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: forward-multiple-tg
port:
name: use-annotation
설정후 AWS Console에서 ALB의 Listener 규칙을 확인해보면 가중치 기반으로 변경된것을 확인할 수 있습니다.
위와 같이 배포후 ALB Listener 부분에 가중치 기반으로 ASIS 클러스터로 트래픽은 0%, TOBE 클러스톨 트래픽은 100% 로 설정된것을 확인할 수 있습니다.
8. 결과 확인
Route53 레코드를 변경하지 않은 상태에서 CURL 명령어를 통해 확인하면 ASIS 클러스터로 트래픽은 전달되지 않고, TOBE 클러스터로 트래픽이 전달되는것을 확인할 수 있습니다.
## curl 명령어 통해 확인
for i in {1..10}; do
echo "Request $i :"
status_code=$(curl -s -o response.txt -w "%{http_code}" http://eks-demo.hongetravel.store)
cat response.txt
echo "Status Code : $status_code"
echo "--------------------------------------------"
done
## 확인
Request 10 :
<!DOCTYPE html>
<html>
<head>
<title>EKS 1.32 Multi Target Demo</title>
</head>
<body>
<h1>Welcome to nginx on TOBE Cluster !</h1>
<p>If you see this page, TOBE Cluster .</p>
</body>
</html>
Status Code : 200
--------------------------------------------
업데이트 결과
위와 같이 Multi Target 기반의 EKS 업데이트 방식을 기술검토하고 검증까지 진행해보았습니다.
도입 결과 를 확인해보면 하기와 같습니다.
- ASIS 클러스터에서 TOBE 클러스터로 트래픽 전환을 가중치 기반으로 DNS 캐시 및 TTL에 영향없이 넘어갈 수 있음
- 업데이트 도중 문제가 발생할 경우 빠른 롤백(w. ArgoCD)이 가능함
- ASIS 클러스터와 TOBE 클러스터는 버전의 종속성 제한없이 완전 격리하여 구성할 수 있음
- 완전격리시 발생할 수 있는 파이프라인 및 모니터링 등은 Terraform과 Github 공통 Workflow + ArgoCD를 통해 구성이 가능함
- 기존 Custom Chart를 통해 AWS Controller에 대한 Helm Template을 그대로 사용할 수 있음
다만 저희에게 주어진 시간은 약 4주로 해당 EKS 업데이트 방식 뿐만 아니라 Terraform 고도화 및 OSS 업데이트 등 여러가지 분석을 진행해야해서 다음 EKS 업데이트 방식에 도입해보고자 합니다. (이번 업데이트에는 Blue-Green Route53 레코드 변경 방식으로 진행)
TOBE 클러스터에 대해 일부 가중치 기반으로 업데이트
해본다면 좋은 전략일것으로 보입니다.
각 인프라 환경 및 서비스 특성마다 제약사항들이 존재하므로 참고하여 업데이트를 진행해보시면 좋을것 같습니다!
해당 글이 매년 있는 EKS 업데이트로 인해 고민하시는분들에게 도움이 되었으면 합니다.
감사합니다.🙂