반응형

며칠 전 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

 

 

 

 

 

 

반응형
Posted by seungkyua@gmail.com
,
반응형

Kubernetes Upgrade 는 고려해야 할 사항이 많지만 Kubespray 를 활용하면 의외로 간단할 수 도 있다.

Kubespray 는 Kubernetes 설치에 kubeadm 을 활용하기 때문에 업그레이드는 Kubernetes 의 바로 윗단계 마이너버전까지만 가능하다. 예를 들어 지금 Kubernetes 버전이 v1.14.x 이면 v1.16.x 로는 업그레이드를 못한다. v1.16.x 로 업그레이드를 하기 위해서는 v1.15.x 로 업그레이드를 하고, v1.16.x 로 다시 업그레이드를 해야 한다.

 

마침 업그레이드가 필요했고 현재 설치된 Kubernetes 버전이 v1.14.3 이므로 v1.15.6 으로 업그레이드를 먼저 진행하였다.

$ cd kubespray

$ git branch
  master
* release-2.11
  release-2.12
  tag_v2.10.4
  tag_v2.9.0

Kubespray 의 release-2.11 branch 는 Kubernetes Kubernetes v1.15.6 이다. 아래 명령어로 확인할 수 버전을 확인할 수 있다.

kube_version: v1.15.6

$ grep -nr kube_version: .
./docs/upgrades.md:30:And then repeat with v1.4.6 as kube_version:
./inventory/sample/group_vars/k8s-cluster/k8s-cluster.yml:23:kube_version: v1.15.6
./inventory/k1-seungkyua/group_vars/k8s-cluster/k8s-cluster.yml:23:kube_version: v1.15.6
./roles/download/defaults/main.yml:52:kube_version: v1.15.6
./roles/kubespray-defaults/defaults/main.yaml:15:kube_version: v1.15.6
./RELEASE.md:37:  is bound to ``kube_version: 1.4.x``, ``calico_version: 0.22.0``, ``etcd_version: v3.0.6``,
./RELEASE.md:40:  And Kubespray v3.x.x shall be bound to ``kube_version: 2.x.x`` respectively.

먼저 Master 3대를 업그레이드 하여 업그레이드를 순차적으로 하는 것이 좋다. Kubernetes Master 와 Work Node 는 minor 차이가 나더

라도 큰 문제가 생기지 않기 때문에 순차적 검증을 할 수 있다. 물론 kube-apiserver 에서 활성화한 특정 feature 와 resource version 은 사전에 반드시 테스트하여 안전성을 확보한 후 진행해야 한다. 

$ ansible-playbook -e @inventory/k1-seungkyua/extra-vars.yml -b -f 30 -i inventory/k1-seungkyua/inventory.ini upgrade-cluster.yml --limit k1-master01,k1-master02,k1-master03

중요한 것은 --limit 옵션으로 Master 만 업그레이드를 진행한다는 것이다.

Every 2.0s: kubectl get nodes                                                                                                                                           Thu Jan  9 16:15:35 2020

NAME          STATUS   ROLES          AGE    VERSION
k1-master01   Ready    master         323d   v1.15.6
k1-master02   Ready    master         323d   v1.15.6
k1-master03   Ready    master         323d   v1.15.6
k1-node01     Ready    ingress,node   323d   v1.14.3
k1-node02     Ready    node           323d   v1.14.3
k1-node03     Ready    node           322d   v1.14.3
k1-node04     Ready    node           323d   v1.14.3
k1-node05     Ready    node           323d   v1.14.3

 

이제 Worker 를 업그레이드 할 차례인데, Worker 를 업그레이드는 고려해야 할 사항이 있다. 노드를 업그레이드 하기 위해서는 drain 을 하여 Pod 를 eviction 하는데 Kubespray 는 evction 이 완료될 때 까지 기다린다. DaemonSet 은 무시하는 옵션이 있지만 PodDisruptionBudget 은 policy 에 걸리면 pod 가 terminating 상태에서 완료되지 않기 때문에 timeout 으로 업그레이드에 실패하게 된다. 여기서는 elasticsearch 가 문제가 있어 timeout 나서 실패하였다.

# 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

elasticsearch 문제를 해결하고 다시 k1-node01 이라는 Worker 노드  1대만 업그레이드를 진행한다.

$ ansible-playbook -e @inventory/k1-seungkyua/extra-vars.yml -b -f 30 -i inventory/k1-seungkyua/inventory.ini upgrade-cluster.yml --limit k1-node01

문제없이 업그레이드가 완료되었다.

Every 2.0s: kubectl get nodes                                                                                                                                           Thu Jan  9 16:27:17 2020

NAME          STATUS   ROLES          AGE    VERSION
k1-master01   Ready    master         323d   v1.15.6
k1-master02   Ready    master         323d   v1.15.6
k1-master03   Ready    master         323d   v1.15.6
k1-node01     Ready    ingress,node   323d   v1.15.6
k1-node02     Ready    node           323d   v1.14.3
k1-node03     Ready    node           322d   v1.14.3
k1-node04     Ready    node           323d   v1.14.3
k1-node05     Ready    node           323d   v1.14.3

