Since ARMv6 is not officially supported by Kubernetes, the binaries need to be built from the source in order to get them properly to work. They are all written in Go which facilitates the process of cross-compiling. However, I found it even easier using qemu to to run ARM native golang docker images to compile.
It's not required, but if you want to follow that path, then install qemu-system-arm
, qemu-user-static
and binfmt-support
.
Use docker to build the binaries, although it’s not necessary, it removes the clutter from my local environment, as I don’t normally use Go.
- arm32v7/golang for armhf - Pi 3
- arm32v5/golang for armel - Pi Zero
git clone https://github.com/kubernetes/kubernetes.git
git checkout release-1.18
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/golang:1.15.5-buster bash
root@637ae3b798bc:/usr/src/myapp# export GOOS="linux"
root@637ae3b798bc:/usr/src/myapp# export GOARCH="arm"
root@637ae3b798bc:/usr/src/myapp# export CGO_ENABLED=0
root@637ae3b798bc:/usr/src/myapp# export GOARM=6
root@637ae3b798bc:/usr/src/myapp# export GOFLAGS=""
root@637ae3b798bc:/usr/src/myapp# export LDFLAGS='-d -s -w -linkmode=external -extldflags="-static" -static -static-libgcc'
root@e0954fe5228c:/usr/src/myapp# apt update
root@e0954fe5228c:/usr/src/myapp# apt install rsync
root@637ae3b798bc:/usr/src/myapp# make WHAT=cmd/kube-scheduler
root@637ae3b798bc:/usr/src/myapp# make WHAT=cmd/kube-controller-manager
root@637ae3b798bc:/usr/src/myapp# make WHAT=cmd/kube-apiserver
root@637ae3b798bc:/usr/src/myapp# make WHAT=cmd/kubectl
This process can take a while to complete, be patient. Once it's finished, copy the binaries to master to then transfer to worker nodes.
scp _output/local/bin/linux/arm/kube* [email protected]:~/bin
Note - kubectl can be reused for worker nodes as well, it worked for me.
Before building kubelet, I found numerous issues with a missing cgroup (cpuset) in the raspberry pi zero. I’m not entirely sure why this is a requirement and I removed it from the code. I published my findings in the raspberry pi forum.
To avoid having those issues I removed the validation as follows:
File: pkg/kubelet/cm/container_manager_linux.go
- expectedCgroups := sets.NewString("cpu", "cpuacct", "cpuset", "memory")
+ expectedCgroups := sets.NewString("cpu", "cpuacct", "memory")
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v5/golang:1.15.5-buster bash
root@e3b475b2f53e:/usr/src/myapp# export GOOS="linux"
root@e3b475b2f53e:/usr/src/myapp# export GOARCH="arm"
root@e3b475b2f53e:/usr/src/myapp# export CGO_ENABLED=0
root@e3b475b2f53e:/usr/src/myapp# export GOARM=6
root@e3b475b2f53e:/usr/src/myapp# export GOFLAGS=""
root@e3b475b2f53e:/usr/src/myapp# export LDFLAGS='-d -s -w -linkmode=external -extldflags="-static" -static -static-libgcc'
root@e3b475b2f53e:/usr/src/myapp# apt update
root@e3b475b2f53e:/usr/src/myapp# apt install rsync
root@e3b475b2f53e:/usr/src/myapp# make WHAT=cmd/kubelet
root@e3b475b2f53e:/usr/src/myapp# make WHAT=cmd/kube-proxy
Copy the binaries to master to then transfer to worker nodes
scp _output/local/bin/linux/arm/kubelet [email protected]:~/bin
scp _output/local/bin/linux/arm/kube-proxy [email protected]:~/bin
We are not going to use all the networking plugins, but to make our life easier, build them all and distribute them to the nodes anyway.
git clone https://github.com/containernetworking/plugins.git
git checkout v0.8.7
sed -i 's/\$GO\ build -o \"\${PWD}\/bin\/\$plugin\" \"\$\@\"/\$GO\ build -o \"\$\{PWD\}\/bin\/\$plugin\" \"\$\@\"\ \-ldflags\=\"\-d\ \-s\ \-w\"/' build_linux.sh
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v5/golang:1.15.5-buster bash
root@042cbfe7a200:/usr/src/myapp# ./build_linux.sh
scp bin/* [email protected]:~/plugins/
runc
is the actual low level container runtime to launches the child processes.
git clone https://github.com/opencontainers/runc.git
cd runc
git checkout v1.0.0-rc92
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v5/golang:1.15.5-buster bash
root@cda70ed7dfb3:/usr/src/myapp# apt update
root@cda70ed7dfb3:/usr/src/myapp# apt install libseccomp-dev
root@cda70ed7dfb3:/usr/src/myapp# make static
root@cda70ed7dfb3:/usr/src/myapp# ./runc --version
runc version 1.0.0-rc92
commit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
spec: 1.0.2-dev
root@cda70ed7dfb3:/usr/src/myapp# ./contrib/cmd/recvtty/recvtty --version
recvtty version 1.0.0-rc92
commit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
scp ./runc ./contrib/cmd/recvtty/recvtty [email protected]:~/bin/
containerd
is the daemon that controls containers at runtime.
git clone https://github.com/containerd/containerd.git
cd containerd
git checkout release/1.4
docker run --rm -it -v "$PWD":/go/src/github.com/containerd/containerd -w /go/src/github.com/containerd/containerd arm32v5/golang:1.15.5-buster bash
root@809ff752ed2d:/usr/src/myapp# apt update
root@809ff752ed2d:/usr/src/myapp# apt install btrfs-progs libbtrfs-dev
root@809ff752ed2d:/usr/src/myapp# apt install protobuf-compiler
root@809ff752ed2d:/usr/src/myapp# make
scp bin/* [email protected]:~/bin/
cri-tools
provides a communication platform with the current CRI compliant
container runtime.
git clone https://github.com/kubernetes-sigs/cri-tools.git
cd cri-tools
git checkout v1.18.0
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/golang:1.15.5-buster bash
root@da0beb1cf478:/usr/src/myapp# make
root@da0beb1cf478:/usr/src/myapp# _output/crictl --version
crictl version 1.18.0
scp _output/* [email protected]:~/bin/
etcd
is the main database that maintains the cluster state.
git clone https://github.com/etcd-io/etcd.git
cd etcd
git checkout release-3.4
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/golang:1.15.5-buster bash
root@3a6d3a16f556:/usr/src/myapp# ./build
root@3a6d3a16f556:/usr/src/myapp# ls -l bin/
total 42624
-rwxr-xr-x 1 root root 24999558 Nov 26 11:22 etcd
-rwxr-xr-x 1 root root 18641042 Nov 26 11:24 etcdctl
scp ./bin/* [email protected]:~/bin
The environment variable ETCD_UNSUPPORTED_ARCH=arm needs setting, otherwise we get an explicit error message. Inside master node $HOME directory.
$ ETCD_UNSUPPORTED_ARCH=arm bin/etcd --version
running etcd on unsupported architecture "arm" since ETCD_UNSUPPORTED_ARCH is set
etcd Version: 3.4.13
Git SHA: eb0fb0e79
Go Version: go1.15.5
Go OS/Arch: linux/arm
$ bin/etcdctl version
etcdctl version: 3.4.13
API version: 3.4
This step is more for the sake of completeness of building everything from the source, in case you want to create your own version of the pause
container which is a fundamental pillar of the pod structure.
docker run --rm -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v5/golang:1.15.5-buster bash
root@637ae3b798bc:/usr/src/myapp# cd build/pause/
root@637ae3b798bc:/usr/src/myapp/build/pause# gcc -Os -Wall -Werror -static -s -g -fPIE -fPIC -o pause pause.c
scp build/pause/pause [email protected]:~/bin