ラズパイで自宅Kubernetes構築 (2026年夏版)
go言語で作成したアプリの実行環境としてKubernetes(以下ではK8s)を使いたくなりましたので、2026年の夏にRaspberry Piを使って最新の環境構築を行ったときのメモです。
なお、この記事は2026年8月25日時点で最新版だったv1.36.2を使って書き始めたのですが、翌日にK8sの最新版v1.37がリリースされてしまいました。そのため、v1.37で最初からやり直しています。
数年前にK8s v1.28 (Raspberry Pi OS Bookworm)で構築したときと比べて色々変わっていましたので、この記事もすぐに時代遅れになってしまいそうですが、参考になれば幸いです。
自宅K8sの全体像
Section titled “自宅K8sの全体像”Raspberry Pi 4を4台使ってハードウェア環境を構築しています。
写真は下図のK8s用システムの枠で囲んだ部分になります。
flowchart TB pow[ACアダプタ] hub[PoEハブ 1Gbps<br>10.0.0.0/22] pi1[ラズパイ#1<br>'pi4main'] pi2[ラズパイ#2<br>'pi4node1'] pi3[ラズパイ#3<br>'pi4node2'] pi4[ラズパイ#4<br>'pi4node3'] wlan[Wi-Fiルーター] internet([インターネット]) pc[PC<br>Ubuntu 24.04 LTS] pow --- hub subgraph K8s用システム hub -- 10.0.0.1 --- pi1 hub -- 10.0.1.1 --- pi2 hub -- 10.0.1.2 --- pi3 hub -- 10.0.1.3 --- pi4 end pc --- wlan pi1 -- pi4main.local --- wlan pi2 -- pi4node1.local --- wlan pi3 -- pi4node2.local --- wlan pi4 -- pi4node3.local --- wlan wlan --- internet
各Raspberry PiはPoE HATを搭載しており、電源は有線LANポートから得ているので、セットアップ完了後のK8s用システムから出ている配線はPoEハブのACアダプタだけになり、非常にすっきりしています。
PoEハブ: スイッチングハブ(1GbE・PoE対応)10.0.0.0/22のプライベートネットワークを構築してラズパイ同士を接続する。- PoE HAT経由で給電可能。
ラズパイ#1: Raspberry Pi 4 Model B 4GB + PoE HAT + 250GB USB SSD- K8sのコントロールプレーンとして使用する。
- Podネットワークアドオン(CNIプラグイン)にはflannelを使用する。
- ロードバランサーにはMetalLBを使用する。
- Ingress-Nginx Controllerはリタイアしたそうなので、Gateway APIを使用する。
- Metrics Serverや
DashboardHeadlampを管理ツールとして導入する。
- Persistent Volumeやプライベートレジストリを提供するため、microSDカードより高速・大容量なUSB SSDを使う。
- Wi-Fi接続して、インターネット接続やPCからの遠隔操作を可能にする。最終的には、
ラズパイ#2〜ラズパイ#4からのインターネット接続をルーティングする。Avahiにより、PCからはホスト名.localという名前で接続できる。
- K8sのコントロールプレーンとして使用する。
ラズパイ#2〜ラズパイ#4: Raspberry Pi 4 Model B 4GB + PoE HAT + 64GB microSD- K8sのノードとして使用する。
- セットアップ初期段階ではWi-Fiは有効になっているが、不要なWi-Fi通信を減らすため、最終的にはWi-Fiを無効にする。
- セットアップ完了後は、
ラズパイ#1を経由してインターネット接続する。
1台目のセットアップ
Section titled “1台目のセットアップ”Raspberry Piは4台ありますが、途中までのセットアップ内容は共通なので、容量の小さいmicroSDカード(ここでは32GB製品を使用)を使って1台目のセットアップを行い、それを吸い出してイメージファイルを作成し、USB SSDや64GB microSDカードに移していきます。
Raspberry Pi OSのセットアップ
Section titled “Raspberry Pi OSのセットアップ”まずは、Raspberry Pi OSに関する基本的な部分をセットアップします。
microSDカードにOSイメージを書き込む
Section titled “microSDカードにOSイメージを書き込む”PC(Ubuntu 24.04 LTS)を使って、Raspberry Pi OS (64-bit)のページからRaspberry Pi OS Liteの最新版(13 trixie)をダウンロードして、32GB microSDカードに書き込んでいきます。
sudo dmesg # microSDカードが挿入されたときのデバイス名を調べる: mmcblk0mount|grep mmcblk0 # Ubuntuデスクトップがマウントしているか確認sudo umount /dev/mmcblk0p* # マウントしていたらアンマウントする
# OSイメージの配布ファイル(`.img.xz`)をダウンロードしたフォルダーでコマンドを実行するxz -dkT 6 ./2026-06-18-raspios-trixie-arm64-lite.img.xzsudo dd if=./2026-06-18-raspios-trixie-arm64-lite.img of=/dev/mmcblk0 bs=16M1台目を起動して初期設定する
Section titled “1台目を起動して初期設定する”ラズパイ#1にディスプレイとキーボードを接続し、32GB microSDカードを挿入して電源を入れ、キーボードレイアウトを選択して、新規作成するユーザー名とパスワードを入力します。当記事では、例としてpiという名前を使っています。(古のRaspberry Pi OSのデフォルトユーザー名)
ユーザー名・パスワードでログイン後、raspi-configでラズパイ#1の設定を行います。
sudo raspi-config- System Options
- Wireless LAN
- 日本国内で使用するので、
JPを選択 - SSIDとパスワードを入力
- 日本国内で使用するので、
- Hostname:
pi4main
- Wireless LAN
- Update: raspi-configを最新版に更新する
- Interface Options
- SSH: 有効にする
- Localisation Options
- Locale:
ja-JP.UTF-8を追加 (日本語表示できない場合を考慮してen_GB.UTF-8は残す) - Timezone: 日本国内で使用するので、
Asia/Tokyoを選択
- Locale:
- Advanced Options
- Bootloader Version
- Latest
- Bootloader Version
Bootloaderのバージョンは、sudo vcgencmd bootloader_versionで確認できます。
raspi-configを終了してreboot後、システム全体をアップグレードしておきます。
sudo apt updatesudo apt full-upgradesudo apt autoremove # アップグレード後に不要になったパッケージが生じた場合に実行ネットワークを設定する
Section titled “ネットワークを設定する”サーバーとして使うために固定IPアドレスを設定します。
以前のRaspberry Pi OSはdhcpcdでネットワークを設定していましたが、Bookworm以降はNetworkManagerを使うようになっています。GUIの無い環境のため、TUI版ツールnmtuiで設定します。
# 日本語表示できない場合`en_GB.UTF-8`に変更する。再ログインが必要。sudo update-locale LANG=en_GB.UTF-8
sudo nmtui
# nmtuiが終わったら、ロケールを戻す。sudo update-locale LANG=ja_JP.UTF-8- 有線LAN側:
- IPv4 CONFIGURATION: Manual
- Addresses:
10.0.0.1/22
- Addresses:
- IPv6 CONFIGURATION:
Disabled
- IPv4 CONFIGURATION: Manual
- Wi-Fi側:
- IPv4 CONFIGURATION: Manual
- Addresses:
x.y.z.90/24 - Gateway: ルーターのIPアドレス
- DNS servers: DNSサーバのIPアドレス (
1.1.1.1など)
- Addresses:
- IPv6 CONFIGURATION:
Disabled
- IPv4 CONFIGURATION: Manual
K8s用システムで使用しないIPv6は無効にします。
sudo nano /boot/firmware/cmdline.txt1行目の先頭にipv6.disable=1 を追加します。
ipv6.disable=1 console=serial0,115200 …reboot後、ip aコマンドなどでIPアドレスを確認します。
Raspberry Piをサーバとして使うため、Wi-Fiの電力管理をオフにして、Wi-Fiの省電力による接続不安定を回避します。
sudo apt install wireless-toolssudo nano /etc/rc.local # trixieではこのファイルが無い模様#!/bin/bash/usr/sbin/iwconfig wlan0 power offexit 0sudo chmod 755 /etc/rc.localsudo systemctl start rc-localiwconfig wlan0コマンドを実行して、Power Management:offになっていることを確認します。
Raspberry Piハードウェアの設定を変更する
Section titled “Raspberry Piハードウェアの設定を変更する”/boot/firmware/config.txtにハードウェアの設定を必要に応じて追加します。(任意)
sudo nano /boot/firmware/config.txt# https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README
# Bluetoothを無効にする場合dtoverlay=disable-bt
# ディスプレイなしで運用する場合hdmi_force_hotplug=1 # hdmi_groupやhdmi_modeはコメントアウト
# PoE HATのファンの回転数制御を変更する場合dtoverlay=rpi-poedtparam=poe_fan_temp0=70000,poe_fan_temp0_hyst=1000dtparam=poe_fan_temp1=75000,poe_fan_temp1_hyst=5000dtparam=poe_fan_temp2=80000,poe_fan_temp2_hyst=5000dtparam=poe_fan_temp3=82000,poe_fan_temp3_hyst=2000SSHをパスワード入力なしで接続できるようにする
Section titled “SSHをパスワード入力なしで接続できるようにする”PCのターミナルでSSHの公開鍵を作成してラズパイ#1に転送します。
ssh-keygen -t rsa -b 4096 # id_rsa.pubを作成するssh-copy-id -i ~/.ssh/id_rsa.pub pi@x.y.z.90これでPCからssh pi@x.y.z.90で接続するときにパスワード入力が不要になります。
K8s関連のセットアップ
Section titled “K8s関連のセットアップ”次に、K8sを動かすために必要なソフトをインストールします。
- nerdctl
- containerdやruncが同梱されているFullをインストールする
- kubeadm, kubelet, kubectl
nerdctl(full)をインストールする
Section titled “nerdctl(full)をインストールする”まずはK8sのネットワーク設定に必要な(あるいは必要だった?)ソフトをインストールします。
sudo apt updatesudo apt install iptables arptables ebtablessudo nano /boot/firmware/cmdline.txtcontainerdを動かすために必要なパラメータ(cgroup_で始まる)を追加します。
cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 ipv6.disable=1 console=serial0,115200 …nerdctlのReleasesページからnerdctl(full)をダウンロードして、/usr/local配下に展開します。
以下はv2.3.5の例です。
mkdir -p ~/tempcd ~/tempwget https://github.com/containerd/nerdctl/releases/download/v2.3.5/nerdctl-full-2.3.5-linux-arm64.tar.gzsudo tar Cxzvf /usr/local nerdctl-full-2.3.5-linux-arm64.tar.gz # Cでdir指定できるcontainerdを環境設定する
Section titled “containerdを環境設定する”K8s docsのContainer Runtimesの説明に則って、cgroup driversはsystemdを使うように設定します。
また、K8s用システムが後述のプライベートレジストリからhttp接続でコンテナイメージをpullできるように設定します。
sudo mkdir -p /etc/containerdcontainerd config default | sudo tee /etc/containerd/config.toml > /dev/nullsudo nano /etc/containerd/config.toml/etc/containerd/config.tomlの デフォルト設定値を以下のように変更します。
...[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc] ... [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options] SystemdCgroup = true... [plugins.'io.containerd.cri.v1.images'.registry] config_path = '/etc/containerd/certs.d'レジストリを設定します。こちらの説明に則って、プライベートレジストリにhttp接続できるようにします。
sudo mkdir -p /etc/containerd/certs.d/docker.iosudo mkdir -p /etc/containerd/certs.d/10.0.0.1:5000Dockerのレジストリの設定:
sudo nano /etc/containerd/certs.d/docker.io/hosts.tomlserver = "https://registry-1.docker.io"[host."https://registry-1.docker.io"]プライベートレジストリの設定:
sudo nano /etc/containerd/certs.d/10.0.0.1:5000/hosts.tomlserver = "http://10.0.0.1:5000"[host."http://10.0.0.1:5000"] capabilities = ["pull", "resolve", "push"] skip_verify = truecontainerdを起動します。
sudo systemctl enable --now containerdsudo nerdctl run hello-world # 動作確認Buildkitをセットアップする
Section titled “Buildkitをセットアップする”nerdctl buildを使えるようにBuildKitをセットアップします。
sudo mkdir -p /etc/buildkitsudo nano /etc/buildkit/buildkitd.toml/etc/buildkit/buildkitd.tomlを作成します。
[worker.oci] enabled = false
[worker.containerd] enabled = true # namespace should be "k8s.io" for Kubernetes (including Rancher Desktop) namespace = "default"buildkitを起動します。
sudo systemctl enable --now buildkitkubeadm, kubelet, kubectlを使うための準備を行う
Section titled “kubeadm, kubelet, kubectlを使うための準備を行う”IPv4 Forwardの設定とiptablesにブリッジされたトラフィックを見えるようにします。
cat <<EOF | sudo tee /etc/modules-load.d/k8s.confoverlaybr_netfilterEOF
sudo modprobe overlaysudo modprobe br_netfiltersysctlパラメータを設定します。
cat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1net.ipv4.ip_forward = 1EOF
sudo sysctl --systemswapがいるとkubeletは適切に動作しないため、swapを停止します。
sudo systemctl list-units --type=swap # SWAPがいるかどうか確認sudo mkdir -p /etc/rpi/swap.conf.d/sudo tee /etc/rpi/swap.conf.d/90-disable-swap.conf > /dev/null <<EOF[Main]Mechanism=noneEOFrebootして、設定値を確認します。
lsmod | grep br_netfilterlsmod | grep overlaysysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forwardsudo systemctl list-units --type=swapkubeadm, kubelet, kubectlをインストールする
Section titled “kubeadm, kubelet, kubectlをインストールする”kubeadm, kubelet, kubectlをインストールします。
- kubeadm: クラスターを起動するコマンドです。
- kubelet: クラスター内のすべてのマシンで実行されるコンポーネントです。 Podやコンテナの起動などを行います。
- kubectl: クラスターにアクセスするためのコマンドラインツールです。
なお、当記事を書いている間にURLがv1.36がv1.37に変わっています。最新のURLはこちらから確認できます。
sudo apt updatesudo apt install apt-transport-https ca-certificates curl gpgcurl -fsSL https://pkgs.k8s.io/core:/stable:/v1.37/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpgecho 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.37/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update # K8s用のリポジトリを追加sudo apt install kubelet kubeadm kubectlsudo apt-mark hold kubelet kubeadm kubectlkubectl version # Kubernetesのバージョンを確認NFSクライアントをインストールする
Section titled “NFSクライアントをインストールする”Persistent Volume用にNFSを使うので、NFSクライアントをインストールしておきます。
sudo apt updatesudo apt install nfs-common/etc/hostsを編集する
Section titled “/etc/hostsを編集する”ラズパイ#1〜ラズパイ#4のホスト名を/etc/hostsに追加します。
sudo nano /etc/hosts10.0.0.1 pi4main10.0.1.1 pi4node110.0.1.2 pi4node210.0.1.3 pi4node3ここで1台目をシャットダウンして電源を落とします。
sudo shutdown -h nowSSHが使えるようになっているので、不要になるキーボードとディスプレイも取り外します。
2台目〜4台目のセットアップ
Section titled “2台目〜4台目のセットアップ”1台目としてセットアップした32GB microSDカードの内容を吸い出して、ラズパイ#2〜ラズパイ#4用の64GB microSDカードに移し、それぞれのIPアドレスを設定します。また、ラズパイ#1用の250GB USB SSDにも移します。
1台目のディスクイメージを吸い出して縮小する
Section titled “1台目のディスクイメージを吸い出して縮小する”ラズパイ#1から32GB microSDカードを取り出して、PCでディスクイメージをファイル(.img)に吸い出します。
sudo dmesg # /dev/mmcblk0 であることを確認するcd ~/tempsudo dd if=/dev/mmcblk0 of=raspios-trixie-k8s.img bs=16M # 処理時間はmicroSDカードの容量に比例吸い出したイメージファイルのサイズは大きい(microSDカードの容量)ので、PiShrinkやresizeimage.plを使ってファイルサイズを縮小します。
# resizeimage.plを使う場合の例sudo perl /path/to/resizeimage.pl $HOME/temp/raspios-trixie-k8s.imgsudo chown $(id -u):$(id -g) raspios-trixie-k8s.img2台目〜4台目のmicroSDカードに書き込む
Section titled “2台目〜4台目のmicroSDカードに書き込む”出来上がった1台目のイメージファイルをラズパイ#2〜ラズパイ#4用の64GB microSDカードに書き込みます。
# 64GB microSDカードを都度入れ替えて以下のコマンドを実行するsudo dd if=raspios-trixie-k8s.img of=/dev/mmcblk0 bs=16M1台目のUSB SSDにも書き込む
Section titled “1台目のUSB SSDにも書き込む”ラズパイ#1用の250GB USB SSDにも1台目のイメージファイルを書き込みます。
sudo dmesg # USB SSDのデバイス名を調べる: /dev/sdcsudo dd if=raspios-trixie-k8s.img of=/dev/sdc bs=16M1台ずつ起動してホスト名とIPアドレスを変更する
Section titled “1台ずつ起動してホスト名とIPアドレスを変更する”今の状態では、microSDカードのホスト名とIPアドレスが全て1台目のまま(pi4mainと10.0.0.1/22 x.y.z.90/24)になっているので、ラズパイ#2から順に1台ずつ64GB microSDカードで起動して、SSH経由でIPアドレスを変更します。
ssh pi@x.y.z.90まずraspi-configを実行して、ホスト名を変更します。さらに、microSDカードに書き込んだディスクイメージのファイルシステム領域を拡張しておきます。
sudo raspi-config- System Options
- Hostname:
pi4node1(#3はpi4node2, #4はpi4node3)
- Hostname:
- Advanced Options
- Expand Filesystem
- Bootloader Version
- Latest
そして、nmtuiでIPアドレスの設定を変更します。有線LAN側のGatewayにはラズパイ#1のIPアドレス(10.0.0.1)を設定しておきます。
sudo nmtui- 有線LAN側:
- IPv4 CONFIGURATION: Manual
- Addresses:
10.0.1.1/22(#3は10.0.1.2/22, #4は10.0.1.3/22) - Gateway:
10.0.0.1 - DNS servers: DNSサーバのIPアドレス (1.1.1.1など)
- Addresses:
- IPv4 CONFIGURATION: Manual
- Wi-Fi側:
- IPv4 CONFIGURATION: Manual
- Addresses:
x.y.z.91/24(#3はx.y.z.92/24, #4はx.y.z.93/24)
- Addresses:
- IPv4 CONFIGURATION: Manual
rebootして新しいIPアドレスでSSH接続し、ip aコマンドでIPアドレスの設定を確認します。
ssh pi@x.y.z.91 # #3は`ssh pi@x.y.z.92`, #4は`ssh pi@x.y.z.93`ラズパイ#2〜ラズパイ#4のIPアドレスを変更して重複が無くなったら、ラズパイ#1をUSB SSDで起動して、USB SSDに書き込んだディスクイメージのファイルシステム領域を拡張します。
sudo raspi-config- Advanced Options
- Expand Filesystem
ネットワークの整理(オプション)
Section titled “ネットワークの整理(オプション)”K8sのノードとして動かすラズパイ#2〜ラズパイ#4は、PCからSSH接続で使う機会がほぼ無いので、Wi-Fiを停止してラズパイ#1からSSH接続で使うようにします。ただし、ラズパイ#2〜ラズパイ#4がDebianパッケージやコンテナイメージなどをパブリックリポジトリからダウンロードできるようにする必要があるため、ラズパイ#1でルーティングできるようにします。
flowchart TB pow[ACアダプタ] hub[PoEハブ 1Gbps<br>10.0.0.0/22] pi1[ラズパイ#1<br>'pi4main'] pi2[ラズパイ#2<br>'pi4node1'] pi3[ラズパイ#3<br>'pi4node2'] pi4[ラズパイ#4<br>'pi4node3'] wlan[Wi-Fiルーター<br>x.y.z.0/24] internet([インターネット]) pc[PC<br>Ubuntu 24.04 LTS] pow --- hub subgraph K8s用システム hub -- 10.0.0.1 --- pi1 hub -- 10.0.1.1 --- pi2 hub -- 10.0.1.2 --- pi3 hub -- 10.0.1.3 --- pi4 end pc -- DHCP --- wlan pi1 -- x.y.z.90 --- wlan wlan --- internet
ルーティングを設定する
Section titled “ルーティングを設定する”trixieではnftablesを使ってルーティングを設定することができます。PCからラズパイ#1にSSHでログインして、/etc/nftables.confを編集します。
ssh pi@x.y.z.90sudo nano /etc/nftables.conf#!/usr/sbin/nft -f
flush ruleset
table inet filter { chain input { type filter hook input priority filter; } chain forward { type filter hook forward priority filter; policy accept; iifname "wlan0" oifname "eth0" ct state established,related accept iifname "eth0" oifname "wlan0" accept } chain output { type filter hook output priority filter; }}
table inet nat { chain postrouting { type nat hook postrouting priority srcnat; policy accept; oifname "wlan0" masquerade }}nftablesを起動します。
sudo systemctl enable --now nftablessudo systemctl status nftables # エラーが出ていないか確認するreboot後、設定が正しく反映されていることを確認します。
sudo nft list rulesetラズパイ#1からパスワード入力なしでSSH接続できるようにする
Section titled “ラズパイ#1からパスワード入力なしでSSH接続できるようにする”ラズパイ#1からラズパイ#2〜ラズパイ#4にパスワード入力なしでSSH接続できるようにします。
ssh-keygen -t rsa -b 4096ssh-copy-id -i ~/.ssh/id_rsa.pub pi4node1ssh-copy-id -i ~/.ssh/id_rsa.pub pi4node2ssh-copy-id -i ~/.ssh/id_rsa.pub pi4node3ラズパイ#2〜#4のWi-Fiを停止する
Section titled “ラズパイ#2〜#4のWi-Fiを停止する”ラズパイ#2〜ラズパイ#4の/boot/firmware/config.txtを変更してWi-Fiを停止します。
ssh pi4node1 # pi4node2, pi4node3も同様に行うsudo nano /boot/firmware/config.txt以下の行を末尾に追加します。
dtoverlay=disable-wifireboot後は、PCからラズパイ#2〜ラズパイ#4に直接SSH接続できなくなります。
K8sクラスターの構築
Section titled “K8sクラスターの構築”K8s用システムにおけるラズパイ#1〜ラズパイ#4の役割を以下のようにします。
| 機体 | ホスト名 | K8sでの役割 |
|---|---|---|
ラズパイ#1 | pi4main | コントロールプレーン |
ラズパイ#2 | pi4node1 | ノード (Worker) |
ラズパイ#3 | pi4node2 | ノード (Worker) |
ラズパイ#4 | pi4node3 | ノード (Worker) |
ラズパイ#1には、さらに以下の役割を持たせます。
- NFSサーバ: Persistent Volumeに用いる
- プライベートレジストリ: 自作アプリのコンテナイメージの展開に用いる
以降の設定ではラズパイ#1にSSHでログインして操作を行います。
Helmをインストールする
Section titled “Helmをインストールする”K8s用パッケージマネージャのHelmをインストールします。
- インストールスクリプトを使う場合:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash- aptを使う場合:
export HELM_BUILDKITE_APT_KEY_ID="DDF78C3E6EBB2D2CC223C95C62BA89D07698DBC6"sudo apt install curl gpg apt-transport-httpscurl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey > "${TMPDIR:-/tmp}/helm.gpg"sh <<ENDif [ "$(gpg --show-keys --with-colons "${TMPDIR:-/tmp}/helm.gpg" | awk -F: '$1 == "fpr" {print $10}' | head -n 1)" != "${HELM_BUILDKITE_APT_KEY_ID}" ]; then echo "ERROR: Unexpected Helm APT key ID: potential key compromise"; exit 1; ficat "${TMPDIR:-/tmp}/helm.gpg" | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/nullecho "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.listEND
# ERRORが発生しなければ、aptでhelmをインストールするsudo apt updatesudo apt install helmNFSサーバを起動する
Section titled “NFSサーバを起動する”/shareフォルダーを作成して、NFSサーバで共有します。
sudo mkdir /sharesudo apt install nfs-kernel-serversudo nano /etc/exports/share 10.0.0.0/22(rw,no_root_squash,no_subtree_check)sudo systemctl restart nfs-serverラズパイ#1からラズパイ#2〜ラズパイ#4にSSHでログインして、NFSサーバのボリュームをマウントできることを確認します。
# NFSの動作確認sudo mount -t nfs 10.0.0.1:/share /mntsudo umount /mntプライベートレジストリを起動する
Section titled “プライベートレジストリを起動する”registryコンテナイメージを起動します。
sudo nerdctl container run -d -p 5000:5000 --restart always --name registry registry
# 動作確認: レジストリ内を確認するcurl http://pi4main:5000/v2/_catalogコントロールプレーンを構築する
Section titled “コントロールプレーンを構築する”kubeadm initコマンドを実行して、ラズパイ#1をK8sのコントロールプレーンとしてセットアップします。flannelをデフォルト設定で使用するため、--pod-network-cidr=10.244.0.0/16を指定します。
# kubeletがエラーになっていないことを確認するsudo systemctl status kubelet # エラーの場合、swap無効化などの設定が抜けている可能性あり
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=10.0.0.1kubeadm initが成功すると、以下のようなメッセージが表示されます。(*は伏せ字)
最後の2行はラズパイ#2〜ラズパイ#4で実行するコマンドです。メモに控えておきます。
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
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
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 10.0.0.1:6443 --token ******.**************** \ --discovery-token-ca-cert-hash sha256:*********************************以下のコマンドを実行すると、ラズパイ#1のログインユーザー(pi)がkubectlコマンドを使ってK8sを制御できるようになります。
mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configPodネットワークアドオンのflannelをインストールします。
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.ymlkubectl get pods --all-namespaces # flannelのPodが作成できていることを確認ノードを追加する
Section titled “ノードを追加する”kubeadm init時に表示された最後の2行のコマンド(kubeadm join)をSSH経由で実行して、ラズパイ#2〜ラズパイ#4をノードとして追加します。
ssh pi4node1 sudo kubeadm join 10.0.0.1:6443 --token ...(以下略)ssh pi4node2 sudo kubeadm join 10.0.0.1:6443 --token ...(以下略)ssh pi4node3 sudo kubeadm join 10.0.0.1:6443 --token ...(以下略)ノードが追加されていることを確認します。
kubectl get nodes
# 成功していれば、以下のような感じでノードのリストが表示される# NAME STATUS ROLES AGE VERSION# pi4main Ready control-plane 25m v1.37.0# pi4node1 Ready <none> 90s v1.37.0# pi4node2 Ready <none> 77s v1.37.0# pi4node3 Ready <none> 48s v1.37.0ラズパイ#2〜ラズパイ#4のROLESが<none>になっているので、workerを割り当てます。
kubectl label node pi4node1 node-role.kubernetes.io/worker=kubectl label node pi4node2 node-role.kubernetes.io/worker=kubectl label node pi4node3 node-role.kubernetes.io/worker=kubectl get nodes # ワーカーのROLESがworkerであることを確認MetalLBをインストールする
Section titled “MetalLBをインストールする”公式サイトでURLを確認して、MetalLBをインストールします。
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.16.1/config/manifests/metallb-frr-k8s.yaml
# 動作確認(READYになるまで少し時間がかかる)kubectl get deploy -n metallb-systemkubectl get ds -n metallb-systemkubectl get pod -n metallb-systemMetalLBが使用するIPアドレスの範囲を指定します。サブネットマスクで指定できますが、以下のように範囲指定することもできます。
type: LoadBalancerでデプロイしたサービスのEXTERNAL-IPが<pending>になってしまったことがあるので、明示的にautoAssign: trueをセットするようにしています。
nano ./ip-address-pool.yamlapiVersion: metallb.io/v1beta1kind: IPAddressPoolmetadata: name: first-pool namespace: metallb-systemspec: addresses: - 10.0.2.1-10.0.2.100 autoAssign: truekubectl apply -f ./ip-address-pool.yamlkubectl describe -n metallb-system IPAddressPool first-pool # 設定値の確認Persistent Volumeを使ったnginxサービスを展開する
Section titled “Persistent Volumeを使ったnginxサービスを展開する”K8sでアプリケーションを展開できる準備が整いましたので、試しにnginxでWebサーバを動かしてみます。
nginxで公開するWebページはPersistent Volumeに格納して、独自のコンテンツを配信できるようにします。
PersistentVolumeを作成する
Section titled “PersistentVolumeを作成する”PersistentVolume用フォルダーをNFSサーバの/shareフォルダーの中に作成して、その中にWebページのサンプルファイルを配置します。
sudo mkdir -p /share/pv-wwwecho '<h1>Hello my Kubernetes!</h1>' | sudo tee /share/pv-www/index.html/share/pv-www用のPersistentVolumeを作成します。
nano ./create_pv-www.yamlapiVersion: v1kind: PersistentVolumemetadata: name: pv-www labels: name: pv-wwwspec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: slow nfs: server: 10.0.0.1 path: /share/pv-wwwkubectl apply -f create_pv-www.yamlkubectl get pvkubectl describe pv pv-www # PVができていることを確認PersistentVolumeClaimでストレージを要求する
Section titled “PersistentVolumeClaimでストレージを要求する”nginxサービスが利用するストレージを要求するためにPersistentVolumeClaimを作成します。
nano create_pvc-www.yamlapiVersion: v1kind: PersistentVolumeClaimmetadata: name: my-www-claimspec: accessModes: - ReadWriteMany storageClassName: slow resources: requests: storage: 5Gi selector: matchLabels: name: pv-wwwkubectl apply -f create_pvc-www.yamlkubectl get pvckubectl describe pvc my-www-claim # PVCができていることを確認nginxサービスを起動する
Section titled “nginxサービスを起動する”nginxサービスはPVC my-www-claim経由で/share/pv-wwwをマウントするように構成します。
nano deploy_nginx.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app.kubernetes.io/name: nginxspec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: nginx template: metadata: labels: app.kubernetes.io/name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html-volume mountPath: "/usr/share/nginx/html" volumes: - name: html-volume persistentVolumeClaim: claimName: my-www-claim---apiVersion: v1kind: Servicemetadata: name: nginx-servicespec: selector: app.kubernetes.io/name: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancerkubectl apply -f deploy_nginx.yaml
# nginxのserviceが動いていることを確認し、EXTERNAL-IPを取得するkubectl get service
# Webページを取得できることを確認curl http://10.0.2.1/ # EXTERNAL-IPにアクセスする管理用のWeb UIをセットアップする
Section titled “管理用のWeb UIをセットアップする”以前はKubernetes Dashboardがありましたが、現在はメンテナンスが行われていません。代わりにHeadlampを使います。
Kubernetes Metrics Serverをインストールする
Section titled “Kubernetes Metrics Serverをインストールする”Kubernetes Metrics Serverを入れると、CPUやメモリなどのリソースの使用状況が確認できるようになります。
マニフェストファイルをダウンロードして、必要な箇所を修正します。
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlnano components.yamlspec.template.spec.containers.argsの配下に--kubelet-insecure-tlsを追加して、httpで使えるようにします。
公式の文書にFor testing purposes onlyと書かれているように、K8s用システムはテスト用です。
spec: template: spec: containers: - args: - --kubelet-insecure-tls # 追加 - --cert-dir=/tmpマニフェストファイルを適用し、READYになるのを待ちます。kubectl top nodeコマンドやkubectl top podコマンドでCPUやメモリの使用量を確認できるようになります。
kubectl apply -f components.yamlkubectl get pods -n kube-system # READYになるのを待つ
kubectl top nodekubectl top podHeadlampをインストールする
Section titled “Headlampをインストールする”Helmを使ってHeadlampをインストールします。
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/helm repo updatehelm upgrade --install my-headlamp headlamp/headlamp --namespace kube-systemkubectl get pods -n kube-system # `my-headlamp`が動作していることを確認インストールに成功すると、以下のメッセージが表示されます。このメッセージのとおりに実行すればHeadlampのWeb UIを表示できるのですが、ラズパイ#1はGUIを持たないので、http://127.0.0.1:8080を閲覧することはできません。
NOTES:1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace kube-system -l "app.kubernetes.io/name=headlamp,app.kubernetes.io/instance=my-headlamp" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace kube-system $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace kube-system port-forward $POD_NAME 8080:$CONTAINER_PORT2. Get the token using kubectl create token my-headlamp --namespace kube-systemそこで、PCから閲覧できるように、ポートフォワード時にホストのアドレスとしてx.y.z.90または0.0.0.0を指定します。
# メッセージからコピペexport POD_NAME=$(kubectl get pods --namespace kube-system -l "app.kubernetes.io/name=headlamp,app.kubernetes.io/instance=my-headlamp" -o jsonpath="{.items[0].metadata.name}")export CONTAINER_PORT=$(kubectl get pod --namespace kube-system $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
# 認証トークンを取得するkubectl create token my-headlamp -n kube-system > token.txt
# --addressでホストのアドレスを指定するkubectl -n kube-system port-forward $POD_NAME 8080:$CONTAINER_PORT --address x.y.z.90PCからhttp://x.y.z.90:8080をWebブラウザで開くと認証トークンを入力する画面が表示されるので、token.txtの内容をコピペして認証ボタンを押下します。