Raspberry Pi クラスター

Raspberry Pi を集めて、Kubernetes クラスターを作った。

コンテナランタイムは cri-o を、CNI は Flannel を利用した。

後述の参考のコピペがほとんど。

sudo がついてたりついてなかったりする。

以下の Ansible を見ればわかる。そのうち変わってるかも。

https://github.com/kamojiro/study/tree/main/raspberry_pi_cluster/ansible

基本的にはこれを書き下したものになるはず。

基本情報

ハードウェア

ソフトウェア

  • OS

- Ubuntu 22.04.1 LTS

IP アドレスとか

raspberry pi host role IP address MAC address disk
4B k8s-master master 192.168.10.101 e4:5f:01:e2:59:e4
k8s-worker1 worker 192.168.10.102 e4:5f:01:e2:59:14 128GB
k8s-worker2 worker 192.168.10.103 e4:5f:01:e2:5a:1e

rpi-imager

これを見ながらいい感じにやる。公開鍵も登録できて楽。

Raspberry Pi で【リアル☆Kubernetes】を作る!!

ネットワーク関連の設定

やらなくていいかも(よくわからずにやった)

/etc/netplan/99-network.yaml

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: false
      dhcp6: false
      addresses:
        - 192.168.1.101/24 # ラズパイ毎でIPを変更してください。(末尾がそれぞれ101, 102, 103になります。)
      routes: # 自宅のルーターからゲートウェイを調べて下さい。ここを間違えるとラズパイはネットに繋がらなくなります…
        - to: default
          via: 192.168.10.1
      nameservers:
        addresses:
          - 192.168.10.1
sudo netplan apply

ホスト名の変更

@raspberry_pi

ラズパイのOSインストール時に指定したので以下のコマンドは不要

sudo hostnamectl set-hostname <hostname>
hostname

DNS的なののために、etc/hosts に追記

192.168.1.101   k8s-master kube-master.kamoj.com
192.168.1.102   k8s-worker1 kube-master1.kamoj.com
192.168.1.103   k8s-worker2 kube-worker2.kamoj.com

IPv6 の無効化

etc/sysctl.conf の最後に追記

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

timezone, keymap の変更

今回は OS インストール時に設定したので不要

# タイムゾーンの変更
sudo timedatectl set-timezone Asia/Tokyo

# keymapの変更
sudo localectl set-keymap jp106

ルーターから固定IPアドレスを設定する

NECルーターなら以下のように固定 IP を割り当てることができる

ssh

今回は OS インストール時に設定したので不要

iptablesがブリッジを通過するトラフィックを処理できるようにする

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

cri-o

カーネルパラメーターの設定

sudo modprobe overlay

# 必要なカーネルパラメータの設定をします。これらの設定値は再起動後も永続化されます。
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system

準備

sudo apt install -y curl gnupg2 libseccomp2

cri-o のインストール

OS=xUbuntu_22.04
VERSION=1.25
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list

mkdir -p /usr/share/keyrings

curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -

apt update
apt install -y cri-o
apt install -y cri-o-runc

cri-o と cri-o-runc を並べてインストールしようと失敗する(?)

