22 KiB
22 KiB
kubeadm 클러스터 업그레이드 가이드
구성 요소 및 버전
- kubeadm, kubelet, kubectl
Prerequisites
- upgrade 할 kubeadm version 선택
yum list --showduplicates kubeadm --disableexcludes=kubernetes - 하나의 MINOR 버전에서 다음 MINOR 버전으로, 또는 동일한 MINOR의 PATCH 버전 사이에서만 업그레이드할 수 있다.
- 즉, 업그레이드할 때 MINOR 버전을 건너 뛸 수 없다. 예를 들어, 1.y에서 1.y+1로 업그레이드할 수 있지만, 1.y에서 1.y+2로 업그레이드할 수는 없다.
- ex) 1.15 버전에서 1.17 버전으로 한번에 업그레이드는 불가능 하다. 1.15 -> 1.16 -> 1.17 스텝을 진행 해야 한다.
- runtime으로 crio 사용시, CRI-O 메이저와 마이너 버전은 쿠버네티스 메이저와 마이너 버전이 일치해야 한다. 따라서 업데이트한 쿠버네티스 버전에 따라 crio 버전도 함께 업데이트 한다.
폐쇄망 가이드
-
폐쇄망에서 설치하는 경우 아래 가이드를 참고 하여 image registry를 먼저 구축한다.
-
사용하는 image repository에 k8s 설치 시 필요한 이미지를 push한다.
- 작업 디렉토리 생성 및 환경 설정
$ mkdir -p ~/k8s-install $ cd ~/k8s-install- 외부 네트워크 통신이 가능한 환경에서 필요한 이미지를 다운받는다. (1.15.x -> 1.17.x으로 upgrade 하는 경우 두 버전의 image들이 모두 필요하다)
- v1.16.15 images
$ sudo docker pull k8s.gcr.io/kube-proxy:v1.16.15 $ sudo docker pull k8s.gcr.io/kube-apiserver:v1.16.15 $ sudo docker pull k8s.gcr.io/kube-controller-manager:v1.16.15 $ sudo docker pull k8s.gcr.io/kube-scheduler:v1.16.15 $ sudo docker pull k8s.gcr.io/etcd:3.3.15-0 $ sudo docker pull k8s.gcr.io/coredns:1.6.2 $ sudo docker pull k8s.gcr.io/pause:3.1- v1.17.6 images
$ sudo docker pull k8s.gcr.io/kube-proxy:v1.17.6 $ sudo docker pull k8s.gcr.io/kube-apiserver:v1.17.6 $ sudo docker pull k8s.gcr.io/kube-controller-manager:v1.17.6 $ sudo docker pull k8s.gcr.io/kube-scheduler:v1.17.6 $ sudo docker pull k8s.gcr.io/etcd:3.4.3-0 $ sudo docker pull k8s.gcr.io/coredns:1.6.5 $ sudo docker pull k8s.gcr.io/pause:3.1- docker image를 tar로 저장한다.
- v1.16.15 images
$ sudo docker save -o kube-proxy-1.16.tar k8s.gcr.io/kube-proxy:v1.16.15 $ sudo docker save -o kube-controller-manager-1.16.tar k8s.gcr.io/kube-apiserver:v1.16.15 $ sudo docker save -o etcd-1.16.tar k8s.gcr.io/etcd:3.3.15-0 $ sudo docker save -o coredns-1.16.tar k8s.gcr.io/coredns:1.6.2 $ sudo docker save -o kube-scheduler-1.16.tar k8s.gcr.io/kube-scheduler:v1.16.15 $ sudo docker save -o kube-apiserver-1.16.tar k8s.gcr.io/kube-apiserver:v1.16.15 $ sudo docker save -o pause-1.16.tar k8s.gcr.io/pause:3.1- v1.17.6 images
$ sudo docker save -o kube-proxy-1.17.tar k8s.gcr.io/kube-proxy:v1.17.6 $ sudo docker save -o kube-controller-manager-1.17.tar k8s.gcr.io/kube-controller-manager:v1.17.6 $ sudo docker save -o etcd-1.17.tar k8s.gcr.io/etcd:3.4.3-0 $ sudo docker save -o coredns-1.17.tar k8s.gcr.io/coredns:1.6.5 $ sudo docker save -o kube-scheduler-1.17.tar k8s.gcr.io/kube-scheduler:v1.17.6 $ sudo docker save -o kube-apiserver-1.17.tar k8s.gcr.io/kube-apiserver:v1.17.6 $ sudo docker save -o pause-1.17.tar k8s.gcr.io/pause:3.1 -
위의 과정에서 생성한 tar 파일들을 폐쇄망 환경으로 이동시킨 뒤 사용하려는 registry에 이미지를 push한다.
- v1.16.15 images
$ sudo docker load -i kube-apiserver-1.16.tar $ sudo docker load -i kube-scheduler-1.16.tar $ sudo docker load -i kube-controller-manager-1.16.tar $ sudo docker load -i kube-proxy-1.16.tar $ sudo docker load -i etcd-1.16.tar $ sudo docker load -i coredns-1.16.tar $ sudo docker load -i pause-1.16.tar$ sudo docker tag k8s.gcr.io/kube-apiserver:v1.16.15 ${REGISTRY}/k8s.gcr.io/kube-apiserver:v1.16.15 $ sudo docker tag k8s.gcr.io/kube-proxy:v1.16.15 ${REGISTRY}/k8s.gcr.io/kube-proxy:v1.16.15 $ sudo docker tag k8s.gcr.io/kube-controller-manager:v1.16.15 ${REGISTRY}/k8s.gcr.io/kube-controller-manager:v1.16.15 $ sudo docker tag k8s.gcr.io/etcd:3.3.15-0 ${REGISTRY}/k8s.gcr.io/etcd:3.3.15-0 $ sudo docker tag k8s.gcr.io/coredns:1.6.2 ${REGISTRY}/k8s.gcr.io/coredns:1.6.2 $ sudo docker tag k8s.gcr.io/kube-scheduler:v1.16.15 ${REGISTRY}/k8s.gcr.io/kube-scheduler:v1.16.15 $ sudo docker tag k8s.gcr.io/pause:3.1 ${REGISTRY}/k8s.gcr.io/pause:3.1$ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-apiserver:v1.16.15 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-proxy:v1.16.15 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-controller-manager:v1.16.15 $ sudo docker push ${REGISTRY}/k8s.gcr.io/etcd:3.3.15-0 $ sudo docker push ${REGISTRY}/k8s.gcr.io/coredns:1.6.2 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-scheduler:v1.16.15 $ sudo docker push ${REGISTRY}/k8s.gcr.io/pause:3.1- v1.17.6 images
$ sudo docker load -i kube-apiserver-1.17.tar $ sudo docker load -i kube-scheduler-1.17.tar $ sudo docker load -i kube-controller-manager-1.17.tar $ sudo docker load -i kube-proxy-1.17.tar $ sudo docker load -i etcd-1.17.tar $ sudo docker load -i coredns-1.17.tar $ sudo docker load -i pause-1.17.tar$ sudo docker tag k8s.gcr.io/kube-apiserver:v1.17.6 ${REGISTRY}/k8s.gcr.io/kube-apiserver:v1.17.6 $ sudo docker tag k8s.gcr.io/kube-proxy:v1.17.6 ${REGISTRY}/k8s.gcr.io/kube-proxy:v1.17.6 $ sudo docker tag k8s.gcr.io/kube-controller-manager:v1.17.6 ${REGISTRY}/k8s.gcr.io/kube-controller-manager:v1.17.6 $ sudo docker tag k8s.gcr.io/etcd:3.4.3-0 ${REGISTRY}/k8s.gcr.io/etcd:3.4.3-0 $ sudo docker tag k8s.gcr.io/coredns:1.6.5 ${REGISTRY}/k8s.gcr.io/coredns:1.6.5 $ sudo docker tag k8s.gcr.io/kube-scheduler:v1.17.6 ${REGISTRY}/k8s.gcr.io/kube-scheduler:v1.17.6 $ sudo docker tag k8s.gcr.io/pause:3.1 ${REGISTRY}/k8s.gcr.io/pause:3.1$ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-apiserver:v1.17.6 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-proxy:v1.17.6 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-controller-manager:v1.17.6 $ sudo docker push ${REGISTRY}/k8s.gcr.io/etcd:3.4.3-0 $ sudo docker push ${REGISTRY}/k8s.gcr.io/coredns:1.6.5 $ sudo docker push ${REGISTRY}/k8s.gcr.io/kube-scheduler:v1.17.6 $ sudo docker push ${REGISTRY}/k8s.gcr.io/pause:3.1
Steps
Step0. kubernetes master upgrade
- master에서 kubeadm을 upgrade 한다.
yum install -y kubeadm-설치버전 --disableexcludes=kubernetes ex) yum install -y kubeadm-1.16.0-0 --disableexcludes=kubernetes ex) yum install -y kubeadm-1.17.6-0 --disableexcludes=kubernetes - 버전 확인
kubeadm version - node drain
- node drain 전 체크 사항
- PDB가 존재하는 Pod가 drain하려는 node에 생성되어있는 경우 evict가 제한 되기 때문에, 아래 명령어로 drain이 가능한 상태인지 확인한다.
kubectl get pdb -A or kubectl get pdb <pdb-name> -oyaml- ALLOWED DISRUPTIONS 및 drain 시키려는 node의 pod 상태를 확인한다.
- PDB의 ALLOWED DISRUPTIONS가 drain을 시도하는 node에 뜬 pod(pdb 설정 pod) 개수보다 적을 경우 아래와 같이 다른 노드로 재스케줄링이 필요하다.
- ex) virt-api pod가 drain하려는 node에 2개 떠있는데, ALLOWED DISRUPTIONS는 0 또는 1일 경우
- 해당 조건에 만족하지 않는 경우 'Cannot evict pod as it would violate the pod's disruption budget' 와 같은 에러가 발생할 수 있다.
- 해결 방법
-
- 해당 Pod를 다른 Node로 재스케줄링을 시도한다.
kubectl delete pod <pod-name>-
- 다른 Node의 리소스 부족, noScheduling 설정 등으로 인해 a번 재스케줄링이 불가할 경우엔 PDB 데이터를 삭제하고 drain한 후에 PDB 데이터를 복구한다.
kubectl get pdb <pdb-name> -o yaml > pdb-backup.yaml kubectl drain <node-to-drain> --ignore-daemonsets --delete-local-data kubectl apply -f pdb-backup.yaml -
- node drain 실행
- warning: node drain시 해당 node상의 pod가 evict되기 때문에, pod의 local-data의 경우 보존되지 않음
kubectl drain <node-to-drain> --ignore-daemonsets --delete-local-data ex) kubectl drain k8s-master --ignore-daemonsets --delete-local-data
- node drain 전 체크 사항
- 업그레이드 plan 변경
sudo kubeadm upgrade plan- 업그레이드 시 kubeadm config 변경이 필요할 경우
sudo kubeadm upgrade plan --config=kubeadm_config.yaml[upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.15.3 [upgrade/versions] kubeadm version: v1.16.0 [upgrade/versions] Latest stable version: v1.16.0 [upgrade/versions] Latest version in the v1.15 series: v1.16.0 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT AVAILABLE Kubelet 1 x v1.15.3 v1.16.0 Upgrade to the latest version in the v1.17 series: COMPONENT CURRENT AVAILABLE API Server v1.15.3 v1.16.0 Controller Manager v1.15.3 v1.16.0 Scheduler v1.15.3 v1.16.0 Kube Proxy v1.15.3 v1.16.0 CoreDNS 1.6.5 1.6.7 Etcd 3.4.3 3.4.3-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.16.0 _____________________________________________________________________ - 업그레이드 실행
(1.15.x-> 1.16.x) sudo kubeadm upgrade apply v1.16.x (1.16.x-> 1.17.x) sudo kubeadm upgrade apply v1.17.x[upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade/version] You have chosen to change the cluster version to "v1.16.0" [upgrade/versions] Cluster version: v1.15.3 [upgrade/versions] kubeadm version: v1.16.0 [upgrade/confirm] Are you sure you want to proceed with the upgrade? [y/N]: y [upgrade/prepull] Will prepull images for components [kube-apiserver kube-controller-manager kube-scheduler etcd] [upgrade/prepull] Prepulling image for component etcd. [upgrade/prepull] Prepulling image for component kube-apiserver. [upgrade/prepull] Prepulling image for component kube-controller-manager. [upgrade/prepull] Prepulling image for component kube-scheduler. [apiclient] Found 1 Pods for label selector k8s-app=upgrade-prepull-kube-controller-manager [apiclient] Found 0 Pods for label selector k8s-app=upgrade-prepull-etcd [apiclient] Found 0 Pods for label selector k8s-app=upgrade-prepull-kube-scheduler [apiclient] Found 1 Pods for label selector k8s-app=upgrade-prepull-kube-apiserver [apiclient] Found 1 Pods for label selector k8s-app=upgrade-prepull-etcd [apiclient] Found 1 Pods for label selector k8s-app=upgrade-prepull-kube-scheduler [upgrade/prepull] Prepulled image for component etcd. [upgrade/prepull] Prepulled image for component kube-apiserver. [upgrade/prepull] Prepulled image for component kube-controller-manager. [upgrade/prepull] Prepulled image for component kube-scheduler. [upgrade/prepull] Successfully prepulled the images for all the control plane components [upgrade/apply] Upgrading your Static Pod-hosted control plane to version "v1.16.0"... ...... [apiclient] Found 1 Pods for label selector component=kube-scheduler [upgrade/staticpods] Component "kube-scheduler" upgraded successfully! [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.16" in namespace kube-system with the configuration for the kubelets in the cluster [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.16" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.16.0". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. - 적용된 cordon을 해제한다.
kubectl uncordon <cp-node-name> ex) kubectl uncordon k8s-master - master와 node에 kubelet 및 kubectl을 업그레이드한다.
(1.15.x-> 1.16.x) yum install -y kubelet-1.16.x-0 kubectl-1.16.x-0 --disableexcludes=kubernetes (1.16.x-> 1.17.x) yum install -y kubelet-1.17.x-0 kubectl-1.17.x-0 --disableexcludes=kubernetes - kubelet을 재시작 한다.
sudo systemctl daemon-reload sudo systemctl restart kubelet - 비고 :
-
master 다중화 구성 클러스터 업그레이드 시에는 다음과 같은 명령어를 실행한다.
-
첫번째 컨트롤 플레인 업그레이드 시에는 위에 step을 진행하고, 나머지 컨트롤 플레인 업그레이드 시에는 아래의 명령어를 실행한다.
-
추가된 master에서 kubeadm을 upgrade 한다.
yum install -y kubeadm-설치버전 --disableexcludes=kubernetes ex) yum install -y kubeadm-1.16.0-0 --disableexcludes=kubernetes ex) yum install -y kubeadm-1.17.6-0 --disableexcludes=kubernetes- 버전 확인
kubeadm version- node drain
- 추가 컨트롤 플레인에서도 첫번째 컨트롤 플레인 node drain 전 체크 사항을 참고하여 drain 가능한 상태인지 체크한다.
- node drain 실행
- node drain시 해당 node상의 pod가 evict되기 때문에, pod의 local-data의 경우 보존되지 않음
kubectl drain <node-to-drain> --ignore-daemonsets --delete-local-data ex) kubectl drain k8s-master2 --ignore-daemonsets --delete-local-data
- 추가 컨트롤 프레인에서는 해당 명령어를 실행하지 않는다. (sudo kubeadm upgrade plan)
- sudo kubeadm upgrade apply 명령어 대신에 sudo kubeadm upgrade node 명령어를 실행한다.
sudo kubeadm upgrade node- 적용된 cordon을 해제한다.
kubectl uncordon <cp-node-name> ex) kubectl uncordon k8s-master2- master와 node에 kubelet 및 kubectl을 업그레이드한다.
(1.15.x-> 1.16.x) yum install -y kubelet-1.16.x-0 kubectl-1.16.x-0 --disableexcludes=kubernetes (1.16.x-> 1.17.x) yum install -y kubelet-1.17.x-0 kubectl-1.17.x-0 --disableexcludes=kubernetes- kubelet을 재시작 한다.
sudo systemctl daemon-reload sudo systemctl restart kubelet- 업그레이드 후 노드가 ready -> not ready 상태로 바뀐 경우
- Failed to initialize CSINode: error updating CSINode annotation: timed out waiting for the condition; caused by: the server could not find the requested resource
sudo vi /var/lib/kubelet/config.yaml에 아래 옵션 추가 featureGates: CSIMigration: false sudo systemctl restart kubelet- 업그레이드시 runtime 변경을 하는 경우 (docker -> cri-o)
systemctl stop kubelet sudo vi /var/lib/kubelet/kubeadm-flags.env에 옵션 변경 기존 (docker) : KUBELET_KUBEADM_ARGS="--cgroup-driver=cgroupfs --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.1 변경 (cri-o) : KUBELET_KUBEADM_ARGS="--container-runtime=remote --cgroup-driver=systemd --container-runtime-endpoint=/var/run/crio/crio.sock" systemctl restart kubelet systemctl restart docker ( #docker image registry node는 systemctl restart docker 명령어를 실행한다. ) -
Step1. kubernetes node upgrade
- 워커 노드의 업그레이드 절차는 워크로드를 실행하는 데 필요한 최소 용량을 보장하면서, 한 번에 하나의 노드 또는 한 번에 몇 개의 노드로 실행해야 한다.
- 모든 worker node에서 kubeadm을 업그레이드한다.
yum install -y kubeadm-설치버전 --disableexcludes=kubernetes ex) (1.15.x-> 1.16.x) yum install -y kubeadm-1.16.x-0 --disableexcludes=kubernetes ex) (1.15.x-> 1.16.x) yum install -y kubeadm-1.17.x-0 --disableexcludes=kubernetes - node drain
- node drain 전 체크 사항
- PDB가 존재하는 Pod가 drain하려는 node에 생성되어있는 경우 evict가 제한 되기 때문에, 아래 명령어로 drain이 가능한 상태인지 확인한다.
kubectl get pdb -A or kubectl get pdb <pdb-name> -oyaml- ALLOWED DISRUPTIONS 및 drain 시키려는 node의 pod 상태를 확인한다.
- PDB의 ALLOWED DISRUPTIONS가 drain을 시도하는 node에 뜬 pod(pdb 설정 pod) 개수보다 적을 경우 아래와 같이 다른 노드로 재스케줄링이 필요하다.
- ex) virt-api pod가 drain하려는 node에 2개 떠있는데, ALLOWED DISRUPTIONS는 0 또는 1일 경우
- 해당 조건에 만족하지 않는 경우 'Cannot evict pod as it would violate the pod's disruption budget' 와 같은 에러가 발생할 수 있다.
- 해결 방법
-
- 해당 Pod를 다른 Node로 재스케줄링을 시도한다.
kubectl delete pod <pod-name>-
- 다른 Node의 리소스 부족, noScheduling 설정 등으로 인해 a번 재스케줄링이 불가할 경우엔 PDB 데이터를 삭제하고 drain한 후에 PDB 데이터를 복구한다.
kubectl get pdb <pdb-name> -o yaml > pdb-backup.yaml kubectl drain <node-to-drain> --ignore-daemonsets --delete-local-data kubectl apply -f pdb-backup.yaml -
- node drain 실행
- warning : node drain시 해당 node상의 pod가 evict되기 때문에, pod의 local-data의 경우 보존되지 않음
kubectl drain <node-to-drain> --ignore-daemonsets --delete-local-data ex) kubectl drain k8s-node --ignore-daemonsets --delete-local-data
- node drain 전 체크 사항
- kubelet 구성 업그레이드
sudo kubeadm upgrade node - kubelet과 kubectl 업그레이드
(1.15.x-> 1.16.x) yum install -y kubelet-1.16.x-0 kubectl-1.16.x-0 --disableexcludes=kubernetes (1.16.x-> 1.17.x) yum install -y kubelet-1.17.x-0 kubectl-1.17.x-0 --disableexcludes=kubernetes sudo systemctl daemon-reload sudo systemctl restart kubelet - 적용된 cordon을 해제한다.
kubectl uncordon <cp-node-name> ex) kubectl uncordon k8s-node - 비고 :
- 1.16.x -> 1.17.x로 업그레이드시 버전에 맞추어 위에 작업을 실행한다.
- 업그레이드 후 노드가 ready -> not ready 상태로 바뀐 경우
- Failed to initialize CSINode: error updating CSINode annotation: timed out waiting for the condition; caused by: the server could not find the requested resource
sudo vi /var/lib/kubelet/config.yaml에 아래 옵션 추가 featureGates: CSIMigration: false sudo systemctl restart kubelet- 업그레이드시 runtime 변경을 하는 경우 (docker -> cri-o)
systemctl stop kubelet sudo vi /var/lib/kubelet/kubeadm-flags.env에 옵션 변경 기존 (docker) : KUBELET_KUBEADM_ARGS="--cgroup-driver=cgroupfs --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.1 변경 (cri-o) : KUBELET_KUBEADM_ARGS="--container-runtime=remote --cgroup-driver=systemd --container-runtime-endpoint=/var/run/crio/crio.sock" systemctl restart kubelet systemctl stop docker ( #docker image registry node는 systemctl restart docker 명령어를 실행한다. )