Kubernetes 1.13 auf ARM mit CRI-O und Arch Linux
In diesem Beitrag wurde die Installation von Kubernetes auf ODROID unter Arch Linux ARM beschrieben.
Hier geht es nun um das Update auf Kubernetes 1.13, auch in diesem Fall mit selbst übersetzten Paketen für Arch Linux. Bei anderen Distributionen sind ggf. bereits die Upstream Pakete verfügbar.
Wie schon in Kubernetes Upgrade Arch Linux ARM im Detail beschrieben, wird das Update in folgenden Schritten durchgeführt:
-
Update der Container Runtime (falls erforderlich)
-
Update der Kubernetes Binaries auf den Master Nodes (Control Plane)
-
Update der Kubernetes Pods auf den Master Nodes
-
Aktualisierung der Kubernetes Binaries auf den Worker Nodes
Zum Build von Kubernetes 1.13
Da der Go Build von Kubernetes erhebliche Mengen Speicher zur Übersetzung und zum Linking benötigt, kann es auf Maschinen mit wenig Speicher erforderlich sein, einige Kniffe anzuwenden. Details dazu finden sich in diesem Beitrag sowie in dieser GitHub Issue: https://github.com/kubernetes/kubernetes/issues/70062
Build CRI-O und crictl
Zunächst werden aktuelle Versionen von CRI-O und der CRI-Tools (crictl) 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.13.0
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 runc
Auch runc
ist in einer neueren Version verfügbar, analog wird ein Paket gebaut.
# Maintainer: Thomas Kruse <[email protected]>
# Contributor: Sébastien "Seblu" Luttringer
pkgname=runc
pkgver=1.0.0rc6+169+gccb5efd37
pkgrel=1
pkgdesc='CLI tool for managing OCI compliant containers'
arch=(x86_64 aarch64)
url='https://runc.io/'
license=(Apache)
depends=(glibc libseccomp)
makedepends=(git go go-md2man)
_commit=v1.0.0-rc6 # master
source=(git+https://github.com/opencontainers/runc.git#commit=$_commit)
md5sums=('SKIP')
pkgver() {
cd runc
git describe | sed 's/^v//;s/-//;s/-/+/g'
}
prepare() {
mkdir -p src/github.com/opencontainers
cp -r runc src/github.com/opencontainers/
}
build() {
cd src/github.com/opencontainers/runc
GOPATH="$srcdir" BUILDTAGS='seccomp' make runc man
}
package() {
cd src/github.com/opencontainers/runc
install -Dm755 runc "$pkgdir/usr/bin/runc"
install -Dm644 contrib/completions/bash/runc \
"$pkgdir/usr/share/bash-completion/completions/runc"
install -d "$pkgdir/usr/share/man/man8"
install -m644 man/man8/*.8 "$pkgdir/usr/share/man/man8"
}
Auch hier erfolgt der Build am einfachsten mit makepkg
.
Build von Kubernetes 1.13 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]>
# sha256sum kubernetes-1.13.2.tar.gz
pkgname=kubernetes
pkgver=1.13.2
_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=('8ccae08b6a02fcb4ceb153da0e5c80dc9f4fef9afe46f162518622f58bcf01d8'
'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
}
Die gebauten Pakete sollten auf alle Knoten verteilt werden oder über ein lokales Repository bereitgestellt werden.
Kubernetes Cluster Update
Zunächst wird die Container-Runtime aktualisiert, anschließend die Kubernetes Komponenten selbst.
Das Update des Kubernetes Clusters auf neue Kubernetes Komponenten erfolgt in Stufen:
Zunächst wird der Master Node auf die neueste Kubernetes Version aktualisiert, danach die Worker.
Da das Beispiel aus lediglich einen einzelnen Master besteht, wird auch nur ein Knoten aktualisiert.
Update der Container Runtime
crictl
und runC$ sudo systemctl stop kubelet
$ sudo systemctl stop crio
$ sudo pacman -U cri*.pkg.tar.xz
$ sudo pacman -U runc*.pkg.tar.xz
$ sudo systemctl start crio
Update Kubernetes Master Node
Als erstes wird das neue Kubernetes Arch Paket installiert, danach die Version von kubeadm
verifiziert.
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.1", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"archive", BuildDate:"2018-10-20T20:23:34Z", GoVersion:"go1.11.1", Compiler:"gc", Platform:"linux/arm64"}
$ sudo pacman -U kubernetes-*.tar.xz
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.0", GitCommit:"ddf47ac13c1a9483ea035a79cd7c10005ff21a6d", GitTreeState:"archive", BuildDate:"2018-12-14T19:37:01Z", GoVersion:"go1.11.2", 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.
...
Das eigentliche Upgrade der Kubernetes Control Plane wird durch kubeadm upgrade
gestartet.
kubeadm
$ sudo kubeadm upgrade apply v1.13.0 ... [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.13.0". Enjoy!
Nun bleibt noch ein Upgrade eines evtl. genutzten CNI Netzwerkes.
Bei Weave 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 vorher ggf. vorhandene Workload vom Master 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 127d v1.13.0
c2-worker0 Ready <none> 127d v1.12.1
c2-worker1 Ready <none> 127d v1.12.1
c2-worker2 Ready <none> 127d v1.12.1
Update Kubernetes Worker Nodes
Die Worker Nodes werden einzeln aktualisiert, damit es zu keinen Einschränkungen der Verfügbarkeit des Kubernetes Clusters kommt.
Dazu wird jeweils mit kubectl drain --ignore-daemonsets
die Node evakuiert, aktualisiert und mit kubectl uncordon
wieder aktiviert.
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.
local:~$ NODE=c2-worker0
local:~$ kubectl drain $NODE --ignore-daemonsets --delete-local-data
Nun ist auf dem Worker auch der passende Zeitpunkt, um CRI-O und runC zu aktualisieren.
$ sudo systemctl stop kubelet; sudo systemctl stop crio
$ sudo pacman -U cri*.pkg.tar.xz; sudo pacman -U runc*.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-*-aarch64.pkg.tar.xz
...
$ sudo kubeadm upgrade node config --kubelet-version $(kubelet --version | cut -d ' ' -f 2)
$ sudo systemctl restart kubelet
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 127d v1.13.0
c2-worker0 Ready <none> 127d v1.13.0
c2-worker1 Ready <none> 127d v1.13.0
c2-worker2 Ready <none> 127d v1.13.0
Das Upgrade des Kubernetes Clusters ist nun beendet. Alternativ zum Update des Clusters gibt es als Vorgehensweise, einen neuen Kubernetes Cluster mit der gewünschten Version zu erstellen und die Workload auf den Cluster umzuziehen. Außerhalb von Cloud-Umgebungen ist dazu jedoch entsprechend viel an Resourcen vorzuhalten, so dass das Vorgehen in der Praxis unpraktikabel sein kann.
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.