Neuigkeiten von trion.
Immer gut informiert.

Kubernetes mit CRI-O auf Arch Linux ARM

Auch wenn Docker stand heute die vermutlich am weitesten verbreitete Container-Lösung darstellt, gibt es doch einen regen Wettbewerb. Besonders seit Kubernetes in Version 1.5 das Container-Runtime-Interface (CRI) eingeführt hat, mit dem sich die tatsächliche Container-Implementierung austauschen lässt. Das CRI-O Projekt stellt einen Adapter zwischen der durch die OCI (Open Container Initiative) spezifizierten Schnittstellen für Container-Runtimes und dem durch Kubernetes mit CRI definierten Integrationspunkten dar. Standardmäßig verwendet CRI-O die OCI konforme Containerimplementierung runc.

Andere OCI kompatible Laufzeitumgebungen wie rkt oder Intel Clear Container lassen sich damit ebenfalls einsetzen. In einem typischen Docker basierten Setup sähe die Interaktion so aus:

  • Der kubelet Prozess verwaltet die Container der Node, nutzt dabei die CRI Schnittstelle zur Kommunikation

  • mit dem dockershim, einer CRI-zu-Docker API Bridge, die ihrerseits

  • mit dem eigentlichen docker-Daemon kommuniziert, der dann

  • mit dem containerd-Daemon kommuniziert und darüber

  • runc aufruft, um konkrete Container zu managen

Mit CRI-O sieht die Interaktion so aus:

  • Der kubelet Prozess verwaltet die Container der Node, nutzt dabei die CRI Schnittstelle zur Kommunikation

  • mit dem CRI-O-Daemon, der dann eine OCI kompatible Container-Laufzeitumgebung aufruft, im Default ist das

  • die runc, die auch Docker verwendet

Der Stack bei CRI-O ist also deutlich geringer, ist jedoch als auf Kubernetes fokussierter Stack auch kein vollständiger Ersatz für die vielen verschiedenen Anwendungsfälle von Docker.

Im folgenden geht es um das konkrete Setup von CRI-O mit Kubernetes unter Arch Linux ARM.

Benötigt werden die folgenden Pakete:

  • runc zur Ausführung von Containern

  • CRI-O als Daemon zur Verwaltung der Container

  • crictl als CRI-O Kommandozeilenwerkzeug für Tests und Analyse (optional)

  • CNI und CNI-Plugins zur Implementierung von Container Netzwerken

runc für ARM

Als erstes wird runc bereitgestellt. Über dieses Programm können Container gestartet und gestoppt werden, runc übernimmt dabei die direkte Kommunikation mit dem Linux Kernel.

Der Build des Arch Linux ARM Pakets wird durch eine passende PKGBUILD Datei beschrieben.

PKGBUILD für runc
# Maintainer: Thomas Kruse <tk-kaal@trion.de>
# Contributor: Sébastien "Seblu" Luttringer

pkgname=runc
pkgver=1.0.0rc5+19+g69663f0b
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-rc5  # 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"
}

Die eigentliche Paketierung erfolgt dann durch makepkg -s.

Build des runc Arch Paketes
$ makepkg -s
==> Making package: runc 1.0.0rc5-1
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
  -> Updating runc git repo...
Fetching origin
==> Validating source files with md5sums...
    runc ... Skipped
==> Extracting sources...
  -> Creating working copy of runc git repo...
Cloning into 'runc'...
done.
Switched to a new branch 'makepkg'
==> Starting prepare()...
==> Starting pkgver()...
==> Removing existing $pkgdir/ directory...
==> Starting build()...
go build -buildmode=pie  -ldflags "-X main.gitCommit="4fc53a81fb7c994640722ac585fa9ca548971871" -X main.version=1.0.0-rc5 " -tags "seccomp" -o runc .
man/md2man-all.sh
...
+ go-md2man -in runc.8.md -out ./man8/runc.8
==> Entering fakeroot environment...
==> Starting package()...
==> Tidying install...
  -> Removing, diskussionen libtool files...
  -> Purging unwanted files...
  -> Removing static library files...
  -> Stripping unneeded symbols from binaries and libraries...
  -> Compressing man and info pages...
