Overview
Kubernetes 클러스터를 운영하다 보면 보안 패치, 새로운 기능, 인증서 갱신 등의 이유로 주기적인 업그레이드가 필요하다.
Kubespray는 upgrade-cluster.yml 플레이북을 통해 etcd → Control Plane → Worker 순서로 자동 업그레이드를 지원하며, 수동으로 각 노드에 접속하여 kubeadm upgrade를 실행할 필요 없이 Ansible 한 줄로 전체 클러스터를 업그레이드할 수 있다.
이번 포스팅에서는 다음의 내용을 중심으로 정리하였다.
- Kubespray ↔ Kubernetes 버전 매핑 이해
- etcd 백업 및 복구
- Kubespray 버전 전환 (v2.28.0 → v2.30.0)
- upgrade-cluster.yml을 이용한 Kubernetes 업그레이드 (v1.33.3 → v1.34.3)
- 인증서 자동 갱신
- 업그레이드 중 발생할 수 있는 에러와 대응 방법
- 업그레이드 후 검증 및 inventory 동기화
클러스터 설치 관련 내용은 이전 포스팅을 참고한다.
2026.04.07 - [Container Orchestration/Kubernetes] - Kubernetes 클러스터 구축하기(kubespray 2026v.)
https://github.com/somaz94/script-collection/tree/main/bash/k8s-script/kubespray

