kubernetes(K8S) Worker nodeをRaspberry piで作る方法の話

今回は、kubernetes(略 K8S)においてWorker nodeをRaspberry piに作成する方法をメモしておきます…

我が家では8台のRaspberry piにて構築していますが、毎度メモ帳に書いている内容をぽちぽち書いています。
が、そのメモ帳を無くすと悲しいのでここにもメモを残します。
ついでに書きながら内容を再確認させています

ネット上ではさまざまな構成方法がありますが、なぜか我が環境では動かなかったので試行錯誤しました。
その結果のメモです…

今回のターゲットはworker node 3台目、マシン名 k8s-worker3です。
利用した環境
Raspberry pi : Raspberry Pi 4 Model Bだったはず (メモリ : 4GB)
OS : Raspberry pi OS 64bit . (Bulleyes)

早速作業します。

SDカードを作る

はじめに、Raspberry piのOSを書いたSDカードを作成します。

SDカードを作るには様々な方法がありますが今回はmacOSのRaspberry pi Imagerを使って作成します

ImagerのOSを押下して、OSを選択します。
今回は「Raspberry pi OS LITE (64-bit)」を利用します。

昔は書き込み後にごにょごにょ設定を変えていましたが、
Raspberry pi Imger v1.7から書き込み時に設定を入れることが可能になりました。
歯車にて設定ができますのでそこで設定します。

設定できる内容は以下の内容をです。

  • ホスト名
  • SSHを有効にする
  • ユーザ名とパスワードを設定する
  • Wifiを設定する
  • ロケールを設定する

SSHの有効設定は以降の作業で必ず必要ですので有効にして作成してください。

ユーザ名は必ず設定しましょう。
デフォルトユーザのpiは非推奨です。
やめましょうねw
指定しないとユーザ作成の要求がきたかもしれません。(未確認)

デフォルトの “pi” ユーザーを削除し、代わりに新しくフラッシュした Raspberry Pi OS イメージを最初に起動したときにユーザーを作成するようにしました。

https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/

本体に接続して電源を入れる

ImagerにてSDカードを作成が完了すると
そのSDカードを挿してRaspberry piを起動させます!

起動を行うとSSHで作業をおこないます。
IPアドレスをまず取得しましょう。

IPアドレスの取得は、本体にKVMを付けて確認でも、DHCPサーバの払い出し一覧からとりだしてもOKです。好きな方法で取得しましょうw

IPアドレスが取得できましたら、SSHにて入ります。

ちゃんとOSが入っていることを確認します

wataru@k8s-worker3:~ $ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

おまじない的に最新にします

wataru@k8s-worker3:~ $ sudo apt-get update
wataru@k8s-worker3:~ $ sudo apt-get upgrade

ネットワークの設定を行う

ネットワークの設定って標準のnetplanを使えば?と思いでしょうがSystemd-networkを使います。
なぜかというと、Raspberry piにてNodeが上がらない不具合があったためです。
この不具合解消がnetplanではなくSystemdで指定すれば解決できます…
他の方法知りたいです

作業は 古いネットワーク設定(netplan)周りをざっくり削除して、Systemd-networkd周りをインストールすればOKです。
参考にしたサイトはこちらです。 https://raspberrypi.stackexchange.com/questions/108592/use-systemd-networkd-for-general-networking

古いネットワーク設定周りを削除する

wataru@k8s-worker3:~ $ sudo -i
root@k8s-worker3:~ # systemctl daemon-reload
root@k8s-worker3:~ # systemctl disable --now ifupdown dhcpcd dhcpcd5 isc-dhcp-client isc-dhcp-common rsyslog
root@k8s-worker3:~ # apt --autoremove purge ifupdown dhcpcd dhcpcd5 isc-dhcp-client isc-dhcp-common rsyslog
root@k8s-worker3:~ # rm -r /etc/network /etc/dhcp

systemd-networkdを設定・有効にします

wataru@k8s-worker3:~ $ sudo -i
root@k8s-worker3:~ # systemctl disable --now avahi-daemon libnss-mdns
root@k8s-worker3:~ # apt --autoremove purge avahi-daemon
root@k8s-worker3:~ # apt install libnss-resolve
root@k8s-worker3:~ # ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
root@k8s-worker3:~ # apt-mark hold avahi-daemon dhcpcd dhcpcd5 ifupdown isc-dhcp-client isc-dhcp-common libnss-mdns openresolv raspberrypi-net-mods rsyslog
root@k8s-worker3:~ # systemctl enable systemd-networkd.service systemd-resolved.service

有線LANの設定を書きます

パッケージを入れれば次に有線LANの設定を書きます

