前書き:憧れのラズパイクラスタ

Raspberry Piでスパコンを構築する取り組みは昔からありましたが、最近は「Kubernetesクラスタを作ったよ」という報告が増えてきました。私もラズパイ4(8GB)を一台購入してラズパイが合計4台となったのをキッカケに、憧れのラズパイクラスタに手を出してみました!

本記事では「導入手順(ネットワーク接続などのセットアップ説明は除く)」や「ハマったポイント」を紹介します。

クラスタ材料(ハード、ソフト)

機器・ソフト個数役割・備考
Raspberry Pi4台本記事ではRaspberry Pi 3(2台)、Pi 4(2台)を使用。クラスタのMasterはメモリ使用量が大きいので、Pi4(RAM4GB以上)がオススメ。
microSD4枚本記事では16GB〜64GBを使用。Class10、32GB以上がオススメ。16GBの場合、クラスタ構築が終わった段階で空き容量が不足するかもしれません。
LANケーブル5本本記事ではCat6aを使用。
4層ラックケース1個Raspberry Piを縦に積み上げるタイプのケース。ファンとヒートシンクも付いてきて、お得感があります。私は1層タイプのケースも予備で買いました。
USB Type A to TypeCX個Raspberry Pi4用の電源ケーブル。Pi4の数だけ必要。
microUSB to USB TypeAX個Raspberry Pi3用の電源ケーブル。Pi4の数だけ必要。
microHDMIケーブル1個Raspberry Pi4用の映像出力ケーブル。
HDMIケーブル1個Raspberry Pi3用の映像出力ケーブル。
無線LAN親機(小型)1個上流のルータに無線接続する時に使用しますが、有線接続の場合は不要。
スイッチングハブ1個Raspberry Pi 4台のLANと接続するスイッチングハブ。
USB充電器1個本記事では60W、6ポートのタイプを使用。
Raspberry Pi OS with Desktop1個Raspberry PiのOS。最終的にはデスクトップ環境は不要なので、Linuxが得意な人はLite版でも問題ありません。

上記のTweetでRaspberry Pi2を使ったと書いていますが、組み立て中にお亡くなりになっている事が判明したので、2から4に差し替えました。

Raspberry Piの基本的なセットアップと組み立て

Raspberry Piの基本的なセットアップおよび組み立て方法は、本記事では説明しません。想定している基本的なセットアップ内容を以下に示します。

Raspberry Piの基本的なセットアップ内容(以下は説明を省略します)

  • Raspberry Pi用のOSをmicroSDカードに書き込み
  • Raspberry Piを起動し、キーボードや時刻の設定
  • Raspberry Piを無線もしくは有線でネットワーク接続
  • Raspberry Piが使用できるmicroSDの領域を拡大
  • OSのアップデート

組み立てに関しては、説明書に図が多いため、1〜2時間で完了すると思われます。

全てのRaspberry Piを固定IP化

DHCP設定の場合、Raspberry Piの再起動に伴い、IPアドレスが変わってしまいます。この状態では、Host環境からRaspberry PiにSSH接続する際に不便ですので、IPアドレスを固定化します。

以下の記事を参考にIPアドレスを固定化します。SSH接続する際にIPアドレスが必須なので、メモしてください。

全てのRaspberry PiのHost名を変更

この手順は必須ではありません。SSH接続した際に、どのRaspberry Piにログインしているか(およびクラスタのMaster<->Slaveの関係)を分かりやすくするために、Host名を変更します。

Host名は、任意です。よく見られる命名規則は都市の名前、ディズニーキャラ名、太陽系の惑星名などを使用するケースです。私は、スラッシュメタル四天王(Big4)の名前を付けました。この名付けによって、ラズパイクラスタへの愛着が増します。

以下、Host名とRaspberry Piの組み合わせです。

機器Host名役割
Raspberry Pi4(8GB)metallicaラズパイクラスタのMaster
Raspberry Pi3 Model BmegadethラズパイクラスタのSlaveその1
Raspberry Pi3 Model BslayerラズパイクラスタのSlaveその2
Raspberry Pi4(2GB)anthraxラズパイクラスタのSlaveその3

Host名を変える際は、hostnamectlコマンドを使用します。hostnamectlコマンドだけでは、unknown hostエラーが出るため、/etc/hostsファイルも修正します。なお、/etc/hostsは、Host名とIPアドレスを対応させる役割を持つファイルです。

(注釈):Host環境からRaspberry PiにSSH接続
# ssh pi@$(Raspberry PiのIPアドレス)

(注釈):ここからの手順はRaspberry Pi上で実施
$ sudo hostnamectl set-hostname $(任意のHost名)
$ sudo vi /etc/hosts
(注釈) 以下の記述(ファイル末尾)を変更する。

※変更前
127.0.1.1     raspberrypi

※変更後
127.0.1.1     $(任意のHost名)

上記の手順を全てのRaspberry Piに実行したら、"$ sudo reboot"などで再起動します。

Raspberry Piに新規ユーザを追加し、piユーザを削除

