Kubernetes Upgrade auf ARM mit CRI-O und Arch Linux
In diesem Beitrag wurde die Installation von Kubernetes auf ODROID unter Arch Linux ARM beschrieben. Nachdem Kubernetes 1.12 veröffentlich wurde, ist es an der Zeit, sich auch mit dem Thema Kubernetes Update zu beschäftigen.
Das grundsätzliche Vorgehen bei einem Upgrade von Kubernetes erfolgt in mehreren Schritten:
-
Update der Kubernetes Binaries auf den Master Nodes (Control Plane)
-
Update der Kubernetes Pods auf den Master Nodes
-
Aktualisierung der Worker Nodes auf die neuesten Kubernetes Binaries
Kubernetes Upgrades werden jeweils zwischen Minor Versionen supported, d.h. ein Update von 1.10 zu 1.12 muss über den Zwischenschritt eines Updates auf Kubernetes 1.11 erfolgen.
Das konkrete Vorgehen hängt von dem gewählten Verfahren zur Kubernetes Einrichtung ab.
Da der Beispiel-Cluster mit kubeadm
eingerichtet wurde, wird auch das Update von Kubernetes mit kubeadm upgrade
durchgeführt.
Vorbereitungen - Kubernetes Build auf ODROID
Um Kubernetes aus dem Quellcode zu übersetzen, werden erhebliche Mengen an Hauptspeicher benötigt, um einen erfolgreichen Build zu erzeugen. Auf einem RaspberryPI und selbst auf einem ODROID ist zu wenig Speicher verbaut. Abhilfe schafft hier nur swap-Speicher als virtuelle Erweiterung des Hauptspeichers. Da Swap sehr langsam ist, bietet sich als Kompromiss an, zumindest teilweise auf zRAM zu setzen, um so mittels Kompression die Speicherausnutzung zu Lasten von höherer CPU-Last zu verbessern.
# swapoff -a
# zramctl --reset /dev/zram0
# zramctl --find --size 2000M
/dev/zram0
# mkswap /dev/zram0
# swapon /dev/zram0
Setting up swapspace version 1, size = 2 GiB (2097147904 bytes)
no label, UUID=29030557-c5d8-46d0-a2d4-92d0f0ce1e06
# fallocate -l 2500M /swapfile
# mkswap /swapfile
# swapon /swapfile
Setting up swapspace version 1, size = 2.5 GiB (2621435904 bytes)
no label, UUID=2c77581b-3938-4873-8150-4e47cd7f0685
Zusätzlich sollte das /tmp/
Verzeichnis, dass in der Regel mit tmpfs
betrieben wird, ausgehängt werden:
Die tmpfs
Implementierung nutzt RAM bzw. Swap-Speicher als temporären Speicher für das Verzeichnis und geht somit auch zu Lasten des verfügbaren Speichers.
Update der Go Version
Nach dem Update der Go Version werden Flags nicht mehr in dem alten Format export GOFLAGS="-p 1"
akzeptiert.
Mit diesem Flag wird Go angewiesen, den Build nicht auf die Anzahl der vorhandenen CPU Kerne zu parallelisieren.
Auch das ist ein Mittel, um den Hauptspeicherbedarf zu reduzieren.
Das neue Format wäre export GOFLAGS="-p=1"
, jedoch gibt es dann einen Fehler bei der Ausführung der Kubernetes Tests:
GOFLAGS="-p=1"
go test: p flag may be set only once
==> ERROR: A failure occurred in build().
Aborting...
Als einziger Weg, die Parallelisierung zu verhindern, bleibt daher aktuell der Hack, die CPU Kerne offline zu nehmen. Dank CPU Hotplug Support im Linux kernel, ist das auch relativ einfach zu machen.
echo 0 > /sys/devices/system/cpu/cpu1/online
echo 0 > /sys/devices/system/cpu/cpu2/online
echo 0 > /sys/devices/system/cpu/cpu3/online
Nun kann ein Build aller Komponenten durchgeführt werden.
Build CRI-O und crictl
Zunächst werden aktuelle Versionen von CRI-O und der CRI-Tools gebaut.
Als PKGBUILD
für ARM können die folgenden Vorlagen dienen:
# Maintainer: Thomas Kruse <[email protected]>
# Contributor: Tony Lambiris <[email protected]>
pkgname=cri-o
pkgver=1.11.7
pkgrel=1
pkgdesc='Open Container Initiative-based implementation of Kubernetes Container Runtime Interface'
arch=(x86_64 aarch64)
url='https://github.com/kubernetes-incubator/cri-o'
license=(Apache)
makedepends=(go go-md2man ostree)
backup=('etc/crio/crio.conf')
source=("git+https://github.com/kubernetes-incubator/cri-o")
sha256sums=('SKIP')
prepare() {
cd "$srcdir/$pkgname"
git checkout "v$pkgver"
install -m755 -d "$srcdir/go/src/github.com/kubernetes-incubator"
cp -a "$srcdir/$pkgname" "$srcdir/go/src/github.com/kubernetes-incubator/cri-o"
}
build() {
cd "$srcdir/go/src/github.com/kubernetes-incubator/cri-o"
export GOPATH="$srcdir/go"
make -j1 binaries docs
./bin/crio --selinux=true \
--storage-driver=overlay \
--conmon /usr/libexec/crio/conmon \
--cni-plugin-dir /usr/libexec/cni \
--default-mounts /run/secrets \
--cgroup-manager=systemd config > crio.conf
}
package() {
cd "$srcdir/go/src/github.com/kubernetes-incubator/cri-o"
make install install.systemd PREFIX="$pkgdir/usr"
# fix-up paths pointing to /usr/local to /usr
sed -i --follow-symlinks -re 's|/usr/local|/usr|g' $pkgdir/usr/lib/systemd/system/*.service
# install configs
install -dm755 $pkgdir/etc/crio/
install -Dm644 crio.conf $pkgdir/etc/crio/crio.conf
install -Dm644 seccomp.json $pkgdir/etc/crio/seccomp.json
}
# Maintainer: Thomas Kruse <[email protected]>
# Maintainer: ProFfeSsoRr <evvsoft at gmail dot com>
pkgname=crictl-bin
pkgver=1.12.0
pkgrel=1
pkgdesc="CLI tool for Kubelet Container Runtime Interface (CRI)"
arch=(x86_64 aarch64)
url="https://github.com/kubernetes-incubator/cri-tools/blob/master/docs/crictl.md"
license=('Apache')
source=("https://github.com/kubernetes-incubator/cri-tools/releases/download/v${pkgver}/crictl-v${pkgver}-linux-arm64.tar.gz"
"crictl.yaml")
sha256sums=('SKIP' 'SKIP')
package() {
cd "$srcdir"
install -Dm755 crictl "$pkgdir"/usr/bin/crictl
install -Dm644 crictl.yaml "$pkgdir"/etc/crictl.yaml
}
Wie immer werden die Pakete am besten mit makepkg --clean --syncdeps
gebaut.
Nachdem die neuesten Versionen der Container Runtime CRI-O und zugehöriger Tools gebaut sind, können die Kubernetes Binaries gebaut werden.
Build von Kubernetes und kubeadm
Für kubelet
und kubeadm
wird das Paket kubernetes
gebaut.
Das benötigte PKGBUILD kann z.B. wie folgt aussehen:
#Maintainer: Thomas Kruse <[email protected]>
#Contributor: Iwan Timmer <[email protected]>
pkgname=kubernetes
pkgver=1.12.1
_contribver=f4ce29dd35b68f538a5845d7e294bbf056d5d215
pkgrel=1
pkgdesc="Production-Grade Container Scheduling and Management"
depends=('glibc' 'bash')
makedepends=('go' 'rsync' 'go-bindata')
optdepends=('etcd: etcd cluster required to run Kubernetes')
arch=('x86_64' 'i686' 'armv7h' 'aarch64')
source=("$pkgname-$pkgver.tar.gz::https://dl.k8s.io/v$pkgver/kubernetes-src.tar.gz"
"https://github.com/kubernetes/contrib/archive/$_contribver.tar.gz"
"kubernetes.install")
noextract=("$pkgname-$pkgver.tar.gz")
url="http://kubernetes.io/"
license=("APACHE")
backup=('etc/kubernetes/apiserver'
'etc/kubernetes/config'
'etc/kubernetes/controller-manager'
'etc/kubernetes/kubelet'
'etc/kubernetes/proxy'
'etc/kubernetes/scheduler')
install=kubernetes.install
sha256sums=('35fc8ba46c75f7f41560bb4b9f969ceecadfaa34924e2ff5808bee3bc497546b'
'4bd2a2f4fc2a17b78dd53a8f7312760b4028d600d14006a3cdf5768b28b44b27'
'fb6fce3ef4b793863286dafb5856ce28027427005d6c6fd44162844921ab714b')
prepare() {
mkdir -p $srcdir/$pkgname-$pkgver
tar -xf $srcdir/$pkgname-$pkgver.tar.gz -C $srcdir/$pkgname-$pkgver
}
build() {
cd $srcdir/$pkgname-$pkgver
make -j1
hack/generate-docs.sh
}
package() {
cd $srcdir/$pkgname-$pkgver
[ "$CARCH" = 'i686' ] && _kubearch=386
[ "$CARCH" = 'x86_64' ] && _kubearch=amd64
[ "$CARCH" = 'aarch64' ] && _kubearch=arm64
[ "$CARCH" = 'armv7h' ] && _kubearch=arm
binaries=(apiextensions-apiserver cloud-controller-manager kube-proxy kube-apiserver kube-controller-manager kubelet kubeadm kubemark hyperkube kube-scheduler kubectl kubemark)
for bin in "${binaries[@]}"; do
install -Dm755 _output/local/bin/linux/$_kubearch/$bin $pkgdir/usr/bin/$bin
done
# install manpages
install -d $pkgdir/usr/share/man/man1/
install -pm 644 docs/man/man1/* $pkgdir/usr/share/man/man1
# install the place the kubelet defaults to put volumes
install -d $pkgdir/var/lib/kubelet
cd $srcdir/contrib-$_contribver
# install config files
install -dm 755 $pkgdir/etc/kubernetes/
install -m 644 -t $pkgdir/etc/kubernetes/ init/systemd/environ/*
# install service files
install -dm 755 $pkgdir/usr/lib/systemd/system
install -m 644 -t $pkgdir/usr/lib/systemd/system init/systemd/*.service
install -dm 755 $pkgdir/usr/lib/tmpfiles.d
install -m 644 -t $pkgdir/usr/lib/tmpfiles.d init/systemd/tmpfiles.d/*.conf
}
Auch hier erfolgt der Build am einfachsten mit makepkg
.
$ makepkg -sc
==> Making package: kubernetes 1.12.0-1 (Sat Oct 20 13:26:27 2018)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
-> Found kubernetes-1.12.0.tar.gz
-> Found f4ce29dd35b68f538a5845d7e294bbf056d5d215.tar.gz
-> Found kubernetes.install
==> Validating source files with sha256sums...
kubernetes-1.12.0.tar.gz ... Passed
f4ce29dd35b68f538a5845d7e294bbf056d5d215.tar.gz ... Passed
kubernetes.install ... Passed
==> Extracting sources...
-> Extracting f4ce29dd35b68f538a5845d7e294bbf056d5d215.tar.gz with bsdtar
==> Starting prepare()...
==> Removing existing $pkgdir/ directory...
==> Starting build()...
+++ [1020 13:27:03] Building go targets for linux/arm64:
./vendor/k8s.io/code-generator/cmd/deepcopy-gen
+++ [1020 13:27:34] Building go targets for linux/arm64:
./vendor/k8s.io/code-generator/cmd/defaulter-gen
+++ [1020 13:27:58] Building go targets for linux/arm64:
./vendor/k8s.io/code-generator/cmd/conversion-gen
+++ [1020 13:28:28] Building go targets for linux/arm64:
./vendor/k8s.io/kube-openapi/cmd/openapi-gen
2018/10/20 13:29:04 Code for OpenAPI definitions generated
+++ [1020 13:29:04] Building go targets for linux/arm64:
./vendor/github.com/jteeuwen/go-bindata/go-bindata
+++ [1020 13:29:09] Building go targets for linux/arm64:
cmd/kube-proxy
cmd/kube-apiserver
cmd/kube-controller-manager
cmd/cloud-controller-manager
cmd/kubelet
cmd/kubeadm
cmd/hyperkube
cmd/kube-scheduler
vendor/k8s.io/apiextensions-apiserver
cluster/gce/gci/mounter
cmd/kubectl
cmd/gendocs
cmd/genkubedocs
cmd/genman
cmd/genyaml
cmd/genswaggertypedocs
cmd/linkcheck
vendor/github.com/onsi/ginkgo/ginkgo
test/e2e/e2e.test
cmd/kubemark
vendor/github.com/onsi/ginkgo/ginkgo
test/e2e_node/e2e_node.test
...
Die gebauten Pakete sollten auf alle Knoten verteilt werden oder über ein lokales Repository bereitgestellt werden.
Kubernetes Cluster Update
Das Update des Kubernetes Clusters auf eine neue Kubernetes Version erfolgt in zwei Stufen:
Zunächst wird der Master Node auf die neueste Kubernetes Version aktualisiert, danach die Worker.
Da kubeadm
derzeit lediglich einen einzelnen Master unterstützt, wird auch nur ein Knoten aktualisiert.
CRI-O Update
Auf allen Nodes wird zunächst das aktualisierte CRI-O und crictl
ausgerollt.
crictl
$ sudo pacman -U cri*.pkg.tar.xz
loading packages...
resolving dependencies...
looking for conflicting packages...
Packages (2) cri-o-1.11.7-1 crictl-bin-1.12.0-1
Total Installed Size: 49.54 MiB
Net Upgrade Size: 4.22 MiB
:: Proceed with installation? [Y/n]
...
Master Node
Als erstes wird das neue Kubernetes Arch Paket installiert, danach die Version von kubeadm
kontrolliert.
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.1", GitCommit:"b1b29978270dc22fecc592ac55d903350454310a", GitTreeState:"archive", BuildDate:"2018-07-28T11:57:20Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/arm64"}
$ sudo pacman -U kubernetes-1.12.1-1-aarch64.pkg.tar.xz
loading packages...
resolving dependencies...
looking for conflicting packages...
Packages (1) kubernetes-1.12.1-1
Total Installed Size: 820.89 MiB
Net Upgrade Size: 95.88 MiB
:: Proceed with installation? [Y/n]
...
: Running post-transaction hooks...
(1/3) Reloading system manager configuration...
(2/3) Creating temporary files...
(3/3) Arming ConditionNeedsUpdate...
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.1", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"archive", BuildDate:"2018-10-20T12:23:34Z", GoVersion:"go1.11.1", Compiler:"gc", Platform:"linux/arm64"}
Durch kubeadm
wird ein Upgrade von Kubernetes nativ unterstützt und erfordert wenige manuelle Eingriffe.
kubeadm
$ sudo kubeadm upgrade plan
[preflight] Running pre-flight checks.
[upgrade] Making sure the cluster is healthy:
[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'
[upgrade] Fetching available versions to upgrade to
[upgrade/versions] Cluster version: v1.11.1
[upgrade/versions] kubeadm version: v1.12.1
[upgrade/versions] Latest stable version: v1.12.1
[upgrade/versions] Latest version in the v1.11 series: v1.11.3
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 4 x v1.11.1 v1.12.1
Upgrade to the latest stable version:
COMPONENT CURRENT AVAILABLE
API Server v1.11.1 v1.12.1
Controller Manager v1.11.1 v1.12.1
Scheduler v1.11.1 v1.12.1
Kube Proxy v1.11.1 v1.12.1
CoreDNS 1.2.2 1.2.2
Etcd 3.2.18 3.2.24
You can now apply the upgrade by executing the following command:
kubeadm upgrade apply v1.12.1
_____________________________________________________________________
Das eigentliche Upgrade der Control Plane wird dann durch kubeadm upgrade
gestartet.
Folgende Schritte führt das Upgrade dabei durch:
-
Überprüfung des Kubernetes Cluster-Zustands
-
API Server ist erreichbar
-
Alle Nodes sind im
Ready
Zustand -
Control-Plane ist betriebsbereit
-
-
Einhaltung der Upgrade-Policy: Lediglich Minor-Updates werden unterstützt
-
Prüfung, dass die Container-Images für die Control-Plane verfügbar sind oder gepullt werden können
-
Upgrade der Control-Plane Komponenten mit automatischem Rollback, falls Probleme auftreten
-
Aktualisierung der
kube-dns
undkube-proxy
Manifeste und aller erforderlichen RBAC Rollen -
Falls Zertifikate oder private Schlüsseln des API Servers in den nächsten 180 Tagen auslaufen werden diese aktualisiert, das bisherige Schlüsselmaterial gesichert
kubeadm
$ sudo kubeadm upgrade apply v1.12.1 [preflight] Running pre-flight checks. [upgrade] Making sure the cluster is healthy: [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' [upgrade/apply] Respecting the --cri-socket flag that is set with higher priority than the config file. [upgrade/version] You have chosen to change the cluster version to "v1.12.1" [upgrade/versions] Cluster version: v1.11.1 [upgrade/versions] kubeadm version: v1.12.1 [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-apiserver [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-controller-manager [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 kube-controller-manager. [upgrade/prepull] Prepulled image for component kube-apiserver. [upgrade/prepull] Prepulled image for component kube-scheduler. [upgrade/prepull] Prepulled image for component etcd. [upgrade/prepull] Successfully prepulled the images for all the control plane components [upgrade/apply] Upgrading your Static Pod-hosted control plane to version "v1.12.1"... Static pod: kube-apiserver-c2-master0 hash: fc768201867c1cdaeebbd9617ed4285c Static pod: kube-controller-manager-c2-master0 hash: 6474abf9737348f996b44d724256fa9e Static pod: kube-scheduler-c2-master0 hash: 6e1c1eb822c75df4cec74cac9992eea9 Static pod: etcd-c2-master0 hash: 24e2ce158856a08e7e23269fd3aa6740 [etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests507879547/etcd.yaml" [upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/etcd.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2018-10-20-13-02-07/etcd.yaml" [upgrade/staticpods] Waiting for the kubelet to restart the component [upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s Static pod: etcd-c2-master0 hash: 24e2ce158856a08e7e23269fd3aa6740 Static pod: etcd-c2-master0 hash: 24e2ce158856a08e7e23269fd3aa6740 Static pod: etcd-c2-master0 hash: 24e2ce158856a08e7e23269fd3aa6740 Static pod: etcd-c2-master0 hash: 18d7366d9b7791d910e690a889ab5233 [apiclient] Found 1 Pods for label selector component=etcd [upgrade/staticpods] Component "etcd" upgraded successfully! [upgrade/etcd] Waiting for etcd to become available [util/etcd] Waiting 0s for initial delay [util/etcd] Attempting to see if all cluster endpoints are available 1/10 [upgrade/staticpods] Writing new Static Pod manifests to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests507879547" [controlplane] wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests507879547/kube-apiserver.yaml" [controlplane] wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests507879547/kube-controller-manager.yaml" [controlplane] wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests507879547/kube-scheduler.yaml" [upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-apiserver.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2018-10-20-13-02-07/kube-apiserver.yaml" [upgrade/staticpods] Waiting for the kubelet to restart the component [upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s Static pod: kube-apiserver-c2-master0 hash: fc768201867c1cdaeebbd9617ed4285c Static pod: kube-apiserver-c2-master0 hash: fc768201867c1cdaeebbd9617ed4285c Static pod: kube-apiserver-c2-master0 hash: fc768201867c1cdaeebbd9617ed4285c ... [apiclient] Found 1 Pods for label selector component=kube-apiserver [upgrade/staticpods] Component "kube-apiserver" upgraded successfully! [upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-controller-manager.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2018-10-20-13-02-07/kube-controller-manager.yaml" [upgrade/staticpods] Waiting for the kubelet to restart the component [upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s Static pod: kube-controller-manager-c2-master0 hash: 6474abf9737348f996b44d724256fa9e Static pod: kube-controller-manager-c2-master0 hash: c5bc680d2460cb6417f3b079a50f53db [apiclient] Found 1 Pods for label selector component=kube-controller-manager [upgrade/staticpods] Component "kube-controller-manager" upgraded successfully! [upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-scheduler.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2018-10-20-13-02-07/kube-scheduler.yaml" [upgrade/staticpods] Waiting for the kubelet to restart the component [upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s Static pod: kube-scheduler-c2-master0 hash: 6e1c1eb822c75df4cec74cac9992eea9 Static pod: kube-scheduler-c2-master0 hash: 24b4b7b60678e898e3b4ff5fe89c6968 [apiclient] Found 1 Pods for label selector component=kube-scheduler [upgrade/staticpods] Component "kube-scheduler" upgraded successfully! [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.12" in namespace kube-system with the configuration for the kubelets in the cluster [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.12" ConfigMap in the kube-system namespace [kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "c2-master0" as an annotation [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] 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.12.1". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
Nun bleibt noch ein Upgrade eines evtl. genutzten CNI Netzwerkes.
Hat man sich für Weave entschieden, ist nicht viel zu tun:
Das DaemonSet
von Weave verwendet Rolling Updates - wird eine neue Kubernetes Version installiert, werden die Weave Net Pods automatisch der Reihe nach aktualisiert.
Damit das neue kubelet verwendet wird, muss der Prozess neu gestartet werden. Es empfiehlt sich ggf. vorhandene Workload vom Master vorher herunter zu nehmen.
$ NODE=c2-master0
$ kubectl drain $NODE --ignore-daemonsets
$ sudo systemctl restart kubelet
$ kubectl uncordon $NODE
Eine Überprüfung der Node Liste zeigt, dass der Master erfolgreich aktualisiert wurde.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
c2-master0 Ready master 85d v1.12.1
c2-worker0 Ready <none> 85d v1.11.1
c2-worker1 Ready <none> 85d v1.11.1
c2-worker2 Ready <none> 85d v1.11.1
Worker Nodes
Die Worker Nodes werden einzeln aktualisiert, damit es zu keinen Einschränkungen der Verfügbarkeit kommt.
Dazu wird zunächst mittels kubectl drain
die Arbeitslast evakuiert - Kubernetes stellt sicher, dass die Pods auf anderen Knoten des Clusters neu gestartet werden.
Durch die Option --ignore-daemonsets
werden Fehlermeldungen unterdrückt, die durch auf der Node aktive DaemonSet
Objekte verursacht werden - da ein DaemonSet
an eine Node gebunden ist, lässt sich diese nicht auf eine ander Node umziehen.
Werden Pods ausgeführt, die lokal Daten speichern, kann die Option --delete-local-data
mit angegeben werden.
Da lokaler Speicher nicht im Cluster an einem anderen Ort bereitgestellt werden kann, gehen diese Daten verloren, wenn die zugehörigen Pods auf einer anderen Node neu erzeugt werden.
Wichtig ist generell zu beachten: Wird mit einer harten Affinity oder Anti-Affinity gearbeitet, sollte stets eine reserve Node zur Verfügung stehen, damit die Pods tatsächlich evakuiert werden können.
Die mit local:
angegebenen Schritte können auf einem beliebigen Host mit Zugriff auf den API Server durchgeführt werden, die weiteren Schritte werden jeweils auf den einzelnen Kubernetes Nodes durchgeführt.
local:~$ NODE=c2-worker0
local:~$ kubectl drain $NODE --ignore-daemonsets --delete-local-data
node/c2-worker0 cordoned
WARNING: Ignoring DaemonSet-managed pods: kube-proxy-wj5bn, weave-net-58th2, rook-ceph-agent-mbhfd, rook-discover-fqbgc; Deleting pods with local storage: monitoring-grafana-57dd5f7b66-mmgp2
pod/rook-ceph-osd-prepare-c2-worker0-2pwbb evicted
pod/rook-ceph-mon6-r8h9r evicted
pod/monitoring-grafana-57dd5f7b66-mmgp2 evicted
pod/rook-ceph-osd-id-1-657ff7cdf6-djnjt evicted
Nun ist auf dem Worker auch der passende Zeitpunkt, um CRI-O zu aktualisieren.
$ sudo systemctl stop kubelet
$ sudo systemctl stop crio
$ sudo pacman -U cri*.pkg.tar.xz
$ sudo systemctl start crio
Auf den Worker Nodes muss zusätzlich die Konfiguration von kubelet
aktualisiert werden, was ebenfalls durch kubeadm
unterstützt wird.
$ sudo pacman -U kubernetes-1.12.1-1-aarch64.pkg.tar.xz
...
$ sudo kubeadm upgrade node config --kubelet-version $(kubelet --version | cut -d ' ' -f 2)
$ sudo systemctl restart kubelet
$ systemctl status kubelet
* kubelet.service - Kubernetes Kubelet Server
Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2018-10-20 13:35:48 UTC; 6s ago
Docs: https://kubernetes.io/docs/concepts/overview/components/#kubelet
https://kubernetes.io/docs/reference/generated/kubelet/
Main PID: 28843 (kubelet)
Tasks: 19 (limit: 2124)
Memory: 85.1M
CGroup: /system.slice/kubelet.service
local:~$ kubectl uncordon $NODE
Sind alle Nodes aktualisiert, sollten diese auch wieder als verfügbar gelistet werden:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
c2-master0 Ready master 85d v1.12.1
c2-worker0 Ready <none> 85d v1.12.1
c2-worker1 Ready <none> 85d v1.12.1
c2-worker2 Ready <none> 85d v1.12.1
Der Kubernetes Cluster steht nun in der aktuellen Version zur Verfügung. Je nach Kubernetes Distribution und verwendetem Tooling sieht der Upgrade-Prozess natürlich anders aus.
Upgrade oder Phoenix
Eine alternative Vorgehensweise zu dem beschriebenen Upgrade des Kubernetes Clusters ist die Einrichtung eines separaten Clusters mit entsprechend neuer Kubernetes Version. Die Workload kann dann von dem bisherigen Cluster in den neuen Cluster umgezogen werden, der alte Cluster anschließend außer Betrieb genommen werden.
Im Prinzip ist das Vorgehen die Anwendung von blue-green-Deployment auf Cluster Ebene und erlaubt zum einen größere Versionssprünge, zum anderen ist ein Rollback jederzeit möglich. Der Aufwand und Resourcenbedarf ist bei diesem Vorgehen jedoch höher und dürft vor allem in Cloud-Umgebungen praktikabel sein, die dynamisch Resourcen zur Verfügung stellen. Gerade in Cloud Umgebungen werden jedoch in der Regel managed Kubernetes Umgebungen angeboten und stellen angesichts des mit Upgrades einhergehenden Aufwands eine attraktive Alternative dar.
Zu den Themen Kubernetes, Docker und Cloud Architektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.