【Raspberry Pi】Kubernetes 環境の構築

はじめに

Raspberry Pi OS の 64bit 版に Lite バージョンが出ていたことに気づいたので、32bit 版で構成していた Raspberry Pi 4 Model B での Kubernetes 環境を新たに64bit 版で再構築してみました。

ちなみに、インストール手順については以下のページを参考にさせていただいています。

 

準備

SDカード書き込み

Raspberry Pi 公式の Raspberry Pi Imager を使用して Raspberry Pi OS (64bit 版) Lite をSDカードに書き込みます。Pi 4 が 4台あるので SD カードの書き込みも 4 回実施。

SSH有効化

 Pi 4 にモニターやキーボードを接続していないため、予め SSH を有効にする必要があります。SD カードに OS イメージを書き込んだ後、SD 上の boot パーティションに「ssh」という名前の空ファイルを置くことで自動的に ssh でのログインが有効になります。

DHCP 割り当て設定

ネットワークへの接続には有線 LAN を使い、IP アドレスの割り当ては DHCP で行います。各ボードの MAC アドレスは既に DHCP サーバに登録してあるので、固定 IP を割り当てることができるようにしています。

ちなみに IP アドレスとホスト名の対応は以下のような感じです。

192.168.0.21	pi4b01
192.168.0.22	pi4b02
192.168.0.23	pi4b03
192.168.0.24	pi4b04

 

 Raspberry Pi を設定する

初期設定

各ボードで raspi-config を使って、このへんの初期設定を行います。

  • パスワード変更
  • ホストネーム変更
  • ロケール変更
  • TimeZone 設定

/etc /hosts ファイルも編集しておきます。

  • 127.0.1.1 の行を削除
  • 各ボードに割り当てた IP アドレスの設定を追加する
192.168.0.21	pi4b01
192.168.0.22	pi4b02
192.168.0.23	pi4b03
192.168.0.24	pi4b04

Docker をインストールする

sudo apt-get update
sudo apt-get -y upgrade

sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common gnupg2
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -

echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
        $(lsb_release -cs) stable" | \
        sudo tee /etc/apt/sources.list.d/docker.list

sudo apt-get update
sudo apt-get install docker-ce

 

sudo無しでdockerを利用できるようにするには「 sudo usermod -aG docker $USER」で自分を docker グループに追加します。 こうすることで次回のログインから docker コマンドが su なしで利用可能になります。

 Kubernetes をインストールする

iptables の設定

 Kubernetes 用の 設定が必要そうなので以下の作業をしておきます。

cat << EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

 

Cgroup の memory グループを有効にする

cat /proc/cgroups をすると memory グループが無効になっているので、 /boot/cmdline.txt の行の末尾に 以下の設定を追加します。追加する際は改行を入れずに一行にする必要があります。

cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory

 この設定が有効になるように、ここで reboot します。

kubeadm, kubelete, kubectl をインストールする
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
 swap を停止する

swap があると kubernetes の設定ができないので swap は無効にしておきます。

sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove
sudo systemctl stop  dphys-swapfile
sudo systemctl disable  dphys-swapfile

ここまでは全ボード共通で行う作業です。

Master ノードの設定

 ここでは pi4b01 を Master ノードとして設定します。Pod ネットワークには Flannel を使う例が多いようなので、ここでも Flannel を使いました。また、ロードバランサーは MetalLB を使用します。

  • 初期化する
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
pi@pi4b01:~ $ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
W1003 20:59:40.066256    7995 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.19.2
[preflight] Running pre-flight checks
        [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
        [WARNING SystemVerification]: missing optional cgroups: hugetlb
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local pi4b01] and IPs [10.96.0.1 192.168.0.21]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost pi4b01] and IPs [192.168.0.21 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost pi4b01] and IPs [192.168.0.21 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 37.511892 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node pi4b01 as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node pi4b01 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: dznswr.altmxn5ip8qwbpgf
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.0.21:6443 --token dznswr.altmxn5ip8qwbpgf \
    --discovery-token-ca-cert-hash sha256:c12a398a8acb4d2069b367980a0db018b2a4454a4a3a7e5d0544ac9d13eb269e 

メッセージに従って以下のコマンドを入力します。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
  • Flannel を導入する。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
  • MetalLB を導入する
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/metallb.yaml
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

適当なディレクトリに以下の内容で config.yaml というファイルを作成します。 address の部分は DHCP と被らない範囲をテキトーに設定しています。

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.0.60-192.168.0.69
kubectl apply -f config.yaml

 

Worker ノードの設定

Master ノードを初期化した際のログに書かれているコマンドを各 Worker ノードで実行します。

sudo kubeadm join 192.168.0.21:6443 --token dznswr.altmxn5ip8qwbpgf     --discovery-token-ca-cert-hash sha256:c12a398a8acb4d2069b367980a0db018b2a4454a4a3a7e5d0544ac9d13eb269e

このコマンドを実行後、Master ノードで各ノードの状態を見ることができます。

kubectl get nodes

おわりに

 今回はOSからの再インストールということで Rasberry Pi OS Lite の 64 bit 版を使ってみましたが、32 bit 版の時と何ら変わることなくOSインストールや Kubernetes の設定ができました。このまま 64bit 版の環境で使ってみようと思います。