==> Checking for packaging issues...
==> WARNING: Package contains reference to $srcdir
usr/bin/runc
==> Creating package "runc"...
  -> Generating .PKGINFO file...
  -> Generating .BUILDINFO file...
  -> Generating .MTREE file...
  -> Compressing package...
==> Leaving fakeroot environment.
==> Finished making: runc 1.0.0rc5-1

Nun steht mit runc die grundlegende Infrastruktur bereit, um Container zu starten. Damit Kubernetes damit arbeiten kann, wird als nächstes CRI-O installiert.

CRI-O für ARM 64 (aarch64)

Um CRI-O für ARM 64 auf Arch Linux zu paketieren wird eine PKBUILD Datei benötigt. Darin ist der Build des Paketes beschreiben.

PKGBUILD für CRI-O Arch Linux ARM 64
# Maintainer: Thomas Kruse <tk-kaal@trion.de>
# Contributor: Tony Lambiris <tony@criticalstack.com>

pkgname=cri-o
pkgver=1.11
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
}

Ausgeführt wird der Build anschließend mit makepkg -s, wie im folgenden zu sehen:

$ makepkg -s
==> Making package: cri-o 1.11-1 (Sun Jul 22 17:57:22 2018)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
  -> Updating cri-o git repo...
Fetching origin
==> Validating source files with sha256sums...
    cri-o ... Skipped
==> Extracting sources...
  -> Creating working copy of cri-o git repo...
Switched to a new branch 'makepkg'
==> Starting prepare()...
Branch 'release-1.11' set up to track remote branch 'release-1.11' from 'origin'.
Switched to a new branch 'release-1.11'
==> Starting build()...
touch "/home/tkruse/cri-o/src/go/.gopathok"
go build -i -ldflags '-s -w -X main.gitCommit="cd1f68f3d6183995526fb8935f5fc5feaa45245c" -X main.buildInfo=1532282245' -tags "btrfs_noversion   exclude_graphdriver_btrfs  seccomp  containers_image_ostree_stub" -o bin/crio github.com/kubernetes-incubator/cri-o/cmd/crio
( cd conmon && /home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/bin/crio-config )
make -C conmon
make[1]: Entering directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/conmon'
cc -march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include  -DVERSION=\"1.11.2-dev\" -DGIT_COMMIT=\""cd1f68f3d6183995526fb8935f5fc5feaa45245c"\" -D_FORTIFY_SOURCE=2  -c -o conmon.o conmon.c
cc -march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include  -DVERSION=\"1.11.2-dev\" -DGIT_COMMIT=\""cd1f68f3d6183995526fb8935f5fc5feaa45245c"\" -D_FORTIFY_SOURCE=2  -c -o cmsg.o cmsg.c
cc -o ../bin/conmon config.h conmon.o cmsg.o -march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include  -DVERSION=\"1.11.2-dev\" -DGIT_COMMIT=\""cd1f68f3d6183995526fb8935f5fc5feaa45245c"\" -lglib-2.0
make[1]: Leaving directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/conmon'
make -C pause
make[1]: Entering directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/pause'
cc -march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -static -D_FORTIFY_SOURCE=2  -c -o pause.o pause.c
cc -o ../bin/pause pause.o -march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -static
make[1]: Leaving directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/pause'
(go-md2man -in docs/crio.conf.5.md -out docs/crio.conf.5.tmp && touch docs/crio.conf.5.tmp && mv docs/crio.conf.5.tmp docs/crio.conf.5) || (/home/tkruse/cri-o/src/go/bin/go-md2man -in docs/crio.conf.5.md -out docs/crio.conf.5.tmp && touch docs/crio.conf.5.tmp && mv docs/crio.conf.5.tmp docs/crio.conf.5)
(go-md2man -in docs/crio.8.md -out docs/crio.8.tmp && touch docs/crio.8.tmp && mv docs/crio.8.tmp docs/crio.8) || (/home/tkruse/cri-o/src/go/bin/go-md2man -in docs/crio.8.md -out docs/crio.8.tmp && touch docs/crio.8.tmp && mv docs/crio.8.tmp docs/crio.8)
WARN[0000] default configuration file does not exist: /etc/crio/crio.conf
==> Entering fakeroot environment...
==> Starting package()...
go build -i -ldflags '-s -w -X main.gitCommit="cd1f68f3d6183995526fb8935f5fc5feaa45245c" -X main.buildInfo=1532282435' -tags "btrfs_noversion   exclude_graphdriver_btrfs  seccomp  containers_image_ostree_stub" -o bin/crio github.com/kubernetes-incubator/cri-o/cmd/crio
make -C conmon
make[1]: Entering directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/conmon'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/conmon'
make -C pause
make[1]: Entering directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/pause'
make[1]: '../bin/pause' is up to date.
make[1]: Leaving directory '/home/tkruse/cri-o/src/go/src/github.com/kubernetes-incubator/cri-o/pause'
install  -D -m 755 bin/crio /home/tkruse/cri-o/pkg/cri-o/usr/bin/crio
install  -D -m 755 bin/conmon /home/tkruse/cri-o/pkg/cri-o/usr/libexec/crio/conmon
install  -D -m 755 bin/pause /home/tkruse/cri-o/pkg/cri-o/usr/libexec/crio/pause
install  -d -m 755 /home/tkruse/cri-o/pkg/cri-o/usr/share/man/man5
install  -d -m 755 /home/tkruse/cri-o/pkg/cri-o/usr/share/man/man8
install  -m 644 docs/crio.conf.5 -t /home/tkruse/cri-o/pkg/cri-o/usr/share/man/man5
install  -m 644 docs/crio.8 -t /home/tkruse/cri-o/pkg/cri-o/usr/share/man/man8
install  -D -m 644 contrib/systemd/crio.service /home/tkruse/cri-o/pkg/cri-o/usr/lib/systemd/system/crio.service
ln -sf crio.service /home/tkruse/cri-o/pkg/cri-o/usr/lib/systemd/system/cri-o.service
install  -D -m 644 contrib/systemd/crio-shutdown.service /home/tkruse/cri-o/pkg/cri-o/usr/lib/systemd/system/crio-shutdown.service
==> Tidying install...
  -> Removing libtool files...
  -> Purging unwanted files...
  -> Removing static library files...
  -> Stripping unneeded symbols from binaries and libraries...
  -> Compressing man and info pages...
