11.2 버전 정책과 업그레이드
Kubernetes는 연 3회 마이너 버전을 릴리스하고, 최신 3개 마이너 버전만 패치를 받는다. 지금 최신 버전으로 구축한 클러스터도 1년 남짓이면 지원 목록에서 제외된다는 뜻이라, 업그레이드는 선택이 아니라 주기적으로 돌아오는 운영 업무다. 관리형 서비스는 control plane 업그레이드를 대신 실행해 주지만, kubeadm 클러스터에서는 순서 설계와 사전 검증까지 전부 운영자의 일이다.
릴리스 주기와 지원 기간
버전은 x.y.z 형태다. y가 마이너 버전으로 기능 추가와 API 변경이 들어오고, z가 패치 버전으로 버그와 보안 수정만 들어온다. 마이너 릴리스는 2021년부터 연 3회 주기로 나오고, 각 마이너 버전은 1.19부터 약 14개월(12개월 패치 지원과 2개월의 업그레이드 유예) 동안 유지된다. 패치 릴리스는 대략 월 단위로 나온다.
이 주기가 운영에 주는 함의는 단순하다. 최소 연 1회는 마이너 업그레이드를 하지 않으면 보안 패치를 받지 못하는 버전에 도달한다. 업그레이드를 오래 미룰수록 한 번에 건너야 할 마이너 수가 늘고, 뒤에서 볼 “한 번에 한 마이너” 제약 때문에 작업 횟수가 그대로 늘어난다.
버전 스큐 정책
클러스터의 모든 컴포넌트가 같은 버전일 필요는 없다. 업그레이드가 순차적으로 진행되는 동안 버전이 섞이는 것은 불가피하고, Kubernetes는 어느 조합까지 지원하는지를 버전 스큐(version skew) 정책으로 정의한다. 기준점은 kube-apiserver다.
| 컴포넌트 | kube-apiserver 대비 허용 범위 |
|---|---|
| kube-apiserver (HA 인스턴스 간) | 1 마이너 이내 |
| kubelet | 같거나 최대 3 마이너 낮게 |
| kube-controller-manager, kube-scheduler | 같거나 1 마이너 낮게 |
| kube-proxy | 같거나 최대 3 마이너 낮게 |
| kubectl | 1 마이너 높거나 낮거나 같게 |
방향이 비대칭이라는 점을 먼저 읽어야 한다. kubelet은 apiserver보다 낮을 수는 있어도 높을 수는 없다. 새 kubelet은 apiserver가 아직 모르는 API 필드와 동작을 전제할 수 있기 때문이다. 이 비대칭에서 “control plane을 먼저 올린다"는 업그레이드 순서가 도출된다. 참고로 kubelet의 허용 폭은 1.28에서 2 마이너에서 3 마이너로 늘었다.
허용 폭이 3 마이너라는 것은 노드 업그레이드를 control plane보다 몇 사이클 늦출 수 있다는 뜻이지, 늦추는 것이 좋다는 뜻은 아니다. 스큐가 클수록 기능별로 “apiserver는 지원하지만 kubelet은 모르는” 조합이 늘어난다.
업그레이드 순서와 kubeadm 절차
순서 규칙은 두 개다. control plane이 먼저, 그리고 한 번에 한 마이너씩이다. 마이너를 건너뛰는 업그레이드는 지원되지 않고 kubeadm도 거부한다. 1.29에서 1.31로 가려면 1.30을 반드시 경유한다.
flowchart TD
P["사전 점검과 etcd 백업"] --> A["첫 control plane<br/>upgrade apply"]
A --> B["나머지 control plane<br/>upgrade node"]
B --> C["워커 drain"]
C --> D["kubelet 패키지 교체<br/>재시작"]
D --> E["uncordon"]
E --> F{"남은 워커?"}
F -->|"있음"| C
F -->|"없음"| G["완료"]
첫 번째 control plane 노드에서는 kubeadm 패키지를 먼저 목표 버전으로 교체한 뒤 계획을 확인한다.
sudo kubeadm upgrade planupgrade plan은 현재 클러스터 버전, 올라갈 수 있는 목표 버전, 컴포넌트별 현재/목표 버전, 수동 업그레이드가 필요한 항목(kubelet)을 표로 보여 준다. 실제 적용은 apply다.
sudo kubeadm upgrade apply v1.31.0apply는 새 버전의 control plane static Pod 매니페스트를 작성해 컴포넌트를 하나씩 교체하고, etcd를 함께 올리며, 이 과정에서 관리 인증서도 자동 갱신한다. 두 번째 이후의 control plane 노드와 워커에서는 kubeadm upgrade node를 실행한다. 클러스터 설정은 이미 갱신되어 있으므로 로컬 kubelet 구성만 내려받아 반영하는, apply보다 가벼운 명령이다.
kubeadm이 올려 주는 것은 control plane까지다. 각 노드의 kubelet 바이너리는 패키지 관리자로 직접 교체하고, 교체 전에 노드를 비운다.
kubectl drain node-1 --ignore-daemonsets
# 해당 노드에서: kubeadm upgrade node 실행 후
sudo apt-get install -y kubelet=1.31.0-* kubectl=1.31.0-*
sudo systemctl daemon-reload && sudo systemctl restart kubelet
kubectl uncordon node-1drain과 uncordon을 노드마다 반복하므로, 워크로드가 옮겨 다닐 여유 용량이 있는지가 업그레이드 소요 시간을 결정한다. drain의 동작과 멈추는 경우는 11.4에서 다룬다.
업그레이드 전에 확인할 것
kubeadm 명령 자체보다 사전 확인이 사고를 줄인다. 세 가지가 반복적으로 문제를 만든다.
제거된 API 사용 여부가 첫 번째다. 마이너 릴리스는 deprecated 상태였던 API 버전을 실제로 제거한다. 1.25의 PodSecurityPolicy, 1.22의 extensions/v1beta1 Ingress가 대표 사례다. 제거된 버전을 참조하는 매니페스트와 Helm 차트는 업그레이드 후 apply가 실패한다. apiserver가 노출하는 apiserver_requested_deprecated_apis 메트릭과 감사 로그로 실제 호출 여부를 확인하고, 공식 Deprecated API Migration Guide에서 목표 버전의 제거 목록을 대조한다.
두 번째는 PDB다. 워커 업그레이드는 노드 drain의 연속이라, ALLOWED DISRUPTIONS가 0인 PodDisruptionBudget이 하나라도 있으면 그 시점에 절차가 멈춘다. 업그레이드 전에 kubectl get pdb -A로 여유가 없는 PDB를 미리 찾아 둔다.
세 번째는 etcd 백업이다. upgrade apply는 etcd도 함께 올리므로, 실패 시 되돌아갈 지점으로 직전 스냅샷이 있어야 한다. 릴리스 노트의 Urgent Upgrade Notes 절도 이때 같이 읽는다. 기본 동작이 바뀌는 변경은 이 절에 모여 있다.
정리
업그레이드의 골격은 두 규칙이다. control plane이 먼저, 한 번에 한 마이너씩. 나머지는 준비 작업이라서, 제거된 API 점검과 PDB 확인과 etcd 스냅샷이 끝나 있으면 kubeadm upgrade 자체는 절차대로 진행되는 작업에 가깝다. 연 3회 릴리스와 14개월 지원이라는 주기를 받아들이고 업그레이드를 정기 일정으로 두는 편이, 지원 종료에 몰려 여러 마이너를 연달아 건너는 것보다 훨씬 다루기 쉽다.