```bash
sudo systemctl daemon-reload
sudo systemctl start crio
sudo systemctl enable crio
systemctl status crio

コントロールプレーンノードの kubelet によって使用される cgroup ドライバーの設定

CRI の場合は、/etc/default/kubelet

KUBELET_EXTRA_ARGS=--cgroup-driver=systemd
sudo systemctl daemon-reload
sudo systemctl restart kubelet

おまじない

再起動後とか、うまくいかないときはこれを再実行してみる。

sudo modprobe br_netfilter
echo '1' > /proc/sys/net/ipv4/ip_forward

Kubernetes

kubeadmのインストール | Kubernetes

requirements

  • OS: Ubuntu 16.04+
  • memory >= 2GB per machine
  • core >= 2 per machine
  • クラスター内のすべてのマシン間で通信可能なネットワーク
  • ユニークなhostname、MACアドレス、とproduct_uuid
  • port: private なのでOK
  • swap: off

VXLAN モジュールのインストール

Flannel で使うので。

sudo apt install -y linux-modules-extra-raspi

Flannel のデプロイ前までに再起動が必要。

cgroup で memory の有効化(よくわからない)

/boot/firmware/cmdline.txt の末尾に cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory を追記

おまじない

echo '1' > /proc/sys/net/ipv4/ip_forward

swap の無効化

sudo swapoff -a

iptables が nftables バックエンドを使用しないようにする

sudo apt install -y iptables arptables ebtables
# レガシーバイナリがインストールされていることを確認してください
sudo apt install -y iptables arptables ebtables

# レガシーバージョンに切り替えてください。
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy

準備

sudo apt install -y apt-transport-https curl

kubeadm、kubelet、kubectlのインストール

sudo apt update && sudo apt 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 update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Kubernetes クラスターの作成

コントロールプレーンの設定@master

sudo kubeadm init --apiserver-advertise-address=192.168.10.101 --pod-network-cidr=10.244.0.0/16
  • apiserver-advertise-address
    • このオプションを利用して明示的にAPIサーバーのadvertise addressを設定します。
    • 明示的に指定しない場合はデフォルトゲートウェ 佐野なつイに関連付けられたネットワークインターフェースを使用して設定されます。
  • pod-network-cidr
    • Flannelを使用する場合、こちらを指定する必要があります。
    • Flannelはノード間をつなぐネットワークに仮想的なトンネルを構成することで、クラスター内のPod同士の通信を実現しています。
    • /16と広めに設定します(GitHub - flannel-io/flannel)。

初期化後、kubeadm join 192.168.1.101:6443 --token ...という出力が出たら、どこかのテキストエディタにコピーしておきます。
このコマンドはワーカーノードを追加する際に利用します。

kubectl の設定

# ホームディレクトリに.kubeディレクトリを作成
mkdir -p ~/.kube
# Kubernetesのadmin.confを.kubeディレクトリのconfigファイルへコピー
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
# configファイルの所有者がrootになっているのでk8suserへ変更
sudo chown $(id -u):$(id -g) ~/.kube/config
# .bashrcへ環境変数の追加
echo 'KUBECONFIG=$HOME/.kube/config' >> ~/.bashrc
# コマンドの入力補完を設定
echo "source <(kubectl completion bash)" >> $HOME/.bashrc
# 変更を適用
source ~/.bashrc

Flannel のデプロイ@master

Flannel をデプロイするまでは、coredns は pending 状態になっている。

以下は、やってなかったらやっておく

sudo apt install -y linux-modules-extra-raspi
sudo reboot
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl get pods -n kube-flannel

MetalLB のデプロイ

IaaS だと、type: LoadBalancer で IP アドレスを払い出してくれる。
そんな感じで、IP アドレスの自動割当をやってくる。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
# ...

kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
kubectl get pod -n metallb-system

ワーカーノードの追加

modprobe br_netfilter
sudo kubeadm join 192.168.1.101:6443 --token 3u2z7v.qx81p3azvu15ftzw --discovery-token-ca-cert-hash sha256:0e731a79605ba03cfbc823e86e8b81b2fcdcf7f1887c1d2d86239ed87fff8d04
kubectl get nodes
kubectl label node k8s-worker1 node-role.kubernetes.io/worker=worker
kubectl label node k8s-worker2 node-role.kubernetes.io/worker=worker
kubectl get nodes

確認

$ kubectl get nodes
NAME          STATUS   ROLES           AGE   VERSION
k8s-master    Ready    control-plane   46h   v1.26.0
k8s-worker1   Ready    worker          33m   v1.26.0
k8s-worker2   Ready    worker          19m   v1.26.0
$ kubectl get pods --all-namespaces 
NAMESPACE        NAME                                 READY   STATUS    RESTARTS       AGE
kube-flannel     kube-flannel-ds-dm67n                1/1     Running   0              33m
kube-flannel     kube-flannel-ds-hj2zl                1/1     Running   516            45h
kube-flannel     kube-flannel-ds-kx9c8                1/1     Running   0              20m
kube-system      coredns-787d4945fb-dhmzs             1/1     Running   0              46h
kube-system      coredns-787d4945fb-zjp28             1/1     Running   0              46h
kube-system      etcd-k8s-master                      1/1     Running   1              46h
kube-system      kube-apiserver-k8s-master            1/1     Running   1              46h
kube-system      kube-controller-manager-k8s-master   1/1     Running   1              46h
kube-system      kube-proxy-5hxm7                     1/1     Running   1              46h
kube-system      kube-proxy-8dtn8                     1/1     Running   0              20m
kube-system      kube-proxy-xfrd2                     1/1     Running   0              33m
kube-system      kube-scheduler-k8s-master            1/1     Running   1              46h
metallb-system   controller-577b5bdfcc-ql2fb          1/1     Running   1 (31m ago)    4h28m
metallb-system   speaker-j5shp                        1/1     Running   0              19m
metallb-system   speaker-lfvxc                        1/1     Running   0              32m
metallb-system   speaker-ttxpb                        1/1     Running   2 (101m ago)   4h28m

おまけ

Kubernetes クラスターの削除

sudo kubeadm reset && rm ~/.kube/config && rm -r /etc/cni/net.d && sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X
sudo kubeadm init --apiserver-advertise-address=192.168.10.101 --pod-network-cidr=10.244.0.0/16
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config && sudo chown $(id -u):$(id -g) ~/.kube/config