업그레이드 원칙
Kubespray를 통한 Kubernetes 업그레이드에는 반드시 지켜야 할 원칙이 있다.
| 원칙 | 설명 |
| 한 번에 1 마이너 버전만 | v1.33 → v1.34 ✅, v1.33 → v1.35 ❌ |
| 패치 버전은 자유 | v1.33.3 → v1.33.5 ✅ |
| 업그레이드 순서 | etcd → Control Plane → Worker (kubespray가 자동 처리) |
| Worker 업그레이드 방식 | drain(Pod 퇴거) → 업그레이드 → uncordon(복귀) |
| etcd 백업 필수 | 업그레이드 전 반드시 스냅샷 생성 |
| staging 먼저 | 가능하다면 테스트 환경에서 먼저 검증 후 production 적용 |
Kubespray ↔ Kubernetes 버전 매핑
Kubespray 버전마다 지원하는 Kubernetes 버전 범위가 다르다. 업그레이드 전에 반드시 확인해야 한다.
| Kubespray | K8s 지원 범위 |
| v2.25.x | v1.29.x ~ v1.31.x |
| v2.26.x | v1.30.x ~ v1.32.x |
| v2.27.x | v1.31.x ~ v1.33.x |
| v2.28.x | v1.32.x ~ v1.34.x |
| v2.30.0 | v1.32.x ~ v1.34.x |
정확한 매핑은 Kubespray Releases에서 확인하세요. 특정 태그의 지원 버전은 아래 명령어로도 확인 가능하다.
git show <tag>:roles/kubespray_defaults/defaults/main/main.yml | head -5
업그레이드 절차
Step 1. 사전 준비 — 현재 버전 확인
ssh somaz@10.10.10.17
cd ~/kubespray
# 현재 kubespray 버전 확인
git describe --tags
# 현재 K8s 버전 확인
kubectl get nodes -o wide
# 인증서 만료일 확인
sudo kubeadm certs check-expiration
Step 2. etcd 백업 (필수)
업그레이드 전 etcd 스냅샷을 반드시 생성한다. 문제 발생 시 유일한 롤백 수단이다.
# Control Plane에서 실행
sudo ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup-$(date +%Y%m%d).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/ssl/etcd/ssl/ca.pem \
--cert=/etc/ssl/etcd/ssl/node-k8s-control-01.pem \
--key=/etc/ssl/etcd/ssl/node-k8s-control-01-key.pem
# 백업 검증
sudo ETCDCTL_API=3 etcdctl snapshot status /tmp/etcd-backup-$(date +%Y%m%d).db --write-table
Step 3. Kubespray 버전 전환
Kubernetes를 업그레이드하려면 먼저 Kubespray 자체를 해당 K8s 버전을 지원하는 태그로 전환해야 한다.
# venv 활성화
source ~/kubespray/venv/bin/activate
cd ~/kubespray
# 최신 태그 목록 확인
git fetch --tags
git tag -l | sort -V | tail -20
# 변경사항이 있으면 stash
git stash
# 원하는 버전으로 전환
git checkout v2.30.0
# 의존성 업데이트
pip install -r requirements.txt
Step 4. 설정 변경사항 확인 (Diff)
Kubespray 버전이 바뀌면 기본 설정값도 바뀔 수 있다. sample inventory와 내 inventory의 차이를 확인한다.
# sample과 내 inventory의 k8s-cluster.yml 비교
diff ~/kubespray/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml \
~/kubespray/inventory/somaz-cluster/group_vars/k8s_cluster/k8s-cluster.yml
# sample과 내 inventory의 containerd.yml 비교
diff ~/kubespray/inventory/sample/group_vars/all/containerd.yml \
~/kubespray/inventory/somaz-cluster/group_vars/all/containerd.yml
v2.28.0 → v2.30.0 주요 변경사항
| 파일변경 | 내용 | 영향 |
| etcd.yml | 삭제됨 (etcd 설정이 다른 곳으로 이동) | 커스텀 etcd 설정 없으면 영향 없음 |
| k8s-net-weave.yml | 삭제됨 (Weave CNI deprecated) | Cilium 사용 시 영향 없음 |
| k8s-net-cilium.yml | kube_proxy_replacement: partial → false, cilium_extra_values 추가 | 기본값이라 영향 없음 |
| k8s-cluster.yml | kube_owner 주석에 Cilium 관련 안내 추가 | 사소한 변경 |
| containerd.yml | engine/root → options.Root 구조 변경 | 주석(예시)만 변경 |
| addons.yml | local_path_provisioner_image_tag 제거 | 자동 관리로 변경 |
Step 5. kube_version 설정 (선택)
특정 K8s 버전을 지정하려면 아래 파일을 수정한다. 미설정 시 해당 Kubespray 태그의 기본 최신 버전이 적용된다.
vi ~/kubespray/inventory/somaz-cluster/group_vars/k8s_cluster/k8s-cluster.yml
# 추가 또는 수정
kube_version: v1.34.3
Step 6. 업그레이드 실행
source ~/kubespray/venv/bin/activate
cd ~/kubespray
# Dry-run (변경사항 미리보기, 실제 변경 없음)
ansible-playbook -i inventory/somaz-cluster/inventory.ini \
upgrade-cluster.yml \
-b --become-user=root \
--check --diff
# 실제 업그레이드 실행
ansible-playbook -i inventory/somaz-cluster/inventory.ini \
upgrade-cluster.yml \
-b --become-user=root
`cluster.yml`이 아니라 `upgrade-cluster.yml` 을 사용해야 한다. `cluster.yml` 은 신규 설치용이다.
업그레이드는 보통 20~40분 소요되며, API server 10~30초 중단 + Worker drain 시 replica 1인 서비스는 잠시 중단될 수 있다.
Step 7. 업그레이드 검증
# 모든 노드 버전 확인
kubectl get nodes -o wide
# 비정상 Pod 확인
kubectl get pods -A | grep -v Running | grep -v Completed
# 클러스터 정보
kubectl cluster-info
# 컴포넌트 상태
kubectl get --raw='/readyz?verbose'
# containerd insecure registry 설정 유지 확인
ssh somaz@10.10.10.18 "cat /etc/containerd/certs.d/harbor.example.com/hosts.toml"
업그레이드 자동화 스크립트
아래의 github의 자동화 스크립트를 참고하면 위의 step의 과정들을 자동화 할 수 있다.
https://github.com/somaz94/script-collection/tree/main/bash/k8s-script/kubespray
script-collection/bash/k8s-script/kubespray at main · somaz94/script-collection
Contribute to somaz94/script-collection development by creating an account on GitHub.
github.com
인증서 자동 갱신
kubespray로 `upgrade-cluster.yml` 을 실행하면 kubeadm이 인증서를 자동 갱신한다.
자동 갱신되는 인증서
| 인증서 | 용도 | 갱신 여부 |
| apiserver.crt | API Server TLS | 자동 |
| apiserver-kubelet-client.crt | API → kubelet 통신 | 자동 |
| front-proxy-client.crt | API aggregation | 자동 |
| etcd/server.crt | etcd TLS | 자동 |
| etcd/peer.crt | etcd 피어 통신 | 자동 |
| admin.conf | kubectl 접속 | 자동 |
- kubeadm은 업그레이드 시 만료 1년 미만인 인증서를 자동 갱신한다. 기본 유효기간은 1년이다.
현재 인증서 만료일 확인
sudo kubeadm certs check-expiration
주의: 업그레이드 없이 1년 방치하면?
인증서가 만료되어 클러스터가 먹통이 된다. 그때는 수동 갱신이 필요하다.
sudo kubeadm certs renew all
sudo systemctl restart kubelet
권장: 1년 이내에 최소 1회 업그레이드를 수행하면 인증서가 자동 갱신되므로 별도 작업이 불필요하다.
아래의 스크립트를 사용해도 된다.
https://github.com/somaz94/script-collection/blob/main/bash/k8s-script/k8s_certs_renew.sh
script-collection/bash/k8s-script/k8s_certs_renew.sh at main · somaz94/script-collection
Contribute to somaz94/script-collection development by creating an account on GitHub.
github.com
업그레이드 에러 대응
health-check Job 실패
[ERROR CreateJob]: Job "upgrade-health-check-xxxxx" in the namespace "kube-system"
did not complete in 15s: no condition of type Complete
- `kubeadm upgrade` 가 `health check Job` 을 생성했는데 15초 내에 완료되지 않을 때 발생한다.
- 주로 이미지를 처음 당기는 경우에 시간이 초과되는 것이며, 재실행하면 이미지가 캐시되어 있어 대부분 해결된다.
확인
# 실패한 Job 확인
kubectl get jobs -n kube-system | grep upgrade-health
kubectl describe job <job-name> -n kube-system
# Pod 상태 확인
kubectl get pods -n kube-system | grep upgrade-health
해결
# Control Plane이 SchedulingDisabled 상태일 수 있으므로 먼저 uncordon
kubectl uncordon k8s-control-01
# 다시 실행
ansible-playbook -i inventory/somaz-cluster/inventory.ini \
upgrade-cluster.yml -b --become-user=root
containerd insecure registry 설정 초기화
업그레이드 시 containerd가 재설정되면서 직접 수정한 `hosts.toml` 이 덮어쓰여질 수 있다. kubespray inventory의 `containerd.yml` 에 설정이 포함되어 있으면 자동으로 유지된다.
# 업그레이드 후 설정 유지 확인
for node in 10.10.10.17 10.10.10.18 10.10.10.19 10.10.10.22; do
echo "=== $node ==="
ssh somaz@$node "cat /etc/containerd/certs.d/harbor.example.com/hosts.toml 2>/dev/null || echo 'NOT FOUND'"
echo ""
done
만약 설정이 날아갔다면 containerd 태그만 재실행하면 복구된다.
ansible-playbook -i inventory/somaz-cluster/inventory.ini cluster.yml \
--tags containerd -b --become-user=root
중요: insecure registry 설정은 서버에 직접 수정하지 말고, 반드시 kubespray inventory(`containerd.yml`)에서 관리해야 업그레이드 시에도 안전하다.
롤백
Kubespray는 자동 롤백을 지원하지 않는다. 업그레이드에 실패하면 Step 2에서 생성한 etcd 백업에서 복구해야 한다.
# etcd 복구
sudo ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-backup-YYYYMMDD.db \
--data-dir=/var/lib/etcd-restore
# 이후 수동으로 etcd 데이터 디렉토리 교체 필요
# 참고: https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#restoring-an-etcd-cluster
롤백은 복잡하고 위험한 작업이므로, 업그레이드 전 etcd 백업을 반드시 생성하고, 가능하면 staging 환경에서 먼저 테스트하는 것이 최선이다.
업그레이드 후 inventory 동기화
업그레이드가 완료되면 Control Plane의 inventory를 로컬(GitLab 등)에 백업해둔다.
# 로컬에서 실행
scp -r somaz@10.10.10.17:~/kubespray/inventory/somaz-cluster \
~/my-project/kubespray/inventory-somaz-cluster
버전 확인 스크립트를 만들어두면 업그레이드 전후 상태를 빠르게 비교할 수 있다.
#!/bin/bash
# check-version.sh
echo "=== K8s Version ==="
kubectl get nodes -o wide
echo ""
echo "=== Kubespray Version ==="
cd ~/kubespray && git describe --tags
echo ""
echo "=== Containerd Version ==="
containerd --version
echo ""
echo "=== Cilium Version ==="
kubectl get ds cilium -n kube-system -o=jsonpath='{.spec.template.spec.containers[0].image}'
echo ""
echo ""
echo "=== Certificate Expiration ==="
sudo kubeadm certs check-expiration 2>/dev/null | head -15
실제 업그레이드 사례: v1.33.3 → v1.34.3
2026.04.07에 실제로 수행한 업그레이드 과정을 기록한다.
환경
| 항목 | Before | After |
| Kubespray | v2.28.0 | v2.30.0 |
| Kubernetes | v1.33.3 | v1.34.3 |
| Cilium | v1.17.3 | v1.19.1 |
| containerd | v2.1.3 | v2.2.1 |
과정
- etcd 백업 생성
- upgrade-kubespray.sh --diff-only로 설정 변경사항 확인
- upgrade-kubespray.sh --target v2.30.0으로 Kubespray 전환
- upgrade-cluster.yml 실행
- health-check Job 실패로 1회 재실행
- 전체 노드 v1.34.3 업그레이드 완료 확인
- containerd insecure registry 설정 유지 확인
- inventory 로컬 동기화
발생한 이슈
health-check Job 15초 타임아웃
[ERROR CreateJob]: Job "upgrade-health-check-1775526129268" in the namespace "kube-system"
did not complete in 15s
- Control Plane은 이미 v1.34.3으로 업그레이드 완료되었지만 `SchedulingDisabled` 상태로 남아있었다.
- `kubectl uncordon k8s-control-01` 후 재실행하여 해결.
소요 시간
| 단계 | 시간 |
| etcd 백업 | 1분 |
| Kubespray 전환 (git checkout + pip install) | 3분 |
| upgrade-cluster.yml 1차 실행 (실패) | 11분 |
| upgrade-cluster.yml 2차 실행 (성공) | ~25분 |
| 검증 | 5분 |
| 합계 | ~45분 |
업그레이드 후 확인
k get nodes
NAME STATUS ROLES AGE VERSION
k8s-compute-01 Ready <none> 252d v1.34.3
k8s-compute-02 Ready <none> 252d v1.34.3
k8s-compute-03 Ready <none> 245d v1.34.3
k8s-control-01 Ready control-plane 252d v1.34.3
주의사항 정리
| 항목 | 설명 |
| etcd 백업 | 업그레이드 전 반드시 스냅샷 생성 — 유일한 롤백 수단 |
| 마이너 버전 | 한 번에 1 마이너 버전만 업그레이드 가능 |
| 플레이북 | `cluster.yml` 이 아니라 `upgrade-cluster.yml` 사용 |
| venv | kubespray의 Python venv 활성화 확인 (`source venv/bin/activate`) |
| StatefulSet | DB 등 StatefulSet Pod은 drain 시 데이터 확인 필요 |
| PDB | PodDisruptionBudget 설정 확인 `— drain` 이 차단될 수 있음 |
| Replica | 서비스 무중단을 위해 Deployment replica 2개 이상 권장 |
| insecure registry | inventory에서 관리해야 업그레이드 시에도 안전 |
| 인증서 | 1년 이내에 최소 1회 업그레이드하면 자동 갱신 |
| 피크 시간 회피 | 가능하면 서비스 트래픽이 적은 시간대에 진행 |
마무리: "업그레이드는 선택이 아니라 운영의 일부"
Kubernetes 클러스터 업그레이드는 번거로운 작업처럼 느껴지지만, Kubespray를 사용하면 Ansible 한 줄로 전체 클러스터를 업그레이드할 수 있다.
특히 다음 사항을 기억하자.
- etcd 백업은 보험이다. 업그레이드 전 반드시 생성하고, 복구 절차를 미리 숙지해둔다.
- 인증서는 1년이다. 업그레이드를 1년 이상 미루면 인증서 만료로 클러스터가 먹통이 된다.
- Diff를 확인하라. Kubespray 버전이 바뀌면 기본 설정값도 바뀐다. `--diff-only` 로 먼저 확인한다.
- containerd 설정은 inventory에서. 서버 직접 수정은 업그레이드 시 날아간다.
정기적인 업그레이드 습관을 만들면 보안 패치, 인증서 갱신, 새로운 기능 활용을 동시에 챙길 수 있다.
Reference
- Kubespray GitHub
- Kubespray Releases
- Kubespray Upgrade Guide
- etcd Backup/Restore
- Kubespray Node Management
- Cilium CNI Kubespray Docs
Somaz | DevOps Engineer | Kubernetes & Cloud Infrastructure Specialist
'Container Orchestration > Kubernetes' 카테고리의 다른 글
| Public Helm Chart Repository 구축하기 — 로컬 차트에서 ArtifactHub까지 (0) | 2026.04.24 |
|---|---|
| Kubernetes 1.34.x gRPC etcd Warning 버그 상세 분석 (0) | 2026.04.20 |
| Kubernetes 클러스터 구축하기(kubespray 2026v.) (0) | 2026.04.08 |
| Kubernetes Probe (Liveness, Readiness, Startup) (0) | 2026.04.06 |
| 누가 kubectl edit 했어? — Kubernetes Cluster Drift 감지 도구 직접 만들기 (0) | 2026.03.23 |