Container Orchestration/Kubernetes

Kubernetes 클러스터 업그레이드하기 (kubespray 2026v.)

Somaz 2026. 4. 13. 00:00
728x90
반응형

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

 

 

과정

  1. etcd 백업 생성
  2. upgrade-kubespray.sh --diff-only로 설정 변경사항 확인
  3. upgrade-kubespray.sh --target v2.30.0으로 Kubespray 전환
  4. upgrade-cluster.yml 실행
  5. health-check Job 실패로 1회 재실행
  6. 전체 노드 v1.34.3 업그레이드 완료 확인
  7. containerd insecure registry 설정 유지 확인
  8. 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

 

 

 

 

 

 

 

Somaz | DevOps Engineer | Kubernetes & Cloud Infrastructure Specialist

728x90
반응형