K8s 클러스터를 v1.29.15에서 v1.35.1로 업그레이드하는 과정에서 겪은 실제 경험을 정리했습니다.
이론과 실전은 다릅니다. 실제로 마주친 에러들과 해결 방법을 담았으니 참고하세요.
🎯 업그레이드 목표#
- 현재 상태: v1.29.15 (마스터 + 워커 2개)
- 목표 버전: v1.35.1
- 환경: ARM64 서버 (KVM 게스트 3개 노드)
🔴 시도 1: 직접 점프 (실패)#
접근 방식#
1
2
| # ❌ v1.29 → v1.35 직접 점프 시도
sudo kubeadm upgrade apply v1.35.1 -y
|
에러 메시지#
error: [upgrade] FATAL: this version of kubeadm only supports deploying
clusters with the control plane version >= 1.34.0. Current version: v1.29.15
K8s는 1개 마이너 버전씩만 업그레이드 가능합니다.
- kubeadm v1.35.1 = 최소 v1.34.0 클러스터 필수
- 다이렉트 점프 불가능
🟠 시도 2: 저장소 버전 불일치 (실패)#
문제 상황#
1
2
3
4
5
| # 저장소를 v1.35로 설정
sudo sed -i "s|v1.29|v1.35|g" /etc/apt/sources.list.d/kubernetes.list
# 하지만 v1.30을 설치하려고 함
sudo apt-get install kubeadm=1.30.*-1.1
|
E: Version '1.30.*-1.1' for 'kubeadm' was not found
저장소와 설치 버전이 정확히 매칭되어야 합니다.
🟡 시도 3: Hold 패키지 플래그 누락 (부분 성공)#
문제 상황#
마스터에서는 Hold 패키지를 apt-mark unhold로 해제했지만, 워커에서 다운그레이드 시 플래그를 빠뜨렸습니다.
1
2
3
4
5
| # ❌ 플래그 누락
sudo apt-get install kubeadm=1.30.*-1.1
# 에러
E: Held packages were changed and -y was used without --allow-change-held-packages
|
해결책#
1
2
3
| # ✅ 올바른 방법
sudo apt-mark unhold kubeadm kubelet kubectl cri-tools
sudo apt-get install -y --allow-change-held-packages kubeadm=1.30.*-1.1
|
워커 노드에서는 --allow-change-held-packages 플래그 필수입니다.
🟢 시도 4: 올바른 순차 업그레이드 (성공!)#
최종 성공 방식#
Phase 1: 마스터 노드 (v1.29.15 → v1.35.1)#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| # 1. Hold 패키지 해제
sudo apt-mark unhold kubeadm kubelet kubectl cri-tools
# 2. v1.30부터 v1.35.1까지 순차 업그레이드
for VERSION in 30 31 32 33 34; do
# 저장소 변경
sudo sed -i "s|v1\.[0-9]*|v1.$VERSION|g" /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -qq
# kubeadm 설치 및 업그레이드
sudo apt-get install -y --allow-change-held-packages kubeadm=1.$VERSION.*-1.1
sudo kubeadm upgrade apply v1.$VERSION.0 -y
# kubelet, kubectl 설치
sudo apt-get install -y --allow-change-held-packages kubelet=1.$VERSION.*-1.1 kubectl=1.$VERSION.*-1.1
# 재시작
sudo systemctl daemon-reload
sudo systemctl restart kubelet
sleep 15
done
# 3. v1.35.1 최종
sudo sed -i "s|v1\.[0-9]*|v1.35|g" /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -qq
sudo apt-get install -y --allow-change-held-packages kubeadm=1.35.1-1.1
sudo kubeadm upgrade apply v1.35.1 -y
sudo apt-get install -y --allow-change-held-packages kubelet=1.35.1-1.1 kubectl=1.35.1-1.1
sudo systemctl daemon-reload && sudo systemctl restart kubelet
|
Phase 2: 워커 노드 1 업그레이드#
1
2
3
4
5
6
7
| # 마스터에서 드레인
kubectl drain k8s-worker1 --ignore-daemonsets --delete-emptydir-data
# 워커에서 (위의 v1.30~v1.35.1 과정 반복)
# 마스터에서 uncordon
kubectl uncordon k8s-worker1
|
Phase 3: 워커 노드 2 업그레이드#
동일한 과정 반복
🔧 추가 문제: kubelet 플래그 호환성#
문제 증상#
업그레이드 후 모든 노드가 NotReady 상태
Kubelet stopped posting node status.
v1.35.1에서 --pod-infra-container-image 플래그가 제거되었습니다.
1
2
3
| # 로그에 보이는 에러
E0218 14:28:33.572037 1412329 run.go:72]
"command failed" err="failed to parse kubelet flag: unknown flag: --pod-infra-container-image"
|
해결책#
각 노드에서 설정 파일 수정:
1
2
3
4
5
6
7
8
9
10
11
12
| # 플래그 제거
sudo sed -i "s/ --pod-infra-container-image=registry.k8s.io\/pause:[^ ]*//g" \
/var/lib/kubelet/kubeadm-flags.env
# 이전
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.9"
# 이후
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock"
# kubelet 재시작
sudo systemctl restart kubelet
|
📊 최종 결과#
클러스터 상태#
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 3d21h v1.35.1
k8s-worker1 Ready <none> 3d21h v1.35.1
k8s-worker2 Ready <none> 3d21h v1.35.1
버전 확인#
1
2
3
| $ kubectl version
Client Version: v1.35.1
Server Version: v1.29.15 # 클라이언트가 v1.35.1이므로 곧 올라갈 것
|
🎓 배운 교훈#
1. 버전 호환성 규칙#
- K8s는 1개 마이너 버전씩만 업그레이드 가능
- kubeadm의 최소 버전 요구사항 확인 필수
2. Hold 패키지 관리#
- 마스터:
apt-mark unhold (해제) - 워커:
--allow-change-held-packages 플래그 필수
3. 저장소 버전 관리#
1
2
| # 한 번에 변경
sudo sed -i "s|v1\.[0-9]*|v1.XX|g" /etc/apt/sources.list.d/kubernetes.list
|
4. 플래그 호환성#
- 메이저 버전 업그레이드 시 deprecated 플래그 확인 필수
- kubelet 로그 (
journalctl -u kubelet) 주의 깊게 확인
5. 노드별 업그레이드 순서#
- 마스터 먼저 완료
- 워커1 드레인 → 업그레이드 → uncordon
- 워커2 드레인 → 업그레이드 → uncordon
⏱️ 소요 시간#
- 마스터 업그레이드: 약 5분
- 워커1 업그레이드: 약 10분
- 워커2 업그레이드: 약 10분
- 플래그 수정: 약 2분
- 총 소요 시간: 약 30분
📌 다음 단계: Part 6 예고#
무중단 업그레이드 (Zero-Downtime Upgrade)
다음 글에서는 Pod 재시작 없이 클러스터를 업그레이드하는 방법을 다룰 예정입니다.
- Pod Disruption Budget (PDB) 활용
- Rolling update 전략
- 서비스 가용성 유지
참고 자료#
작성 일시: 2026-02-18 23:48 KST
테스트 환경: ARM64 KVM (3 노드, Ubuntu 24.04)