Raspberry Piのデフォルトユーザ(piユーザ)は、パスワードが知れ渡っているため、セキュリティリスクがあります。そのため、新規ユーザ(任意のユーザ名)を作成し、piユーザを削除します。

SSH接続設定(セキュリティ対策含む)

デフォルト設定では、Raspberry PiはSSHが無効化されています。

SSHを有効化するには、Raspberry Piの/bootディレクトリにsshファイル(空ファイル)を置くか、もしくは以下のコマンドをRaspberry Pi上で実行してください。

$ sudo raspi-config
※ Raspberry Pi Software Configuration Tooki(raspi-config)画面で、以下の順番で選択

[5 Interfacing Options]
 ⇓
[P2 SSH]
 ⇓
[SSHを有効化するかどうかの質問に対して"Yes"]

デフォルトのSSH接続設定は脆弱なので、以下の記事を参考にセキュリティ対策を実施してください。

Dockerのインストール

ここまでの手順を実施すれば、Kubernetesのインストールまであと一歩です。

DockerとDocker Composeをインストールしますので、別記事を参照してください。

Kubernetesのインストール

ここまでの手順で、Kubernetesインストールのための前準備が完了しました。以降の手順は、(ようやく)Kuberbetesの環境構築となります。

まずは、Kubernetes用パッケージマネージャであるHelmをインストールします。インストールスクリプトを利用した以下の手順は私の環境で失敗したので、後述するsnapパッケージマネージャを利用して入れました。

※ !!! 注意:以下の手順は失敗する可能性があるため、参考情報としてみてください !!!

※ Helmインストールスクリプトの取得
$  curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
$ ls
get_helm.sh

※ 実行権限の付与
$ chmod a+x get_helm.sh

※ インストールの実行
$ ./get_helm.sh 
Downloading https://get.helm.sh/helm-v3.3.0-linux-arm64.tar.gz
tar: linux-arm64/helm: Wrote only 3072 of 10240 bytes
tar: linux-arm64/LICENSE: Cannot write: No space left on device  ※ 容量は足りているが、本エラーが出る。
tar: Exiting with failure status due to previous errors
Failed to install helm
	For support, go to https://github.com/helm/helm.

snapパッケージマネージャを利用したHelmインストール手順は、以下の通りです。

$ sudo apt update
$ sudo apt install snapd
$ sudo reboot
$ sudo snap install helm --classic

次に、Kubernetesクラスタの構築に用いるkubeadmin(クラスタ起動コマンド)、KubernetesをCLIで操作するkubectl、Pod管理エージェントのkubelet(Podやコンテナを起動するコンポーネント)をインストールします(公式サイトの手順もリンクしておきます)。

インストール前にレガシー版のiptablesに関する設定を行います。2020年にRaspberry Pi OS(正確にはDebian10以降)は、iptablesは内部的にnftablesを使用しており、nftablesとkubeadminに互換性がない問題があります。この問題を回避するために、iptablesをレガシーモードで使用します。

(注釈) レガシーツールをインストールする
$ 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

kubeadmin、kubectl、kubeletをインストールします。また、これらのパッケージはapt-markコマンドを用いて、パッケージ更新対象外とします。

(注釈) 依存パッケージのインストール
$ sudo apt update
$ sudo apt install -y apt-transport-https curl

(注釈) kubernetesの公開鍵を追加
$ 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

Masterノードの構築

CNI(コンテナネットワーキング)プラグインは、Flannelを使用します。

(注釈) Flannelの場合、10.244.0.0/16を指定する。
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16

kubeadm initを実行後、kubectlの設定方法が出力されるので、その内容を順に実行します。また、kubeadm joinに関する設定方法も出力されるので、そちらもメモしておきます(私はメモを無くしてしまいました…)。

(注釈) kubectlの設定
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

Pod Network Addonをインストールします。

$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml

Workerノードの構築

今回はWorkerノードが3台あるため、その3台に対して以下の手順を実行し、Workerノードをクラスタに参加させます。

入力するコマンドは、Masterノードkubeadm initコマンド実行後に表示されたkubeadm joinコマンドです。

(注釈) 環境によって入力するコマンドが異なる。
$ sudo kubeadm join 192.168.13.2:6443 --token vpmuze.ina6swjhlxh57lds --discovery-token-ca-cert-hash sha256:fcda1034ebb1374f0a0b487cd349b29ac1c253e83e6344b4d567cf61123a509c

全てのWorkerノードがクラスタに参加した後、"$ kubectl get nodes"で各ノードのステータスを確認できます。STATUS部分がREADY以外の場合は、上手く設定できていない可能性があります。

最後に

Kubernetesクラスタ環境構築は面倒くさい部類であり、一日近くの時間を要します。

さらに、特に動かしたいDockerコンテナアプリがない場合は、「ここから先、どうすればいいんだ?」と手が止まります。少なくとも私は、何も考えずに作ったクラスタの使い道に困っています。

ハード購入費用もそこそこするので、よく考えてから手を出しましょう(戒め)。