wataru@k8s-worker3:~ # touch /etc/systemd/network/04-wired.network
wataru@k8s-worker3:~ # vi /etc/systemd/network/04-wired.network
[Match]
Name=eth0

[Network]
Address=192.168.1.224/24
Gateway=192.168.1.254
DNS=192.168.1.254
wataru@k8s-worker3:~ # systemctl enable systemd-resolved.service

有線LANの設定を変更しましたので反映…
略、SSHなのでIPが変わるとアクセスできなくなるので、とりあえず再起動で対応します。

これで新しいIPアドレスにてSSHで入ればOKです

とりあえず不具合原因のファイルがあることを確認します

wataru@k8s-worker3:~ $ ls /run/systemd/resolve/resolv.conf
/run/systemd/resolve/resolv.conf

これでRaspberry piのネットワーク周りを設定しました。

K8sインストール前の事前設定

はじめに、K8sをインストールする前にRaspberry piの設定を変更します。
Swapをoffにしてcgroupのメモリをアレします。

Swapをoffにする

Raspberry piのK8sではSwapをonにすると動きません。
なのでSwapをOffにします。

wataru@k8s-worker3:~ $ sudo dphys-swapfile swapoff
wataru@k8s-worker3:~ $ sudo systemctl stop dphys-swapfile
wataru@k8s-worker3:~ $ sudo systemctl disable dphys-swapfile

cgroupsのメモリをアレする

wataru@k8s-worker3:~ $ sudo vi /boot/cmdline.txt

cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory

上をcmdlineの末尾に追記します。

再起動します。

ちゃんと反映されていることを確認
※ 確認ポイント : 末尾が1

wataru@k8s-worker3:~ $ cat /proc/cgroups | grep memory
memory	0	66	1

Dockerのインストール

解説略! Dockerをインストールします。
公式のスクリプトで入ります…

wataru@k8s-worker3:~ $ curl -sSL https://get.docker.com | sh
...
Server: Docker Engine - Community
 Engine:
  Version:          20.10.14
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       87a90dc
  Built:            Thu Mar 24 01:45:44 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.5.11
  GitCommit:        3df54a852345ae127d1fa3092b95168e4a88e2f8
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

wataru@k8s-worker3:~ $ sudo usermod -aG docker wataru

kubernetesのインストール

解説略! リポジトリ追加して入れれば入ります

wataru@k8s-worker3:~ $ sudo apt-get update && sudo apt-get install -y apt-transport-https curl
wataru@k8s-worker3:~ $ sudo curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

K8sのリポジトリを追加する

wataru@k8s-worker3:~ $ sudo vi /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main

リポジトリを更新する

wataru@k8s-worker3:~ $ sudo apt-get update

一式をインストールする

wataru@k8s-worker3:~ $ sudo apt-get install -y kubelet kubeadm kubectl
wataru@k8s-worker3:~ $ sudo apt-mark hold kubelet kubeadm kubectl

kubernetes(k8s)に参加する

一式インストールが終えたので今回のメインディッシュ K8sに参加します。

worker nodeの追加前にmaster nodeの状態を確認します

wataru@k8s-master:~ $ kubectl get node
NAME          STATUS   ROLES                  AGE    VERSION
k8s-master    Ready    control-plane,master   126m   v1.23.6
k8s-worker1   Ready    <none>                 123m   v1.23.6
k8s-worker2   Ready    <none>                 88m    v1.23.6

すでに作業済みのworker1 , worker2だけが追加されています…

参加!join!

本題である参加を発行します!

wataru@k8s-worker3:~ $ sudo kubeadm join 192.168.1.221:6443 --token ypnxoi.z03zcpkv51wj8udf         --discovery-token-ca-cert-hash sha256:20fbb36fde703aaba4d823e0a506c3866fe66f2c818c5685c52034bdc2c908ea 
...
This node has joined the cluster:

tokenを忘れた、昔すぎて覚えていない場合は再生成が必要になります。

こちらを参考ください : Kubernetes(k8s)での新しいnodeの追加方法の話 2022年3月24日

master nodeにて参加を確認する

worker nodeにてjoinをコマンド実行しましたのでmaster nodeにて確認します

wataru@k8s-master:~ $ kubectl get node
NAME          STATUS   ROLES                  AGE    VERSION
k8s-master    Ready    control-plane,master   128m   v1.23.6
k8s-worker1   Ready    <none>                 125m   v1.23.6
k8s-worker2   Ready    <none>                 90m    v1.23.6
k8s-worker3   Ready    <none>                 41s    v1.23.6

今回作業したk8s-worker3が追加されることを確認しました。
早ければNoReadyなのでしばらくたってから再取得ください

参加できました。パチパチ…

動作を確認する

