Kubernetes on Raspberry Pi のセットアップ
自宅に持て余している Raspberry Pi を高可用な自宅サーバーもとい「おうちKubernetes」(n番煎じ)として活用するため、まずはKubernetesを導入するところから始める。
背景
- 学生の頃のインターンシップや、社会人になってからイベントで頂いたRaspberry Piが何台か余っている
- これまでデスクトップPCにサーバーを構築して、セルフホストしたアプリを家族や仲間内に公開してきたが、メンテナンス時に使えなくなることがあった
- デスクトップPCを常時稼働させると電気代がツライし発火するかもしれない
目的
- ちょうど複数台余った Raspberry Pi で冗長構成を取り、サービスを止めずにメンテナンスできるようにする
- 個人的な Kubernetes の勉強環境を構築する
- デスクトップPCに比較して省電力・安全安心にする(多分)
やらないこと
- 完璧な可用性の担保
- UPSとか必要そう
- そもそも自宅サーバーなので停電なり災害なりあったら強制サ終
クラスター構成
今回は以下の通り Master/Worker ともに冗長構成とする。
未だに Raspberry Pi 2 だと 32bit OS を使う羽目になるが、まだサポートしてくれているコンテナが少ないせいでアプリの立ち上げには苦戦する…。また別の記事にする。今からクラスターを作るなら Raspberry Pi 4 only の構成がおすすめ。
- Master
- Raspberry Pi 4 (4GB RAM) × 2機
- Ubuntu 22.04.3 64bit
- Raspberry Pi 3 Rev1.2 (1GB RAM) × 1機
- Ubuntu 22.04.3 64bit
- Raspberry Pi 4 (4GB RAM) × 2機
- Worker
- Raspberry Pi 2 Rev1.1 (1GB RAM) × 3機
- Ubuntu 22.04.3 32bit
- Raspberry Pi 2 Rev1.1 (1GB RAM) × 3機
SDカードの準備
Raspberry Pi Imager でOSを焼く。今回は Ubuntu 22.04.3 を選択。
最近の Imager は焼く前にホスト名やSSHのユーザー名・パスワード、Wi-Fi等が設定できる。すげぇ。
初期設定
OSを焼いたSDカードを Raspberry Pi に挿入し、起動する。起動後の各 Raspberry Pi 上で初期設定作業を繰り返し行う。
なお、 Raspberry Pi のIPアドレスは、macOS/Linuxなら arp-scan
コマンド、Windowsなら ping
と arp
の組み合わせで推測できる。例として arp-scan
コマンドでの検索方法は以下の通り。
$ sudo arp-scan -I [ネットワークインターフェース名] 192.168.xxx.0/24
extraモジュールのインストール
クラスター内の通信のために vxlan モジュールが必要。
$ sudo apt install -y linux-modules-extra-raspi
IP固定
netplan のファイルを追加する。
$ sudo bash -c 'cat << EOS > /etc/netplan/99-manual.yaml
network:
version: 2
ethernets:
eth0:
addresses:
- 192.168.xxx.aaa/24 # ノードのIP
gateway4: 192.168.xxx.ccc # デフォルトルーターのIP
nameservers:
addresses:
- 1.1.1.1
- 1.0.0.1
dhcp4: no
optional: true
EOS'
Linuxカーネルのパラメータ
$ sudo nano /boot/firmware/cmdline.txt
# 以下を末尾に追記 (改行不要)
cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset
SDカードの延命設定
そのまま Raspberry Pi を運用していると、SDカードに対して多数の読み書きが行われ、SDカードが早期に故障する可能性が高まる。
読み書きの多いディレクトリのRAMディスク化、および自動更新の無効化により、SDカードの寿命を長くすることができる(といっても運用し始めたばかりでまだ効果はわからず。。。)
RAMディスクの設定
ここでは、特に読み書きが多いと思われる以下のディレクトリを対象として、RAMディスク(メモリ上にファイルが書き込まれる)の設定を行う。
ディレクトリパス | 内容 |
---|---|
/tmp | 一時ファイル |
/var/tmp | 一時ファイル |
/var/log | OS、ミドルウェアのログ |
/var/spool | 一時ファイル |
/var/cache | OS、ミドルウェアのキャッシュ |
ただし、/var/cache/apt
については、比較的ファイルサイズが大きくなり、Raspberry Pi のメモリ容量では不足する可能性が高いため対象から除外する。
以下のコマンドでRAMディスクがマウントされるようにする。
$ sudo nano /etc/fstab
# 末尾に以下を追記
tmpfs /tmp tmpfs defaults,size=64m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=16m,noatime,mode=0755 0 0
tmpfs /var/log tmpfs defaults,size=64m,noatime,mode=0755 0 0
tmpfs /var/spool tmpfs defaults,size=4m,noatime,mode=0755 0 0
tmpfs /var/cache tmpfs defaults,size=32m,noatime,mode=0755 0 0
先に /var/cache/apt
の退避先を作る。
$ sudo mkdir /var/cache.apt
RAM ディスクへの切り替えを行う。
現在保存されているデータは全て破棄されるため、必要に応じてバックアップを行うこと。
$ sudo bash -c 'rm -rf /tmp/* /var/tmp/* /var/log/* /var/spool/* /var/cache/* && mount -a && ln -sf /var/cache.apt /var/cache/apt'
以下のコマンドで切り替え完了を確認する。
$ df -h
# コマンドの表示結果に以下が含まれていることを確認する
tmpfs 64M 0 64M 0% /tmp
tmpfs 32M 0 32M 0% /var/cache
tmpfs 64M 0 64M 0% /var/log
tmpfs 4.0M 0 4.0M 0% /var/spool
tmpfs 16M 0 16M 0% /var/tmp
なお、次回起動時からは、自動的にRAMディスクがマウントされる。
/var/cache/apt のシンボリックリンクは、再起動後は削除されるため、 apt で作業を行う場合はもう一度シンボリックリンクを作成すること。
folder2ram などのRAMディスクとストレージを同期して永続化を図る仕組みも存在するものの、今回は期待した動作にならず導入を見送る。
/var/log に記録可能なログのサイズが制限されるため、必要に応じて、適切なログローテーションを設定すること。
自動更新の無効化
apt の設定ファイルを更新する。
$ sudo nano /etc/apt/apt.conf.d/20auto-upgrades
# 以下の通り更新して保存する
APT::Periodic::Update-Package-Lists "0";
APT::Periodic::Unattended-Upgrade "0";
再起動
設定を反映するために、 Raspberry Pi を再起動する。固定IPでアクセスできるかどうか確認すること。
k3sの導入
IoTデバイスでも動作する軽量な Kubernetes ディストリビューションである k3s をインストールする。
Master ノードの構築
1台目と2台目以降では手順が異なるので注意。
1台目の Master ノードでの作業
k3s server のインストール
最初の1台目に以下のコマンドで k3s server をインストールする。 K3S_KUBECONFIG_MODE
に 644
を指定すると、一般ユーザーでも kubectl
コマンドを実行できるようになる。
$ curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE=644 sh -s - server --cluster-init --tls-san [ノードのIP] --bind-address [ノードのIP] --node-ip [ノードのIP]
vxlan モジュールの有効化
server のインストールに成功したあと、先刻インストールした vxlan モジュールを有効化する。
本手順は2台目以降の Master ノード、 Worker ノードでも必要。
$ sudo nano /etc/systemd/system/k3s.service
# ExecStart=/usr/local/bin/k3s の前の行に以下を追記する
ExecStartPre=-/sbin/modprobe vxlan
$ sudo systemctl daemon-reload
$ sudo systemctl restart k3s
まずは1台構成のクラスターが構築されたことを確認する。
$ kubectl get no
NAME STATUS ROLES AGE VERSION
[1台目のホスト名] Ready control-plane,etcd,master 4d22h v1.28.4+k3s2
server 連携トークンの取得
以下のコマンドで、2台目以降を連携するためのトークンを取得しておく。
$ sudo cat /var/lib/rancher/k3s/server/node-token
Master ノードへのコンテナデプロイ禁止
Master ノードへ任意のコンテナをデプロイさせなくするためには、以下のコマンドを実行する。本設定が不要ならSkipしても良い。2台目以降も同様に設定が必要となる。
$ kubectl taint nodes [Master ノードのホスト名] node-role.kubernetes.io/master:NoSchedule
2台目以降の Master ノードでの作業
以下の手順を Master ノードとする台数分だけ繰り返す。
k3s server のインストール
以下のコマンドで k3s server をインストールする。
$ curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE=644 K3S_TOKEN=[1台目で取得したトークン] sh -s - server --server https://[1台目のノードのIP]:6443 --tls-san [ノードのIP] --bind-address [ノードのIP] --node-ip [ノードのIP]
クラスターにノードが追加されたことを確認する。
$ kubectl get no
NAME STATUS ROLES AGE VERSION
[1台目のホスト名] Ready control-plane,etcd,master 10m v1.28.4+k3s2
[n台目のホスト名] Ready control-plane,etcd,master 1m v1.28.4+k3s2
vxlan モジュールの有効化
1台目の Master ノードと同様の手順 で有効化しておく。
Master ノードへのコンテナデプロイ禁止
必要に応じて、 1台目の Master ノードと同様の手順 で設定しておく。
Worker ノードの構築
Worker ノードでは手順は共通。
Woker ノードでの作業
以下の手順を Worker ノードとする台数分だけ繰り返す。
k3s agent のインストール
以下のコマンドで k3s agent をインストールする。
$ curl -sfL https://get.k3s.io | K3S_URL=https://[1台目の Master ノードのIP]:6443 K3S_TOKEN=[1台目の Master ノードで取得したトークン] sh -s - --node-ip [ノードのIP]
クラスターにノードが追加され、 ROLES
が worker
であることを確認する。
$ kubectl get no
NAME STATUS ROLES AGE VERSION
[1台目のホスト名] Ready control-plane,etcd,master 20m v1.28.4+k3s2
[2台目のホスト名] Ready control-plane,etcd,master 8m v1.28.4+k3s2
[3台目のホスト名] Ready control-plane,etcd,master 5m v1.28.4+k3s2
[n台目のホスト名] Ready worker 1m v1.28.4+k3s2
vxlan モジュールの有効化
1台目の Master ノードと同様の手順 で有効化しておく。