k8s 버전 정책 (Skew Policy)
쿠버네티스는 업스트림 마이너 버전을 평균 4개월에 한 번씩 Release 합니다.
그렇기에 새로운 마이너 버전이 Release 되는 시점이 바로 쿠버네티스 버전을 업그레이드하는 적절한 시기가 되는거죠.
Release 목록은 다음 링크에서 확인할 수 있습니다.
k8s.changelog
쿠버네티스의 버전은 단계별로 진행해야해요!
- 1. kubeadm 공식 문서에서 지원하는 "마이너 버전 업그레이드 경로"(v1.29 -> v1.30 등)를 확인하기!
- 2. 메이저(1.x -> 2.x) 건너뛰기는 불가해요! 마이너 버전은 한 단계씩(v1.29 -> v1.30 -> v1.31 ...)만 가능하다는 걸 잊지마세요!
또한, 쿠버네티스 구성 요소 간에 지원되는 버전 차이는 다음과 같아요.
(버전 차이(Skew) 정책)
- 구성 요소 중
kube-apiserver
의 버전은 가장 최신 버전이어야 함. controller-manager
,kube-schedular
는kube-apiserver
보다 한 버전 낮게 설정 가능kubelet
,kube-proxy
는kube-apiserver
보다 두 버전 낮게 설정 가능kubectl
은kube-apiserver
를 기준으로 한 버전 차이 내에서 지원함.
업그레이드 전 준비 사항
1. 현재 버전, 구성 확인하기
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# cp-node Ready control-plane … v1.29.11
# worker-1 Ready <none> … v1.29.11
# worker-2 Ready <none> … v1.29.11
kubeadm version
kubelet --version
kubectl version --client
2. 지원 가능한 업그레이드 경로 확인
- kubeadm 공식 문서에서 지원하는 “마이너 버전 업그레이드 경로”(v1.29 → v1.30 등)를 확인
- 메이저(1.x → 2.x) 건너뛰기는 불가, 마이너 버전은 한 단계씩(v1.29 → v1.30 → v1.31 …)만 가능
3. 백업
etcd
스냅샷 확보하기. (선택)
# control-plane 노드에서
ETCDCTL_API=3 etcdctl snapshot save ~/etcd-backup-$(date +%F).db \
--endpoints=127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
애드온 매니페스트, Helm 릴리즈 값 덤프
4. 릴리즈 노트, Deprecated 체크
- Cilium, nginx-ingress-controller, MetalLB 등 사용 중인 애드온의 새 버전 호환성 확인
- Kubernetes API Deprecated 체크(
kubectl deprecations
플러그인 등 활용)
버전 업그레이드
kubeadm
으로 구성된 환경에서의 쿠버네티스 클러스터 버전을 업그레이드하는 순서입니다.
버전 업그레이드는 Control Plane
-> Worker Node
순으로 작업을 진행할 예정입니다.
각 노드별로 업그레이드가 필요한 구성 요소는 다음과 같아요.
- Control Plane:
kube-apiserver
,controller-manager
,kube-schedular
,kubelet
,kube-proxy
- Worker Node:
kubelet
,kube-proxy
저는 현재 v1.29.11
버전이기 때문에 v1.30
으로 업그레이드를 해볼거에요!
Control Plane
Control Plane
업그레이드 작업 시, 주요 구성 요소의 일시적인 중단을 발생시켜요.
따라서 작업하는 동안 kubectl
명령 및 쿠버네티스 API 사용, 파드 생성/변경/삭제, 파드 생성 실패 시의 재생성 프로세스 등이 제한됩니다.
1. 쿠버네티스 패키지 레포지토리 변경하기 (관련 링크)
변경할 버전에 맞게 수정해주세요.
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 저장소 업데이트
sudo apt-get update -y
2. 버전 hold 해제 후 kubeadm 업그레이드
만약 kubeadm
, kubelet
, kubectl
에 apt-mark hold
가 걸려있지 않다면 해당 부분은 패스하고 업그레이드 부분만 참고해주세요.
sudo apt-mark unhold kubeadm && \
sudo apt-get update -y && sudo apt-get install -y kubeadm='1.30.x-*' && \
sudo apt-mark hold kubeadm
kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"30", GitVersion:"v1.30.11", GitCommit:"6a074997c960757de911780f250ecd9931917366", GitTreeState:"clean", BuildDate:"2025-03-11T19:56:25Z", GoVersion:"go1.23.6", Compiler:"gc", Platform:"linux/amd64"}
3. 업그레이드 플랜 확인
sudo kubeadm upgrade plan
# → 현재 Control Plane 버전, 가능한 Target 버전, etcd 버전 호환성 등 표시
4. Control Plane 업그레이드 실행
sudo kubeadm upgrade apply v1.30.x
- 프롬프트에 따라 yes 입력
- 성공 시
kube‑apiserver
,kube‑controller‑manager
,kube‑scheduler
매니페스트가 자동 업데이트
5. 버전 hold 해제 후 kubelet
, kubectl
업그레이드
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get update -y && sudo apt-get install -y kubelet='1.30.x-*' kubectl='1.30.x-*' && \
sudo apt-mark hold kubelet kubectl
# kubelet 재시작
sudo systemctl daemon-reload
sudo systemctl restart kubelet
6. Control Plane 상태 확인
kubectl get pods -n kube-system
# 모든 컨트롤 플레인 컴포넌트가 Ready 상태인지 확인
kubectl get cs
Worker Node
워커 노드는 한 번에 하나의 노드를 대상으로 업그레이드를 진행합니다.
그리고 목표한 버전에 도달할 때까지 마이너 업그레이드 작업을 노드마다 반복해 수행해야해요!
1. 노드 격리하기 (Control Plane에서 해당 명령어 실행)
kubectl cordon <worker-node>
kubectl drain <worker-node> --ignore-daemonsets --delete-local-data
2. 쿠버네티스 패키지 레포지토리 변경하기 (관련 링크)
변경할 버전에 맞게 수정해주세요.
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 저장소 업데이트
sudo apt-get update -y
3. 버전 hold 해제 후 kubeadm 업그레이드
만약 kubeadm
, kubelet
, kubectl
에 apt-mark hold
가 걸려있지 않다면 해당 부분은 패스하고 업그레이드 부분만 참고해주세요.
sudo apt-mark unhold kubeadm && \
sudo apt-get update -y && sudo apt-get install -y kubeadm='1.30.x-*' && \
sudo apt-mark hold kubeadm
kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"30", GitVersion:"v1.30.11", GitCommit:"6a074997c960757de911780f250ecd9931917366", GitTreeState:"clean", BuildDate:"2025-03-11T19:56:25Z", GoVersion:"go1.23.6", Compiler:"gc", Platform:"linux/amd64"}
4. kubelet config 업그레이드
sudo kubeadm upgrade node
5. 버전 hold 해제 후 kubelet
, kubectl
업그레이드
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get update -y && sudo apt-get install -y kubelet='1.30.x-*' kubectl='1.30.x-*' && \
sudo apt-mark hold kubelet kubectl
6. kubelet 재시작
sudo systemctl daemon-reload
sudo systemctl restart kubelet
7. 노드 격리 해제 (Control Plane에서 해당 명령어 실행)
kubectl uncordon <worker-node>
트러블슈팅
ERROR CreateJob
kubeadm upgrade plan
명령어 사용 시 cluster health check에서 실패하면서 중단되는 문제가 발생함.
[upgrade/health] FATAL: [preflight] Some fatal errors occurred:
[ERROR CreateJob]: Job "upgrade-health-check-xxxxx" in the namespace "kube-system" did not complete in 15s: no condition of type Complete
이건 kubeadm
이 클러스터 상태를 확인하기 위해 Job
리소스를 생성했지만, 그것이 15초 내에 성공적으로 완료되지 않아 실패로 간주했다는 로그임.
원인 분석 및 해결책
1. 노드 리소스 부족 OR Job 스케줄링 실패
- Pod가
Pending
상태에 머물러 Job이 완료되지 못할 수 있음.
확인 방법
kubectl get jobs -n kube-system
kubectl describe job upgrade-health-check-xxxxx -n kube-system
kubectl get pods -n kube-system | grep upgrade-health-check
kubectl describe pod <해당-pod> -n kube-system
2. CNI 플러그인 문제로 인해 Pod 통신 불안정
- health-check Job은 Pod간 통신이 가능한지를 체크하는데, CNI 문제로 실패할 가능성이 있음.
이 경우 다음 명령으로 CNI 상태 점검
kubectl get pods -n kube-system -o wide
CNI 관련 Pod(e.g., calico, flannel, cilium)가 CrashLoopBackOff나 Error 상태라면 먼저 해결해야 함.
3. Job 컨트롤러 문제
- Job 자체가 작동을 못 하거나 API server가 문제가 있을 수도 있음.
kube-controller-manager
, kube-scheduler
, etcd
상태도 같이 확인
kubectl get pods -n kube-system
4. 임시 해결: preflight error 무시하고 강제 실행하기
개발/테스트 환경이라면 다음처럼 preflight error
에러를 무시해서 강제로 upgrade plan
하도록 하는 방법이 있음.
sudo kubeadm upgrade plan --ignore-preflight-errors=CreateJob
단, 실제 upgrade apply
단계에서도 같은 문제가 생길 수 있으므로 원인 파악하는 것이 더 안전함.
CNI 파드 동기화 실패
노드 버전 업그레이드 이후 CNI(cilium
) 파드가 정상적으로 동기화되지 않는 문제가 발생함.(Pending
상태)
원인 분석 및 해결책
1. 정확한 원인 파악을 위해 다음 명령 실행
kubectl describe pod <cilium-operator-pod-name> -n kube-system
Events
: 예:0/2 nodes are available: 1 node(s) had taint {...}
NodeAffinity
/Tolerations
/Scheduling
issues
2. 문제 1: 노드에 taint가 있어 스케줄이 안되는 경우
drain
을 할 때 --delete-local-data
나 --ignore-daemonsets
옵션 때문에 노드에 taint가 남는 경우가 있음.
kubectl describe node <worker-node>
이거에서 Taints: 항목이 NoSchedule
같은 걸로 돼 있으면, cilium-operator가 못 올라올 수 있다고 함.
kubectl taint nodes <worker-node> node-role.kubernetes.io/worker-
실제 taint key
를 확인하고 맞게 제거해야 함.
3. 문제 2: Cilium 자체 충돌 또는 리소스 부족
Pending 상태지만 리소스가 부족해서 스케줄링이 안되는 경우도 있음.
kubectl get nodes -o wide
kubectl top node
해결: (강제 재배포하기)
kubectl rollout restart daemonset cilium -n kube-system
kubectl rollout restart deployment cilium-operator -n kube-system
또는 완전 삭제 후 재설치 (cilium CLI 필요 시)
cilium uninstall
cilium install