==> Checking for packaging issues...
==> WARNING: Package contains reference to $srcdir
usr/bin/crio
==> Creating package "cri-o"...
  -> Generating .PKGINFO file...
  -> Generating .BUILDINFO file...
  -> Generating .MTREE file...
  -> Compressing package...
==> Leaving fakeroot environment.
==> Finished making: cri-o 1.11-1 (Sun Jul 22 18:01:58 2018)

Das fertige Paket kann dann wie gewohnt, zum Beispiel mit pacman, installiert werden.

Installation von CRI-O auf Arch Linux mit pacman
$ sudo pacman -U cri-o-1.11-1-aarch64.pkg.tar.xz
loading packages...
resolving dependencies...
looking for conflicting packages...

Packages (1) cri-o-1.11-1

Total Installed Size:  30.48 MiB

:: Proceed with installation? [Y/n]
(1/1) checking keys in keyring                   [##############################################] 100%
(1/1) checking package integrity                 [##############################################] 100%
(1/1) loading package files                      [##############################################] 100%
(1/1) checking for file conflicts                [##############################################] 100%
(1/1) checking available disk space              [##############################################] 100%
:: Processing package changes...
(1/1) installing cri-o                           [##############################################] 100%
:: Running post-transaction hooks...
(1/2) Reloading system manager configuration...
(2/2) Arming ConditionNeedsUpdate...

Damit CRI-O funktioniert, müssen noch einige Konfigurationen vorgenommen werden. Dazu gehört zum einen die zu verwendende Container-Registry für Images, die ohne voll qualifizierten Namen referenziert werden. Zum anderen müssen die "default_mounts" deaktiviert sein, sonst gibt es später Probleme mit Kubernetes Secrets.

Konfiguration in /etc/crio/crio.conf
registries = ['docker.io']

#default_mounts = [
#       "/run/secrets",
#]

Auch muss eine Policy definiert werden, von wo Images akzeptiert werden, die nicht über eine vertrauenswürdige Signatur verfügen. Diese Konfiguration erfolgt in der JSON Datei /etc/containers/policy.json. Das Docker Standardverhalten, von überall Images zu akzeptieren, kann dann wie folgt erzielt werden:

Image Policy Konfiguration in /etc/containers/policy.json
{
    "default": [{"type": "insecureAcceptAnything"}]
}

Der Pfad der CNI Plugins muss korrekt gesetzt sein, damit die Netzwerkkonfiguration durch CRI-O vorgenommen werden kann.

CNI Konfiguration in /etc/crio/crio.conf
plugin_dir = "/opt/cni/bin"

Zur Verwaltung des CRI-O Dienstes durch systemd wird nun noch ein systemd-Unit-File erzeugt.

Einrichtung der systemd-Unit
$ sudo sh -c 'echo "[Unit]
Description=OCI-based implementation of Kubernetes Container Runtime Interface
Documentation=https://github.com/kubernetes-incubator/cri-o

[Service]
ExecStart=/usr/bin/crio
Restart=always
RestartSec=15

[Install]
WantedBy=multi-user.target" > /etc/systemd/system/crio.service'

Wie üblich wird nun die systemd Konfiguration neu geladen und der CRI-O Dienst aktiviert. Er kann im Anschluß auch direkt gestartet werden.

Aktivierung des CRI-O Dienstes und Start von CRI-O
$ sudo systemctl daemon-reload
$ sudo systemctl enable crio
$ sudo systemctl start crio

Wenn bis hierhin keine Fehler aufgetreten sind, steht CRI-O nun zur Verfügung. Um zu verifizieren, dass CRI-O korrekt arbeitet, kann mit dem Kommandozeilenwerkzeug crictl gearbeitet werden. Auch das muss zunächst paketiert werden, das passende PKGBUILD sieht wie folgt aus:

PKGBUILD für crictl Arch Linux ARM 64
# Maintainer: Thomas Kruse <tk-kaal@trion.de>
# Maintainer: ProFfeSsoRr <evvsoft at gmail dot com>

pkgname=crictl-bin
pkgver=1.11.1
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
}

Die globale Konfiguration von crictl erfolgt in der YAML Datei /etc/crictl.yaml, dort werden z.B. die CRI-O Endpoints konfiguriert.

Konfiguration von crictl in /etc/crictl.yaml
runtime-endpoint: unix:///var/run/crio/crio.sock
image-endpoint: unix:///var/run/crio/crio.sock
timeout: 10
debug: false

Nach der Installation der erstellten Pakets kann mittels crictl die CRI-O Version abgefragt werden.

Verwendung von crictl
$ sudo crictl --runtime-endpoint unix:///var/run/crio/crio.sock version
Version:  0.1.0
RuntimeName:  cri-o
RuntimeVersion:  1.11.2-dev
RuntimeApiVersion:  v1alpha1

Analog zu Docker können mittels crictl auch Images gepullt werden, im Beispiel das Kubernetes Pause Image für ARM 64 bit.

$ sudo crictl pull k8s.gcr.io/pause-arm64:3.1
Image is up to date for k8s.gcr.io/pause-arm64@sha256:f365626a556e58189fc21d099fc64603db0f440bff07f77c740989515c544a39

Auffällig ist dabei, dass es keine Fortschrittsanzeige, wie bei Docker gibt. Das ist normal, über die CRI API werden die Fortschrittsinformationen nicht bereitgestellt. Im nicht-interaktiven Umfeld eines Kubernetes Clusters werden diese schlicht nicht benötigt, und Ziel von CRI ist schließlich eine minimale Schnittstelle.

Um Images zu pullen und Container zu starten ist nun alles vorhanden. Es fehlt jedoch noch eine Möglichkeit, für die Container ein isoliertes Netzwerk bereitzustellen. Dafür gibt es CNI, das Container Network Interface.

CNI Setup

CNI ist aus der rkt Runtime entstanden und mittlerweile ein Projekt der Cloud Native Computing Foundation. Durch CNI werden Netzwerkkonfigurationen für Container vorgenommen.

Die Paketierung von CNI und den CNI-Plugins erfolgt analog. Dazu können die folgenden PKGBUILD Konfigurationen verwendet werden.

PKBUILD für CNI
# Maintainer: Thomas Kruse <tk-kaal@trion.de>
# Contributor: Tobias Martin <tm-x at gmx dot net>

pkgname=cni
pkgver=0.6.0
pkgrel=2
pkgdesc="Specification and libraries for writing plugins to configure network interfaces in Linux containers"
arch=('i686' 'x86_64' 'aarch64')
url="https://github.com/containernetworking/cni"
license=('Apache')
makedepends=('go')
depends=('glibc')
source=("https://github.com/containernetworking/${pkgname}/archive/v${pkgver}.tar.gz")
sha512sums=('3b5b35ed546f82a939b3090ac49d2f7ab0542a079d0f45b0dd9b45cf4849abb6c10fbcb810b7567a7a15d6b8144f5b3962bfca319a37342c5bc39f5fa58f0777')

build() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  ./build.sh
}

package() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  mkdir -p "${pkgdir}/opt/${pkgname}/"
  cp -dr --no-preserve=ownership bin "${pkgdir}/opt/${pkgname}/"

  mkdir -p ${pkgdir}/usr/share/licenses/${pkgname}
  install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}

Der Build erfolgt auch hier mit makepkg -s.

PKBUILD für CNI Plugins
# Maintainer: Thomas Kruse <tk-kaal@trion.de>
# Contributor: Roman Lisagor <rlisagor at gmail dot com>

pkgname=cni-plugins
pkgver=0.6.0
pkgrel=1
pkgdesc="Some standard networking plugins, maintained by the CNI team"
arch=('i686' 'x86_64' 'aarch64')
url="https://github.com/containernetworking/plugins"
license=('Apache')
makedepends=('go')
optdepends=('cni')
depends=('glibc')
source=("https://github.com/containernetworking/plugins/archive/v${pkgver}.tar.gz")
sha512sums=('4b3c1901154eb1af86dc35888fda7b7666ee88d2cf728fb09182df5385d32b747de34c5c01598e1f37ae1e3497dbf5af2bc6ad6f737e683ccfccf9c1860cf6dc')

build() {
  cd "${srcdir}/plugins-${pkgver}"
  ./build.sh
}

package() {
  cd "${srcdir}/plugins-${pkgver}"
  mkdir -p "${pkgdir}/opt/cni/"
  cp -dr --no-preserve=ownership bin "${pkgdir}/opt/cni/"

  mkdir -p ${pkgdir}/usr/share/licenses/${pkgname}
  install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}

Um Container-Networking zu ermöglichen muss im Kernel das IP-Forwarding aktiviert werden. Am besten wird die Konfiguration dauerhaft vorgenommen, indem eine entsprechende sysctl Konfiguration vorgenommen wird.

Konfiguration von IP Forwarding in /etc/sysctl.d/30-ipforward.conf
net.ipv4.ip_forward=1

Damit ist eine grundlegende Container-Laufzeitumgebung vorbereitet. Als nächstes muss noch Kubernetes zur Verwendung von CRI-O konfiguriert werden.

kubelet Konfiguration für CRI-O

Eine Standardinstallation von kubelet als systemd-Dienst wird diesen mit einer Abhängigkeit auf den Docker Daemon konfigurieren. Da nun CRI-O zum Einsatz kommt, muss die systemd-Unit angepasst werden und den crio.service statt Docker deklarieren.

systemd-Unit für kubelet /usr/lib/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://kubernetes.io/docs/concepts/overview/components/#kubelet https://kubernetes.io/docs/reference/generated/kubelet
After=crio.service
Requires=crio.service

[Service]
WorkingDirectory=/var/lib/kubelet
EnvironmentFile=-/etc/kubernetes/config
EnvironmentFile=-/etc/kubernetes/kubelet
ExecStart=/usr/bin/kubelet \
            $KUBE_LOGTOSTDERR \
            $KUBE_LOG_LEVEL \
            $KUBELET_KUBECONFIG \
            $KUBELET_ADDRESS \
            $KUBELET_PORT \
            $KUBELET_HOSTNAME \
            $KUBE_ALLOW_PRIV \
            $KUBELET_ARGS
Restart=always
KillMode=process
RestartSec=60s

[Install]
WantedBy=multi-user.target

Die folgenden Einstellungen für kubelet werden in der /etc/kubernetes/kubelet Datei vorgenommen:

  • Auswahl von CRI-O als Runtime für Container

  • Auswahl von systemd als cgroup Treiber, damit die Namespaces von CRI-O und kubelet zusammen passen

  • Pfad für statische Pods, die kubeadm erzeugt, um die Kubernetes Control-Plane zu booten

  • Angabe der - später - durch kubeadm erzeugten Datei kubelet.conf als weitere Konfigurationsdatei

kubelet Konfiguration in /etc/kubernetes/kubelet
KUBELET_ARGS="--cluster-domain=cluster.local --cluster-dns=10.96.0.10 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd  --fail-swap-on=false  --network-plugin=kubenet --container-runtime=remote --container-runtime-endpoint=unix:///var/run/crio/crio.sock"
KUBELET_KUBECONFIG="--kubeconfig=/etc/kubernetes/kubelet.conf"
KUBELET_HOSTNAME=""

Zusätzlich werden noch Parameter in der /etc/kubernetes/config gesetzt: Für den kube-proxy werden privilegierte Container benötigt, sodass diese erlaubt werden müssen. Außerdem wird die Adresse des kube-apiserver erst einmal leer gelassen - die von kubeadm später erzeugte Datei wird die korrekte URL enthalten.

kubelet Konfiguration in /etc/kubernetes/config
KUBE_ALLOW_PRIV="--allow-privileged=true"
KUBE_MASTER=""

Anschließend können die Konfigdateien von systemd neu eingelesen und der kubelet Dienst aktiviert werden. Der Start des kubelet Dienstes erfolgt erst später, wenn durch kubeadm auch die kubelet.conf Datei erzeugt wurde. Bis dahin werden Startversuche fehlschlagen, da die Datei noch nicht existiert.

$ sudo systemctl daemon-reload
$ sudo systemctl enable kubelet.service

Cluster Setup mit CRI-O und kubeadm

Bei der Einrichtung eines Kubernetes Cluster mit CRI-O Containern und kubeadm muss diesem ebenfalls die Verwendung von CRI-O konfiguriert werden. Dazu muss der Pfad zum CRI-Socket angegeben werden, dieser ist standardmäßig auf dockershim konfiguriert, dass bei CRI-O nicht zum Einsatz kommt.

$ sudo kubeadm init --pod-network-cidr 10.244.0.0/24 --ignore-preflight-errors Swap --cri-socket=/var/run/crio/crio.sock

Sollte etwas schief gehen, ist zu beachten, dass bei einem kubeadm reset auch hier der CRI-Socket zu spezifizieren ist, damit alle Container korrekt gelöscht werden.

$ sudo kubeadm reset --cri-socket=/var/run/crio/crio.sock

Während die Container durch kubelet gestartet werden, kann bereits mittels crictl der Status beobachtet werden:

$ sudo crictl pods
POD ID         CREATED        STATE   NAME             NAMESPACE    ATTEMPT
92944837d1bbb  4 seconds ago  Ready   kube-scheduler   kube-system  0
39e8d6401df44  4 seconds ago  Ready   kube-controller  kube-system  0
37b8cb3450a84  4 seconds ago  Ready   kube-apiserver   kube-system  0
d753b24712a99  4 seconds ago  Ready   etcd             kube-system  0

Im nächsten Beitrag geht es um die Einrichtung von Workernodes mit diesem Setup: Kubernetes CRI-O Worker.

Aktualisierte Pakete werden hier beschrieben: Kubernetes 1.13.




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.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Zur Desktop Version des Artikels