이제 나머지 노드를 모드 업그레이드를 하면 된다. Kubespray 는 한대씩 순차적으로 업그레이드를 하기 때문에 전체 서비스에는 영향이 없다. (서비스를 여러 pod 로 load balancing 했을 경우에)

 

반응형
Posted by seungkyua@gmail.com
,
반응형


https://github.com/seungkyua/my-kubespray

my-kubespray

You can easily add your custom logic without modifying kubespray.

The my-kubespray has serveral parameters to override and can deploy ceph rbd provisioner into namespace.

Prerequisites

  • All servers must have the same user, and the user must set root permissions to NOPASSWD in sudo.

  • In the deployment node (or master 1 node), you need to enable ssh access to all other servers (including localhost) without a password to the corresponding account.

  • Register all cluster servers in the /etc/hosts file.

  • Time synchronization between servers with ntp.

  • Enable network restart with systemctl restart network.service .

  • Disable firewall such as selinux or ufw.

  • swapoff.

  • Install python 2.7.x in ansible runner node.

Quick Start

To deploy the cluster you can use :

# Download kubespray and my-kubespray
$ git clone https://github.com/kubernetes-sigs/kubespray.git
$ git clone https://github.com/seungkyua/my-kubespray.git

# Change directory into my-kubespray
$ cd my-kubespray

# Install dependencies from ``requirements.txt``
$ sudo pip install -r ../kubespray/requirements.txt

# Copy ``inventory/k2-seungkyua`` as ``inventory/mycluster``
$ cp -rfp inventory/k2-seungkyua inventory/mycluster

# Update Ansible inventory file
$ vi inventory/mycluster/hosts.ini
[all]
k2-master01 ip=192.168.30.151
k2-master02 ip=192.168.30.152
k2-master03 ip=192.168.30.153
k2-ctrl01 ip=192.168.30.154
k2-ctrl02 ip=192.168.30.155
k2-ctrl03 ip=192.168.30.156
k2-cn01 ip=192.168.30.157

[etcd]
k2-master01
k2-master02
k2-master03

[kube-master]
k2-master01
k2-master02
k2-master03

[kube-node]
k2-ctrl01
k2-ctrl02
k2-ctrl03
k2-cn01

[k8s-cluster:children]
kube-node
kube-master

# Review and change parameters under ``inventory/mycluster/group_vars/k8s-cluster.yml``
$ cat inventory/mycluster/group_vars/k8s-cluster.yml
populate_inventory_to_hosts_file: false
override_system_hostname: false
helm_enabled: true
etcd_memory_limit: 8192M
kubeconfig_localhost: true
kubectl_localhost: true
ipip_mode: Never
calico_ip_auto_method: "can-reach=8.8.8.8"
kubeadm_enabled: true
docker_insecure_registries:
- seungkyua:5000
dashboard_enabled: true
local_volume_provisioner_enabled: true
ingress_nginx_enabled: true
ingress_nginx_host_network: true
ingress_nginx_nodeselector:
node-role.kubernetes.io/ingress: true
ceph_version: mimic
storageclass_name: rbd
monitors: 192.168.30.23:6789,192.168.30.24:6789,192.168.30.25:6789
admin_token: QBTEBmRVVlh5UmZoTlJBQTMyZTh6Qk5uajV1VElrMDJEbWFwWmc9WA==
user_secret_namespace: default
pool_name: kubes
user_id: kube
user_token: QEFESG9CcFlpZ0o3TVJBQTV2eStjbDM5RXNLcFkzQyt0WEVHckE9WA==

# Run Ansible Playbook to deploy kubernetes cluster
$ ansible-playbook -b -f 30 -i inventory/mycluster/hosts.ini ../kubespray/cluster.yml

# Run Ansible Playbook to deploy ceph rbd provisioner
$ ansible-playbook -b -f 30 -i inventory/mycluster/hosts.ini storage.yml

Miscellaneous

After installation, you can find the artifacts which are kubectl and admin.conf in inventory/mycluster/artifacts directorin on deploy node(ansible runner).

$ ls -al inventory/mycluster/artifacts
total 173620
drwxr-x--- 2 seungkyua seungkyua     4096 Feb 22 05:25 .
drwxrwxr-x 4 seungkyua seungkyua     4096 Feb 22 02:38 ..
-rw-r----- 1 seungkyua seungkyua     5449 Feb 22 05:25 admin.conf
-rwxr-xr-x 1 seungkyua seungkyua 177766296 Feb 22 05:25 kubectl
-rwxr-xr-x 1 seungkyua seungkyua       65 Feb 22 05:25 kubectl.sh

If desired, copy admin.conf to ~/.kube/config and kubectl to /usr/local/bin/kubectl

$ mkdir -p ~/.kube
$ cp inventory/mycluster/artifacts/admin.conf ~/.kube/config
$ sudo cp inventory/mycluster/artifacts/kubectl /usr/local/bin/kubectl



반응형
Posted by seungkyua@gmail.com
,