며칠 전 Kubernetes Cluster 를 v1.16.3 에서 v1.18.5 로 업그레이드 하다가 발견된 이슈를 해결한 내용을 공유합니다.
제가 관리하고 있는 Kubernetes 는 Kubespray 로 설치했었고 업그레이드 역시 Kubespray 를 활용했습니다.
Kubespray 는 Kubernetes 설치에 kubeadm 을 사용하는데 kubeadm 은 마이너 버전 차이가 1 을 초과하면 업그레이드를 지원하지 않습니다.
그렇기 때문에 v1.16.x 에서 v1.18.x 로 업그레이드를 하려며 v1.16.x -> v1.17.x -> v1.18.x 로 단계적으로 업그레이드를 해야 합니다.
기존 설치된 버전은 kubespray 의 release-2.12 브랜치로 v1.16.3 이었고, kubespray tags/v2.13.2 을 활용하면 v1.17.7 로 업그레이들 할 수 있습니다.
## deploy 디렉토리로 변경
$ cd ~/deploy/kubespray
## kubespray 다운로드 (tag 로 할 때)
$ git checkout master
$ git pull
$ git checkout -b tag_v2.13.2 tags/v2.13.2
$ sudo pip install -r requirements.txt
## inventory 복사 (업그레이드 할 때)
$ rm -rf inventory/k1-seungkyua/group_vars/*
$ cp -r inventory/sample/group_vars inventory/k1-seungkyua
## hosts.ini 수정
$ vi inventory/k1-seungkyua/inventory.ini
[all]
k1-master01 ansible_host=k1-master01 ip=192.168.30.13 iface=eno49
k1-master02 ansible_host=k1-master02 ip=192.168.30.14 iface=ens2f0
k1-master03 ansible_host=k1-master03 ip=192.168.30.15 iface=eno49
k1-node01 ansible_host=k1-node01 ip=192.168.30.12 iface=ens2f0
k1-node02 ansible_host=k1-node02 ip=192.168.30.17 iface=ens2f0
k1-node03 ansible_host=k1-node03 ip=192.168.30.18 iface=ens2f0
k1-node04 ansible_host=k1-node04 ip=192.168.30.21 iface=ens2f0
k1-node05 ansible_host=k1-node05 ip=192.168.30.20 iface=ens2f0
[etcd]
k1-master01
k1-master02
k1-master03
[kube-master]
k1-master01
k1-master02
k1-master03
[kube-node]
k1-node01
k1-node02
k1-node03
k1-node04
k1-node05
[calico-rr]
[k8s-cluster:children]
kube-master
kube-node
calico-rr
## k8s-cluster.yml 수정
$ vi inventory/k1-seungkyua/extra-vars.yml
enable_nodelocaldns: false
# 신규 설치시에만 세팅
# skydns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(10)|ipaddr('address') }}"
kube_proxy_mode: ipvs
# hostname and hosts file
populate_inventory_to_hosts_file: false
override_system_hostname: false
# Helm deployment
helm_enabled: true
## copy admin.conf
kubeconfig_localhost: true
kubectl_localhost: true
## calico setting
ipip_mode: Never
peer_with_router: true
nat_outgoing: true
global_as_num: "65000"
peers:
- router_id: "192.168.30.1"
as: "65000"
# calico_ip_auto_method: "interface=eth.*"
# calico_ip_auto_method: "interface=ens6"
calico_ip_auto_method: "can-reach=8.8.8.8"
kubeadm_enabled: true
docker_insecure_registries:
- tacorepo:5000
dashboard_enabled: true
# Local volume provisioner deployment
local_volume_provisioner_enabled: true
metrics_server_enabled: true
## rbd provisioner deployment
rbd_provisioner_enabled: true
rbd_provisioner_monitors: 192.168.30.23:6789,192.168.30.24:6789,192.168.30.25:6789
rbd_provisioner_pool: kubes
rbd_provisioner_secret: QVFBTmRVVlh5UmZoTlJBQTMyZTh6Qk5uajV1VElrMDJEbWFwWmc9PQ==
rbd_provisioner_user_secret: QVFDdC9CcFlpZ0o3TVJBQTV2eStjbDM5RXNLcFkzQyt0WEVHckE9PQ==
저의 경우에는 calico 를 활용하여 switch 와 bgp 로 통신하므로 bgp 설정을 넣었습니다.
## k8s 업그레이드 수행
$ ansible-playbook -e @inventory/k1-seungkyua/extra-vars.yml -b -f 30 -i inventory/k1-seungkyua/inventory.ini upgrade-cluster.yml
업그레이드를 돌리면 순차적으로 drain 과 uncordon 을 수행하는데 중간에 에러가 날 경우에는 kubelet 을 업그레이드 이전 버전으로 돌려놓아야 합니다.
예를 들어, master02 를 업그레이드 하다가 에러가 나면 아래의 작업을 수행해 줘야 합니다.
1. 에러가 나도 kubelet 의 버전은 올라가므로 kubelet 버전을 업그레이드 이전으로 다운그레이드 해야 합니다. 쉬운 방법은 다른 노드에 있는 kubelet 을 복사해서 kubelet 을 restart 해야 합니다.
systemctl restart kubelet
2. schedule 이 disabled 되어 있을 수 있으니 uncordon 해줘야 합니다.
kubectl uncordon k1-master02
## 업그레이드 시 에러 날 경우
PodDisruptionBudget 을 확인해야 함
istio 의 MIN AVAILABLE 은 전부 0 으로 세팅
elasticsearch 는 삭제
# kubectl get PodDisruptionBudget -A
NAMESPACE NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
istio-system istio-egressgateway 1 N/A 0 76d
istio-system istio-galley 1 N/A 0 76d
istio-system istio-ingressgateway 1 N/A 0 76d
istio-system istio-pilot 1 N/A 0 76d
istio-system istio-policy 1 N/A 0 76d
istio-system istio-telemetry 1 N/A 0 76d
logging elasticsearch-k1-master-pdb N/A 1 0 71d
Master의 root 디렉토리 확인
/root/.kube/http-cache 디렉토리 삭제
/root/.docker/config 파일 삭제 (도커 로그인정보를 가지고 있어서 docker pull 이 안될 수 있음)
coreDNS 가 10.233.0.3 이면 kubeadm 에서 coreDNS 는 10.233.0.10 이어야 한다는 업그레이드 에러 발생
kubeadm 명령어에 --print-config 옵션을 붙혀서 미리 한 번 실행하여 이상이 없는지 확인
# kubeadm upgrade apply -y v1.17.7 --config=/etc/kubernetes/kubeadm-config.yaml --ignore-preflight-errors=all --allow-experimental-upgrades --allow-release-candidate-upgrades --etcd-upgrade=false --certificate-renewal=true --force --v=9 --print-config
실행에 이상이 없으면 kubespray 의 roles/kubernetes/master/tasks/kubeadm-upgrade.yml 에 해당 옵션을 추가
kubelet upgrade 시에 에러가 발생하였음.
kubelet 버전은 v1.16.3 에서 v1.17.7 로 업그레이드가 되었으나 기존 옵션으로 kubelet 이 start 시에 에러가 남
kubelet --version 으로 v1.17.7 이면 v1.16.3 으로 kubelet 을 다시 복사하고 Kubelet restart