worker nodeがちゃんと動いていることを確認します。

手順はこちら : https://kubernetes.io/ja/docs/tasks/run-application/run-stateless-application-deployment/

手順がどうのは無視してnginxを4個動かせば3台のWorkerなので1台はworker3にて動くでしょう!
手順を全否定に近いねw
早速動かす

 kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml

次に動いているpodを確認する!

wataru@k8s-master:~ $ kubectl get pod -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
nginx-deployment-9456bbbf9-2kl9s   1/1     Running   0          69s   10.244.3.5   k8s-worker3   <none>           <none>
nginx-deployment-9456bbbf9-54jjc   1/1     Running   0          69s   10.244.1.5   k8s-worker1   <none>           <none>
nginx-deployment-9456bbbf9-bzqnr   1/1     Running   0          69s   10.244.2.6   k8s-worker2   <none>           <none>
nginx-deployment-9456bbbf9-mrwfg   1/1     Running   0          69s   10.244.2.7   k8s-worker2   <none>           <none>

はい!k8s-worker3がRunningです。

個別にnginxの動作を確認しますと

wataru@k8s-master:~ $ curl 10.244.3.5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

こいつ、動いているぞ!

動作を確認できましたので、お片付けはちゃんとしましょう

 kubectl delete -f https://k8s.io/examples/application/deployment-scale.yaml

終いに

今回、Raspberry piのk8s worker nodeを追加する方法をメモしました。

下の不具合が原因でかなり試行錯誤しました。

次はRaspberry piのk8s master nodeを作成する方法かな…

Raspberry piのmaster nodeがReadyにならない不具合

worker nodeを参加させることができますが、NoReadyのまま上がらない不具合がありました。

wataru@k8s-master:~$ kubectl get node
NAME        STATUS     ROLES                  AGE   VERSION
k8s-master      Ready      control-plane,master   77d   v1.23.6
k8s-worker0   NotReady   <none>                 36d   v1.23.6

Nodeの状態を確認すると…

wataru@k8s-master:~$ kubectl describe node k8s-worker0
... 略 ...
Events:
  Type     Reason                                            Age                From        Message
  ----     ------                                            ----               ----        -------
  Warning  listen tcp4 :31242: bind: address already in use  0s (x1 over 30s)   kube-proxy  can't open port "nodePort for default/hello-minikube" (:31242/tcp4), skipping it
  Normal   Starting                                          31s                kube-proxy  
  Normal   NodeHasSufficientMemory                           15m (x2 over 15m)  kubelet     Node k8s-worker0 status is now: NodeHasSufficientMemory
  Normal   NodeHasNoDiskPressure                             15m (x2 over 15m)  kubelet     Node k8s-worker0 status is now: NodeHasNoDiskPressure
  Normal   NodeHasSufficientPID                              15m (x2 over 15m)  kubelet     Node k8s-worker0 status is now: NodeHasSufficientPID
  Normal   Starting                                          15m                kubelet     Starting kubelet.
  Normal   NodeHasSufficientMemory                           15m                kubelet     Node k8s-worker0 status is now: NodeHasSufficientMemory
  Normal   NodeHasNoDiskPressure                             15m                kubelet     Node k8s-worker0 status is now: NodeHasNoDiskPressure
  Normal   NodeHasSufficientPID                              15m                kubelet     Node k8s-worker0 status is now: NodeHasSufficientPID
  Normal   NodeAllocatableEnforced                           15m                kubelet     Updated Node Allocatable limit across pods
  Normal   Starting                                          15m                kubelet     Starting kubelet.
  Warning  CheckLimitsForResolvConf                          15m                kubelet     open /run/systemd/resolve/resolv.conf: no such file or directory

らしいです…

確認すると…

pi@k8s-worker0:~ $ ls /run/systemd/resolve/resolv.conf
ls: cannot access '/run/systemd/resolve/resolv.conf': No such file or directory

ないです…
そもそも、resolveディレクトリからありません…

とりあえず、強制的にファイルを作りました

pi@k8s-worker0:~ $ sudo mkdir /run/systemd/resolve
pi@k8s-worker0:~ $ sudo ln -s /etc/resolv.conf /run/systemd/resolve/resolv.conf 
pi@k8s-worker0:~ $ sudo systemctl restart kubelet

すると… ちゃんとReadyになりました!

wataru@k8s-master:~$ kubectl get node
NAME        STATUS   ROLES                  AGE   VERSION
gitlab      Ready    control-plane,master   77d   v1.23.6
k8s-node0   Ready    <none>                 36d   v1.23.6

解決!にはなりません…

再起動するとresolve/resolv.confは無くなります…

それはダメなのでちゃんとsystemdから作るとこの問題は解消できます。