150ドル以下で構築する4ノードRaspberry Pi K3sクラスター:実践DevOpsラボ

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

午前2時の気づき:なぜ仮想化だけでは不十分なのか

午前2時、本番環境で障害が発生していました。分散ストレージ層のレースコンディション(競合状態)によりノードがダウンしていましたが、自分のワークステーションでは再現できませんでした。ハイエンドの仮想化環境では、ハードウェアの遅延やネットワークの癖が隠されてしまい、こうした障害の引き金が見えなくなります。高可用性(High Availability)を真にマスターするには、物理的なハードウェアが必要だと痛感しました。ソフトウェアがパニックに陥る様子を見るために、物理的にプラグを抜くことができるクラスターが必要だったのです。

マルチノードクラスターを管理することで、ネットワークやリソースの制約に対する視点が変わります。これらの教訓を学ぶために、エンタープライズ向けのサーバーラックは必要ありません。私は144ドルで4ノードのRaspberry Piクラスターを構築しましたが、それはどのクラウド認定資格よりもKubernetesについて多くのことを教えてくれました。ここでは、あなたも同じように構築する方法を紹介します。

150ドルの材料リスト(BOM)

予算内に収めるために、Raspberry Pi Zero 2 Wを選びました。これは非常に小さなフットプリントにクアッドコアプロセッサを搭載しています。512MBというメモリ容量は厳しいですが、それゆえにリソースの最適化を学ぶことを強いられます。コストの内訳は以下の通りです:

  • 4x Raspberry Pi Zero 2 W: 約60ドル(希望小売価格で1台15ドル)
  • 4x 32GB MicroSDカード (SanDisk Ultra): 約24ドル
  • 1x 6ポートUSB充電ステーション (60W): 約25ドル
  • 4x Micro-USBケーブル(15cm程度の短いもの): 約10ドル
  • 1x USB 2.0ハブ + 128GB USBメモリ: 約25ドル
  • 合計: 約144ドル

注:このセットアップでは、高価なPoE Hatやスイッチを節約するために2.4GHzのWiFiを使用しています。K8sのアーキテクチャを学ぶには最適ですが、パケットロスを最小限に抑えるためにノードをルーターの近くに配置することをお勧めします。

インストール:ベアメタルからK3sへ

限られたメモリで作業する場合、効率が重要です。バックグラウンドのオーバーヘッドを50MB以下に抑えるために、Raspberry Pi OS Lite (64-bit)を使用します。デスクトップ環境は絶対に避けてください。

1. OSの準備

Raspberry Pi Imagerを使用してSDカードに書き込みます。事前設定メニューを使用して、一意のホスト名(node-01からnode-04)を設定し、SSHを有効にします。起動する前に、K3sがリソースを正しく管理できるようにcgroupsを有効にする必要があります。/boot/cmdline.txtの末尾に以下を追加してください:

cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

ノードを起動し、ルーターで静的IPを割り当てます。静的IPは、デプロイ中にDHCPリースの期限が切れてクラスターが崩壊するのを防ぎます。

2. コントロールプレーン(node-01)へのK3sのインストール

K3sはエッジコンピューティング向けに設計された軽量のKubernetesディストリビューションです。自作アプリのために約80MBのメモリを節約するため、Traefikとmetrics-serverを無効にします。

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik --disable metrics-server --write-kubeconfig-mode 644" sh -s -

スクリプトが終了したら、ノードトークンを取得します。この文字列により、ワーカーノードがクラスターに安全に参加できるようになります:

sudo cat /var/lib/rancher/k3s/server/node-token

3. ワーカーノードの参加

残りの3つのノードでインストールスクリプトを実行します。コントロールプレーンのIPを指定し、先ほど保存したトークンを使用します:

curl -sfL https://get.k3s.io | K3S_URL=https://<MASTER_IP>:6443 K3S_TOKEN=<YOUR_TOKEN> sh -

node-01からkubectl get nodesを実行します。4つのノードすべてが「Ready」ステータスを返せば、クラスターは正式に稼働しています。

設定:共有ストレージの悩みを解決する

KubernetesのPodは一時的なものです。共有ストレージがない限り、Podが別のノードで再起動するとデータは消失します。専用のSANはないため、node-01に接続した128GBのUSBメモリをNFSサーバーとして利用します。

1. NFSサーバーのセットアップ

USBメモリをnode-01に接続し、ネットワークにエクスポートします:

sudo apt-get install nfs-kernel-server -y
sudo mkdir -p /mnt/cluster_storage
# /etc/exports に追加
/mnt/cluster_storage *(rw,sync,no_subtree_check,no_root_squash)

sudo exportfs -raを実行して設定を適用します。

2. プロビジョナーによるストレージの自動化

手動でPersistent Volume(永続ボリューム)を作成するのは面倒です。代わりに、**NFS Subdir External Provisioner**を使用します。これは、アプリがストレージを要求するたびに、USBメモリ上にフォルダを自動的に作成します。Helmを使用してインストールします:

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
    --set nfs.server=<MASTER_IP> \
    --set nfs.path=/mnt/cluster_storage \
    --set storageClass.name=nfs-client \
    --set storageClass.defaultClass=true

これで、PersistentVolumeClaimを要求するデプロイメントは、即座にその USBメモリ上のスペースを確保できるようになります。これにより、データベースやステートフルなアプリの実行が非常に簡単になります。

検証:稼働状態の維持

クラスターは稼働し続けてこそ意味があります。メモリが512MBしかないため、積極的に監視を行う必要があります。Prometheusのような重いツールは避け、代わりにターミナルベースのUIであるk9sを使用します。

1. テスト用ワークロードのデプロイ

3つのレプリカを持つNginxインスタンスをデプロイして、スケジューラーとストレージを検証します。test-nginx.yamlファイルを使用します:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: storage
          mountPath: /usr/share/nginx/html
      volumes:
      - name: storage
        persistentVolumeClaim:
          claimName: nginx-pvc

kubectl apply -f test-nginx.yamlを実行します。ステータスがRunningに変われば、ストレージのロジックは正常です。

2. リアルタイム・トラブルシューティング

ノードが故障したとき(必ず発生します)、kubectl get events -wを実行してください。これらの小さなRaspberry Piで最も一般的なエラーは**OOMKilled**(メモリ不足による強制終了)です。ノードが「フラッピング」(ReadyとNotReadyを繰り返す状態)を始めたら、すぐに負荷を確認してください:

kubectl top nodes

node-03が限界に達している場合は、Taint(汚れ)を付与して、重いPodが配置されないようにします。この物理ラボは、直感的な体験を提供してくれます。SSH接続が切れる直前に、Raspberry PiのLEDが激しく点滅するのを見ることができます。これは、システムの実際の限界を学ぶための素晴らしい方法です。

最後に

このクラスターは、処理能力を追求するためのものではありません。失敗しても時間以外のコストがかからない遊び場です。コンテナイメージの最適化や、仮想環境では存在しないネットワーク問題のデバッグ方法を学ぶことができます。150ドル以下で、現代のウェブを支えるインフラのミニチュア版を手に入れたのです。さあ、心置きなく何かを壊してみましょう。

Share: