はじめに
Kubesprayで構築したk8sクラスターのOSは、全て Ubuntu 20.04 です。
まだしばらくは20.04のサポートは続きますが、22.04へのアップグレードはどこかで検討しなければいけません。
幸いにも試すことができるクラスターがあったので、workerの1ノードをアップグレードしてみました。
Ubuntu 22.04.5から24.04.2へのアップグレードを試していますが、ここに記載しているような手順(cordon→drain→ansible-playbook→uncordo)といった流れでkubernetesのシステム自体は問題なくアップグレードできます。
しかしrook/cephについてはCSIドライバがrbd.ko.zst
を正しくロードできず正常に動作しないPodがありました。
この問題はRook/Cephを事前にv1.15の最新に更新することで回避できるはずです。
またOS再起動のタイミングでRX100 S7pが停止してしまったので現地で強制リセットの必要がありました。
これは特定ハードウェアの特性ではあると思いますが、KVMや富士通製であればiRMCなどで遠隔操作できないのであればモートだけで作業するのは避けた方が良いでしょう。
環境
Kubespray v2.20.0 (Kubernetes v1.24.6) 以降では、OSとしてUbuntu 22.04がサポートされています。
今回は以下の環境でアップグレードを行なっています。
- Kubespray: v2.21.0 (Kubernetes: v1.25.6)
- OS: Ubuntu 20.04.5 LTS (最新版)
- ノード数: 4
確認作業 (PoC)
このセクションの内容は必要な作業を洗い出すための準備作業です。
アップグレード手順としては利用せず、後述の#作業手順を参照してください。
とりあえずcordonして新規にPodが割り当てられないようにしておきます。
$ sudo kubectl cordon node4
node/node4 cordoned
状態を確認します。
$ sudo kubectl get node
NAME STATUS ROLES AGE VERSION
node1 Ready control-plane 555d v1.25.6
node2 Ready control-plane 555d v1.25.6
node3 Ready <none> 555d v1.25.6
node4 Ready,SchedulingDisabled <none> 555d v1.25.6
この状態で、node4をdo-release-upgradeしようとするとエラーになります。
$ sudo do-release-upgrade -d
Checking for a new Ubuntu release
Please install all available updates for your release before upgrading.
$ sudo apt dist-upgrade
...
The following packages have been kept back:
containerd.io docker-ce docker-ce-cli
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
Kubesprayはpackageを保留状態(hold)にしています。
$ dpkg -l |grep ^h
hi containerd.io 1.6.4-1 amd64 An open and reliable container runtime
hi docker-ce 5:20.10.20~3-0~ubuntu-focal amd64 Docker: the open-source application container engine
hi docker-ce-cli 5:20.10.20~3-0~ubuntu-focal amd64 Docker CLI: the open-source application container engine
これらをunholdすれば、作業自体は進めることが可能ですが、はたしてどうするべきなのか、検討してみます。
参考資料
- Kubernetes Part 18: How-To Upgrade Kubernetes Nodes from Ubuntu 20.04 to 22.04 LTS
- Kubesprayを利用してKubernetesをデプロイ・アップグレードした時のメモ - v2.15.1でcontainerd.ioパッケージが更新されてしまう問題について
とりあえず壊れても問題のないクラスターなので、単純にunholdしてdo-release-upgradeする方法で進めてみます。
作業手順
OSのアップグレードはworkerノードから実施しています。
あらかじめcordonしてからdrainまで実施しましょう。
$ sudo kubectl cordon node4
$ sudo kubectl drain node4 --force --ignore-daemonsets
## ↑で失敗した場合はメッセージを確認して"--delete-local-data"オプション付きで実行する
$ sudo kubectl drain node4 --force --ignore-daemonsets --delete-emptydir-data
grace-periodは指定しません。
まず3つのパッケージをunholdしておきます。
$ sudo apt-mark unhold containerd.io docker-ce docker-ce-cli
Canceled hold on containerd.io.
Canceled hold on docker-ce.
Canceled hold on docker-ce-cli.
パッケージ全体をアップグレードします。
$ sudo apt update
$ sudo apt dist-upgrade
パッケージを最新にした状態でノードを再起動し、最新のカーネルで起動している状態にします。
$ sudo shutdown -r now
Ubuntu 22.04にアップグレードします。
この中でGNU screenが起動するので、別のターミナルからsshでnode4にログインし、作業を進めます。
$ sudo do-release-upgrade -d
あとは、基本的に'y'キーなどで作業を進め、設定ファイルは現状のまま変更しない'N'を選択しながら見守ります。
そのまま再起動して様子を確認します。
再起動後の作業
起動後、数分してからcontrol-planeからノードの状況を確認して、Readyになるまで待機します。
$ kcg node
NAME STATUS ROLES AGE VERSION
node1 Ready control-plane 555d v1.25.6
node2 Ready control-plane 555d v1.25.6
node3 Ready <none> 555d v1.25.6
node4 Ready,SchedulingDisabled <none> 555d v1.25.6
表面上は問題なく動いている様子です。
続いて、kubesprayのupdate-cluster.ymlを--limitを利用してnode4だけに適用します。これはエラーになるので実行の際には、最後に"--skip-tags=multus"を加えて実行してください。
$ . venv/k8s/bin/activate
(k8s) $ grep kube_version inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
kube_version: v1.25.6
(k8s) $ ansible-playbook upgrade-cluster.yml -b -i inventory/mycluster/hosts.yaml -e kube_version=v1.25.6 --limit=node4
...
もしこれを実行してしまうと、エラーで停止します。
...
TASK [kubernetes-apps/network_plugin/multus : Multus | Start resources] ***************************************************
failed: [node4 -> {{ groups['kube_control_plane'][0] }}] (item=None) => {"ansible_loop_var": "item", "changed": false, "item": null, "msg": "Failed to template loop_control.label: 'None' has no attribute 'item'", "skip_reason": "Conditional result was False"}
NO MORE HOSTS LEFT ********************************************************************************************************
PLAY RECAP ****************************************************************************************************************
node4 : ok=312 changed=23 unreachable=0 failed=1 skipped=451 rescued=0 ignored=0
GitHubのIssuesには同様の事例が登録されていて、Node-based upgrade fails with: "Failed to template loop_control.label: 'None' has no attribute 'item'" #9703 に従って --skip-tags=multus を追加して再度実行します。
(k8s) $ ansible-playbook upgrade-cluster.yml -b -i inventory/mycluster/hosts.yaml -e kube_version=v1.25.6 --limit=node4 --skip-tags=multus
...
続いて別のエラーが発生します。
...
TASK [container-engine/docker : ensure docker packages are installed] *****************************************************
fatal: [node4]: FAILED! => {"attempts": 4, "cache_update_time": 1678337172, "cache_updated": true, "changed": false, "msg": "'/usr/bin/apt-get -y -o \"Dpkg::Options::=--force-confdef\" -o \"Dpkg::Options::=--force-confold\" install 'containerd.io=1.6.4-1' 'docker-ce-cli=5:20.10.20~3-0~ubuntu-jammy' 'docker-ce=5:20.10.20~3-0~ubuntu-jammy'' failed: E: Packages were downgraded and -y was used without --allow-downgrades.\n", "rc": 100, "stderr": "E: Packages were downgraded and -y was used without --allow-downgrades.\n", "stderr_lines": ["E: Packages were downgraded and -y was used without --allow-downgrades."], "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nThe following packages were automatically installed and are no longer required:\n docker-buildx-plugin docker-compose-plugin libpython2-stdlib\n libpython2.7-minimal libpython2.7-stdlib python2 python2-minimal python2.7\n python2.7-minimal\nUse 'sudo apt autoremove' to remove them.\nSuggested packages:\n aufs-tools cgroupfs-mount | cgroup-lite\nThe following packages will be DOWNGRADED:\n containerd.io docker-ce docker-ce-cli\n0 upgraded, 0 newly installed, 3 downgraded, 0 to remove and 4 not upgraded.\n", "stdout_lines": ["Reading package lists...", "Building dependency tree...", "Reading state information...", "The following packages were automatically installed and are no longer required:", " docker-buildx-plugin docker-compose-plugin libpython2-stdlib", " libpython2.7-minimal libpython2.7-stdlib python2 python2-minimal python2.7", " python2.7-minimal", "Use 'sudo apt autoremove' to remove them.", "Suggested packages:", " aufs-tools cgroupfs-mount | cgroup-lite", "The following packages will be DOWNGRADED:", " containerd.io docker-ce docker-ce-cli", "0 upgraded, 0 newly installed, 3 downgraded, 0 to remove and 4 not upgraded."]}
これは参考資料に上げたv2.15.1で遭遇した問題と同じなので、force: true を roles/container-engine/docker/tasks/main.yml に追加して、再度実行します。
## venv環境の導入
$ . venv/k8s/bin/activate
## kube_versionの確認
(k8s) $ grep kube_version inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
kube_version: v1.25.6
## dockerインストール時にforce: trueを設定
(k8s) $ vi roles/container-engine/docker/tasks/main.yml
## kube_versionを指定して、--skip-tags=multusオプションも指定して実行
(k8s) $ ansible-playbook upgrade-cluster.yml -b -i inventory/mycluster/hosts.yaml -e kube_version=v1.25.6 --limit=node4 --skip-tags=multus
最終的には無事に完了しました。
PLAY RECAP ****************************************************************************************************************
node4 : ok=451 changed=19 unreachable=0 failed=0 skipped=855 rescued=0 ignored=1
最後には忘れずに uncordon します。
$ sudo kubectl uncordon node4
これで問題なく動作するようになりました。
node4のcontainerd.io docker-ce docker-ce-cliの状態は次のようになっています。
$ dpkg -l containerd.io docker-ce docker-ce-cli
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==============-===========================-============-========================================================
hi containerd.io 1.6.4-1 amd64 An open and reliable container runtime
hi docker-ce 5:20.10.20~3-0~ubuntu-jammy amd64 Docker: the open-source application container engine
hi docker-ce-cli 5:20.10.20~3-0~ubuntu-jammy amd64 Docker CLI: the open-source application container engine
バージョンはアップグレード前と同じになっています。
/etc/apt/sources.list.d/ の中は次のようになっています。
$ $ ls /etc/apt/sources.list.d
download_docker_com_linux_ubuntu.list download_docker_com_linux_ubuntu.list.distUpgrade
$ cat /etc/apt/sources.list.d/download_docker_com_linux_ubuntu.list
deb [arch=amd64] https://download.docker.com/linux/ubuntu jammy stable # disabled on upgrade to jammy
$ cat /etc/apt/sources.list.d/download_docker_com_linux_ubuntu.list.distUpgrade
deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable
この状態で upgrade を実行すると次のようになって、docker関連のパッケージが少し導入されますが、このままインストールしています。
$ sudo apt dist-upgrade
...
The following packages have been kept back:
containerd.io docker-ce docker-ce-cli
The following packages will be upgraded:
docker-buildx-plugin docker-ce-rootless-extras docker-compose-plugin docker-scan-plugin
4 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
このまま全ノードをUbuntu 22.04にアップグレードしたら、dockerからcontainerdに乗り換える方法を検討しようと思います。
legacy trusted.gpg keyring への対応
しばらくして次のようなワーニングに気がつきました。
$ sudo apt update
Hit:1 https://download.docker.com/linux/ubuntu jammy InRelease
...
W: https://download.docker.com/linux/ubuntu/dists/jammy/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
docker.comの手順に従えば、再度gpg鍵を設定することはできます。
これだけでは不十分で、加えてtrusted.gpgから削除する必要があります。
docker自体はアップグレードする必要はないのでしばらく放っておくことにしました。
複数台を更新していく作業のテンポについて
複数のノードを順番にアップグレードしていく場合には、分散DBのように複数ノードに渡るクラスターを運用している場合にはその健全性に注意しましょう。
基本的にはn-1台でサービスが継続できるように構成されていると思われるため、1ノードずつ停止している分には問題は発生しないはずです。
しかし短期間に繰り返し作業をしてしまうと問題が発生するかもしれません。
1台の作業が終る度にRook/Cephであればceph status
などで健全性を確認するようにしてください。
control-planeノードのアップグレード
この記事を投稿してから、control-planeのノードもUbuntu 20.04から、22.04にアップグレードしました。
特にworkerノードと違う点はありませんでしたが、再起動に非常に長い時間がかかりました。
原因は不明ですが作業時間は想定よりも2倍程度かかった点が印象的です。
まとめ
作業自体はそれほど危険な感じはしませんが、再起動などをしてからクラスター全体が安定するまでにはしばらく時間がかかります。
またcordonしている間にkubesprayを実行し、ノードを再び再起動するなど確認の手間はおしまない方が良さそうです。
結果としては Rook/Ceph の動作にも影響はないですし、以前 docker や containerd.io がアップグレードされてしまった状態から戻したこともあったので、それほど混乱なく作業を進めることができました。
K8sクラスターは安定していると、特に日本の風土では、アップグレードなどをしないまま放置してしまうことがありそうだなと感じています。
しかしk8sの各バージョンのサポート期間はとても短いので、End-of-Life(EOL)情報は定期的に確認し、メンテナンスウィンドウを設けてk8sクラスターをアップグレードし続けるようにしましょう。
後日談: 24.04へのアップグレード時に遭遇した問題点
Rook/Cephで"Still connection to unix:///csi/csi.sock"メッセージが出る
OSアップグレード後のノードでcsi-rbdpluginが上記のメッセージを出力して正常に稼動しない問題が発生しました。
状況は違いますが、同様のメッセージは下記のissuesでも報告されています。
結果的にRook/Cephのバージョンが古いことでこの問題に遭遇してしまったので、OSを更新したノードでmodprobe rbd
を実行して全体を正常にしてからRookのバージョンをv1.15.9に、Cephをv18.2.4に更新しました。
v1.14.12ではCSIのバージョンがv3.10.1と古いままで問題は解決しませんでした。
以上