버전 차이(skew) 정책
공식 문서: https://kubernetes.io/ko/releases/version-skew-policy/
kubelet 을 제외하고 쿠버네티스 모든 구성 요소들은 컨테이너로 구성되어 있고 버전을 업그레이드 할 때 이미지를 교체하는 것이기 때문에 모든 컨테이너를 종료하고 교체한 이미지로 컨테이너를 띄우기 때문에 쿠버네티스에 다운 타임이 발생한다.
그러면 무중단 시스템을 위해 버전을 업그레이드하기 위해서는 어떻게 해야하는지가 이 문서에 나와 있다.
지원되는 버전
쿠버네티스 버전은 x.y.z 로 표현되는데, 여기서 x 는 메이저 버전, y 는 마이너 버전, z 는 패치 버전을 의미
쿠버네티스 프로젝트는 최근 세 개의 마이너 릴리스 (1.24, 1.23, 1.22) 에 대한 릴리스 분기를 유지한다. 쿠버네티스 1.19 이상은 약 1년간의 패치 지원을 받는다. 쿠버네티스 1.18 이상은 약 9개월의 패치 지원을 받는다.
지원되는 버전 차이
고가용성 클러스터에서 마스터 api-server 버전이 다를 경우 각각의 api-server 는 통신할 수 없다. 만약 최신 api-server 버전이 1.24 일 경우 1.23, 1.22 를 지원한다.
예:
- 최신 kube-apiserver는 1.24 이다.
- 다른 kube-apiserver 인스턴스는 1.24 및 1.23 을 지원한다.
kubelet은 kube-apiserver보다 최신일 수 없으며, 2단계의 낮은 마이너 버전까지 지원한다.
예:
- kube-apiserver가 1.24 이다.
- kubelet은 1.24, 1.23 및 1.22 을 지원한다.
예:
- kube-apiserver 인스턴스는 1.24 및 1.23 이다.(즉, 마스터가 2대)
- kubelet은 1.23 및 1.22 을 지원한다(1.24 는 kube-apiserver의 1.23 인스턴스보다 최신 버전이기 때문에 지원하지 않는다).
kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager 는 그들과 통신하는 kube-apiserver 인스턴스보다 최신 버전이면 안 된다. kube-apiserver 마이너 버전과 일치할 것으로 예상하지만, 최대 한 단계 낮은 마이너 버전까지는 허용한다(실시간 업그레이드를 지원하기 위해서).
- kube-apiserver은 1.24 이다.
- kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager는 1.24 과 1.23 을 지원한다.
예:
- kube-apiserver 인스턴스는 1.24 및 1.23 이다.(즉, 마스터가 2대)
- kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager는 모든 kube-apiserver 인스턴스로 라우팅하는 로드 밸런서와 통신한다.
- kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager는 1.23 에서 지원한다(1.24 는 kube-apiserver 인스턴스의 1.23 버전보다 최신이기 때문에 지원하지 않는다).
kubectl은 kube-apiserver의 한 단계 마이너 버전(이전 또는 최신) 내에서 지원한다.
예:
- kube-apiserver은 1.24 이다.
- kubectl은 1.25, 1.24 및 1.23 을 지원한다.
kubectl 를 먼저 업그레이드하고 그 후에 api-server 업그레이드를 하거나 api-server 를 업그레이드하고 kubectl 를 업그레이드할 수 있기 때문이다.
k8s 클러스터 업그레이드 예제
아래 순서대로 업그레이드를 진행한다.
kube-apiserver 업그레이드
사전 요구 사항:
- 단일 인스턴스 클러스터에서 기존 kube-apiserver 인스턴스는 1.23 이어야 한다.
- HA 클러스터에서 모든 kube-apiserver 인스턴스는 1.23 또는 1.24 이어야 한다(이것은 kube-apiserver 인스턴스 간의 가장 최신과 오래된 버전의 차이를 최대 1개의 마이너 버전의 차이로 보장한다).
- 이 서버와 통신하는 kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager의 버전은 1.23 이어야 한다(이것은 기존 API서버 버전보다 최신 버전이 아니고 새로운 API서버 버전의 마이너 1개의 버전 내에 있음을 보장한다).
- 모든 kubelet 인스턴스는 버전 1.23 또는 1.22 이어야 한다(이것은 기존 API서버 버전보다 최신 버전이 아니며, 새로운 API서버 버전의 2개의 마이너 버전 내에 있음을 보장한다).
- 등록된 어드미션 웹훅은 새로운 kube-apiserver 인스턴스가 전송하는 데이터를 처리할 수 있다:
- ValidatingWebhookConfiguration 그리고 MutatingWebhookConfiguration 오브젝트는 1.24 에 추가된 REST 리소스의 새 버전을 포함하도록 업데이트한다(또는 v1.15 이상에서 사용 가능한 [matchPolicy: Equivalent option](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-matchpolicy) 설정을 사용).
- 웹훅은 자신에게 전송될 REST리소스의 새버전과 1.24 에서 기존 버전에 추가된 새로운 필드를 처리할 수 있다.
kube-apiserver를 1.24 으로 업그레이드
kube-controller-manager, kube-scheduler 그리고 cloud-controller-manager 업그레이드
사전 요구 사항:
- kube-apiserver 인스턴스는 1.24 이여야 한다(HA 클러스터에서 kube-apiserver 인스턴스와 통신할 수 있는 구성 요소를 업그레이드 전에 모든 kube-apiserver 인스턴스는 업그레이드되어야 한다).
kube-controller-manager, kube-scheduler 및 cloud-controller-manager 를 1.24 으로 업그레이드한다.
kubelet 업그레이드
컨트롤 플레인에서 먼저 업그레이드를 하고 후에 워커 노드에서 kubelet 업그레이드를 한다.
kubelet → docker → container 이런 방식으로 kubelet 이 컨테이너를 제어한다.
그렇기 때문에 kubelet 을 업그레이드하면 컨테이너가 중지된다. 그래서 업그레이드를 하기 전에 컨테이너를 제거해야 한다. 이를 드레인이라
사전 요구 사항:
- kubelet과 통신하는 kube-apiserver 인스턴스는 1.24 이어야 한다.
필요에 따라서 kubelet 인스턴스를 1.24 으로 업그레이드할 수 있다(또는 1.23 아니면 1.22 으로 유지할 수 있음).
kubelet → docker → container 이런 방식으로 kubelet 이 컨테이너를 제어한다.
그렇기 때문에 kubelet 을 업그레이드하면 컨테이너가 중지된다. 그래서 업그레이드를 하기 전에 컨테이너를 제거해야 한다. 컨테이너를 제거하는 작업을 드레인이라고 한다.
참고: kubelet 마이너 버전 업그레이드를 수행하기 전에, 해당 노드의 파드를 드레인(drain)해야 한다. 인플레이스(In-place) 마이너 버전 kubelet 업그레이드는 지원되지 않는다.
경고: 클러스터 안의 kubelet 인스턴스를 kube-apiserver의 버전보다 2단계 낮은 버전으로 실행하는 것을 권장하지 않는다: • kube-apiserver를 업그레이드한다면 한 단계 낮은 버전으로 업그레이드해야 한다. • 이것은 관리되고 있는 3단계의 마이너 버전보다 낮은 kubelet을 실행할 가능성을 높인다.
kube-proxy 업그레이드
- kube-proxy는 반드시 kubelet과 동일한 마이너 버전이어야 한다.
- kube-proxy는 반드시 kube-apiserver 보다 최신 버전이면 안 된다.
- kube-proxy는 kube-apiserver 보다 2단계 낮은 마이너 버전 이내여야 한다.
예:
kube-proxy 버전이 1.22 인 경우:
- kubelet 버전도 반드시 1.22 와 동일한 마이너 버전이어야 한다.
- kube-apiserver 버전은 반드시 1.22 에서 1.24 사이 이어야 한다.
정리하자면 순서는 다음과 같다.
- kube-apiserver
- kube-controller-manager, kube-scheduler, cloud-controller-manager
- kubelet(Control Plane → Worker Node)
- kube-proxy(Control Plane → Worker Node)
Controle Plane(api → cm, ccm, sched → let, proxy) → Worker Node(let, proxy)
kubeadm 클러스터 업그레이드
공식 문서: https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/
추상적인 업그레이드 작업 절차는 다음과 같다.
- 기본 컨트롤 플레인 노드를 업그레이드한다.
- 추가 컨트롤 플레인 노드를 업그레이드한다.
- 워커(worker) 노드를 업그레이드한다.
업그레이드할 버전 결정
OS 패키지 관리자를 사용하여 쿠버네티스의 최신 패치 릴리스 버전(1.24)을 찾는다.
ubuntu, debian 또는 Hypriot OS
apt update
apt-cache madison kubeadm
# 목록에서 최신 버전(1.24)을 찾는다
# 1.24.x-00과 같아야 한다. 여기서 x는 최신 패치이다.
"kubeadm upgrade" 호출
첫 번째 컨트롤 플레인 노드의 경우
- kubeadm 업그레이드
# 1.24.x-00에서 x를 최신 패치 버전으로 바꾼다.
apt-mark unhold kubeadm && \\
apt-get update && apt-get install -y kubeadm=1.24.x-00 && \\
apt-mark hold kubeadm
- 다운로드하려는 버전이 잘 받아졌는지 확인한다.
- kubeadm version
- 업그레이드 계획을 확인한다.이 명령은 클러스터를 업그레이드할 수 있는지를 확인하고, 업그레이드할 수 있는 버전을 가져온다. 또한 컴포넌트 구성 버전 상태가 있는 표를 보여준다.
- kubeadm upgrade plan
- 업그레이드할 버전을 선택하고, 적절한 명령을 실행한다. 예를 들면 다음과 같다.명령이 완료되면 다음을 확인해야 한다.
- [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.24.x". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
- *# 이 업그레이드를 위해 선택한 패치 버전으로 x를 바꾼다.* sudo kubeadm upgrade apply v1.24.x
- CNI 제공자 플러그인을 수동으로 업그레이드한다.CNI 제공자가 데몬셋(DaemonSet)으로 실행되는 경우 추가 컨트롤 플레인 노드에는 이 단계가 필요하지 않다.
- CNI(컨테이너 네트워크 인터페이스) 제공자는 자체 업그레이드 지침을 따를 수 있다. 애드온 페이지에서 사용하는 CNI 제공자를 찾고 추가 업그레이드 단계가 필요한지 여부를 확인한다.
다른 컨트롤 플레인 노드의 경우
첫 번째 컨트롤 플레인 노드와 동일하지만 다음을 사용한다.
sudo kubeadm upgrade node
아래 명령 대신 위의 명령을 사용한다.
sudo kubeadm upgrade apply
kubeadm upgrade plan 을 호출하고 CNI 공급자 플러그인을 업그레이드할 필요가 없다.
노드 드레인
- Prepare the node for maintenance by marking it unschedulable and evicting the workloads:
# <node-to-drain>을 드레인하는 노드의 이름으로 바꾼다.
kubectl drain <node-to-drain> --ignore-daemonsets
kubelet과 kubectl 업그레이드
- 모든 컨트롤 플레인 노드에서 kubelet 및 kubectl을 업그레이드한다.
# replace x in 1.24.x-00의 x를 최신 패치 버전으로 바꾼다
apt-mark unhold kubelet kubectl && \\
apt-get update && apt-get install -y kubelet=1.24.x-00 kubectl=1.24.x-00 && \\
apt-mark hold kubelet kubectl
- kubelet을 다시 시작한다.
sudo systemctl daemon-reload
sudo systemctl restart kubelet
노드 uncordon
- 노드를 스케줄 가능으로 표시하여 노드를 다시 온라인 상태로 전환한다.
*# <node-to-drain>을 드레인하는 노드의 이름으로 바꾼다.*
kubectl uncordon <node-to-drain>
워커 노드 업그레이드
워커 노드의 업그레이드 절차는 워크로드를 실행하는 데 필요한 최소 용량을 보장하면서, 한 번에 하나의 노드 또는 한 번에 몇 개의 노드로 실행해야 한다.
kubeadm 업그레이드
- 모든 워커 노드에서 kubeadm을 업그레이드한다.
# 1.24.x-00의 x를 최신 패치 버전으로 바꾼다
apt-mark unhold kubeadm && \\
apt-get update && apt-get install -y kubeadm=1.24.x-00 && \\
apt-mark hold kubeadm
"kubeadm upgrade" 호출
- 워커 노드의 경우 로컬 kubelet 구성을 업그레이드한다.
sudo kubeadm upgrade node
노드에 적용된 cordon 해제
- 스케줄 가능(schedulable)으로 표시하여 노드를 다시 온라인 상태로 만든다.
# <node-to-drain>을 노드의 이름으로 바꾼다.
kubectl uncordon <node-to-drain>
클러스터 상태 확인
모든 노드에서 kubelet을 업그레이드한 후 kubectl이 클러스터에 접근할 수 있는 곳에서 다음의 명령을 실행하여 모든 노드를 다시 사용할 수 있는지 확인한다.
kubectl get nodes
모든 노드에 대해 STATUS 열에 Ready 가 표시되어야 하고, 버전 번호가 업데이트되어 있어야 한다.
정리
- Control Plane 의 kubeadm 업그레이드
- Control Plane 의 kubeadm 으로 api, cm, sched 업그레이드
- Control Plane 의 kubelet, kubectl 업그레이드
- Worker Node 의 kubeadm 업그레이드
- Worker Node 의 kubeadm 으로 업그레이드
- Worker Node 의 kubelet, kubectl 업그레이드
작동 원리
kubeadm upgrade apply 는 다음을 수행한다.
- 클러스터가 업그레이드 가능한 상태인지 확인한다.
- API 서버에 접근할 수 있다
- 모든 노드가 Ready 상태에 있다
- 컨트롤 플레인이 정상적으로 동작한다
- 버전 차이(skew) 정책을 적용한다.
- 컨트롤 플레인 이미지가 사용 가능한지 또는 머신으로 가져올 수 있는지 확인한다.
- 컴포넌트 구성에 버전 업그레이드가 필요한 경우 대체 구성을 생성하거나 사용자가 제공한 것으로 덮어 쓰기한다.
- 컨트롤 플레인 컴포넌트 또는 롤백 중 하나라도 나타나지 않으면 업그레이드한다.
- 새로운 CoreDNS 와 kube-proxy 매니페스트를 적용하고 필요한 모든 RBAC 규칙이 생성되도록 한다.
- API 서버의 새 인증서와 키 파일을 작성하고 180일 후에 만료될 경우 이전 파일을 백업한다.
kubeadm upgrade node 는 추가 컨트롤 플레인 노드에서 다음을 수행한다.
- 클러스터에서 kubeadm ClusterConfiguration 을 가져온다.
- 선택적으로 kube-apiserver 인증서를 백업한다.
- 컨트롤 플레인 컴포넌트에 대한 정적 파드 매니페스트를 업그레이드한다.
- 이 노드의 kubelet 구성을 업그레이드한다.
kubeadm upgrade node 는 워커 노드에서 다음을 수행한다.
- 클러스터에서 kubeadm ClusterConfiguration 을 가져온다.
- 이 노드의 kubelet 구성을 업그레이드한다.