お久しぶりです、もち256です。
昨今では半導体不足の影響もあり、Raspberry Pi(以後「ラズパイ」と呼称)が手に入らなくなっていますが、たまたま3台入手することができました。
なので、今回はラズパイ3台を使用した、k8sクラスタの構築方法を書いておこうと思います。
はじめに
Kubernetes(k8s)クラスタとは「複数のホストを使用して冗長化したクラスタを構築し、複数コンテナによって構成されたアプリを運用する」という仕組みです。
今回この仕組みを使って検証したいことがあったので、クラスタを構築することとしました。
用意したもの
今回k8sクラスタを構築するにあたり、下記のものを用意しました。
機器名 | 商品名 | 単価 | 個数 |
---|---|---|---|
ラズパイ | Raspberry Pi 4 Model B 8GB | 10,670 | 3 |
L2スイッチ | GS305-300JPS | 2,720 | 1 |
LANケーブル | LD-C6YT/BK05 | 470 | 4 |
ラズパイ ケース | RPI4-ACCASBK | 1,650 | 3 |
SDカード | SDSQUAR-032G-JN3MA | 3,031 | 3 |
ラズパイ 電源 | SSCI-056830 | 1,580 | 3 |
電源ケーブル | AVT-K6A-2650BK | 1,930 | 1 |
ラック | HC-19MB2S-3937 | 2,728 | 1 |
本 | 技術評論社 たった1日で基本が身に付く! Docker/Kubernetes超入門 | 2,838 | 1 |
画像には含まれていませんが、ラックはイオンで販売されていた食器の水切りラックを購入しました。
他、RaspberryPiは共立エレショップ、その他周辺機器はヨドバシ.comで購入しました。
機器の総額は、63,000円程度でした。
機器の準備
用意した機器を組み合わせます。
今回、作りたいラズパイのネットワークは、下記になります。
マスターノードを「m256-main」とし(以後「mainノード」と呼称)、他のワーカーノード(以後「subノード」と呼称)を「m256-sub」としています。
また、mainノードはIPマスカレードの設定を行い、subノードはNATを使用してWANへ接続します。
ラズパイにケースを装着すると、こんな感じになります(かっこいい)。
最終的にラックを使用して、こんな感じで配置しています。
使用しない時は延長用電源ケーブルも収納できて便利です。
Raspberry Pi OSのインストール
さて、ここからが各端末の設定になります。
まずは、ラズパイにOSをインストールします。
OSのインストールは、Raspberry Pi Imagerを使用して、SDカードに焼いていきます。
今回はGUIを使用する予定がないため、OSは「Raspberry Pi OS Lite (64-bit)」を使用します。
また、インストールを行う時点でsshやWi-Fiの設定を行います。
この作業によって、ディスプレイを使用せずにラズパイへ接続を行い、設定を完了することができるようになります。
「m256-main」など、ホスト名もこの設定画面で設定を行えます。
この作業を完了後、ラズパイの電源を付けると、インストール時に登録したWi-Fiへ接続されます。
自分はこの時、ルーターの設定画面から各ラズパイのIPアドレスを特定し、sshを行いました。
各ノードの設定
ここからが各ラズパイの設定になります。
まずはapt updateを行います。
sudo apt -y update
sudo apt -y upgrade
次に、sudoを使用する際にパスワードを毎回入力するのも面倒なので、visudoの設定を行います。
sudo visudo
# 下記の行を追加する
# ------------------------------------
# pi ALL=(ALL:ALL) NOPASSWD:ALL
また、任意で強固なパスワードに変更しておきます。
sudo passwd pi
そして、sshの認証方式をパスワード方式から、公開鍵認証方式に変更します。
下記のコマンドは、mainノードでのみ行いました。
cd ~/.ssh
# 公開鍵の生成
ssh-keygen -t rsa -b 4096 -C "" -f m256-sub.id_rsa
ssh-copy-id -i ~/.ssh/m256-sub.id_rsa.pub pi@m256-sub1
ssh-copy-id -i ~/.ssh/m256-sub.id_rsa.pub pi@m256-sub2
vim ~/.ssh/config
# 下記の行を追加する
# ----------------------------------
# Host m256-sub1
# HostName m256-sub1
# User pi
# IdentityFile /home/pi/.ssh/m256-sub.id_rsa
#
# Host m256-sub2
# HostName m256-sub2
# User pi
# IdentityFile /home/pi/.ssh/m256-sub.id_rsa
最後に、subノードでパスワード認証方式を不許可に設定し、初期設定は終了です。
mainノードの公開鍵を生成した場合は、mainノードで下記の設定を行っても良いです。
sudo vi /etc/ssh/sshd_config
# 下記の行を追加する
# ----------------------------------
# PasswordAuthentication no
sudo systemctl restart sshd
IPアドレスの固定化
ラズパイ同士のネットワークを作るため、まずはスイッチに接続されているインターフェースのIPアドレスを静的に設定します。
設定を書き換えるため、適当にエディタをインストールします。
sudo apt -y install vim
IPアドレスは「dhcpcd.conf」に設定を行います。
sudo vim /etc/dhcpcd.conf
mainノードには下記の設定をしました。
interface eth0
static ip_address=10.4.28.1/24
subノードには下記ような設定を行います。
「ip_address」は適宜変更を行い、「routers」はmainノードを設定します。
interface eth0
static ip_address=10.4.28.11/24
static routers=10.4.28.1
static domain_name_servers=8.8.8.8
また、全てのホストの「/etc/hosts」に下記の内容を記載し、ドメインを解決できるようにします。
10.4.28.1 m256-main
10.4.28.11 m256-sub1
10.4.28.12 m256-sub2
ここまでで、各ノードのIPアドレスが固定化できました。
IPマスカレードの設定
ここからは、mainノードにIPマスカレードの設定を行い、subノードの通信をmainノードを経由して行うようにします。
下記のコマンドをmainノードで実行します。
sudo vim /etc/sysctl.conf
# "net.ipv4.ip_forward=1"のコメントを外す
また、/proc配下の「ip_forward」にも設定を行います。
sudo su -
echo -n 1 > /proc/sys/net/ipv4/ip_forward
reboot
そして、iptablesの設定を行い、iptables-persistentを使用して設定を永続化します。
sudo apt -y install iptables
sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
sudo iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT
sudo apt -y install iptables-persistent
# インストール時、現在のネットワーク設定を保存するか聞かれるので"YES"を選択する
# または、インストール後に"netfilter-persistant save"のコマンドを実行する
sudo systemctl enable netfilter-persistent
最後に、subノードからNATの機能が有効になっているか確認します。
# Wi-Fiの切断
sudo ifconfig wlan0 down
# 下記2つのコマンドが実行できればmainノードのIPマスカレード設定が完了している
ping 8.8.8.8
host mochi256.com
# subノードでWi-Fi設定を読み込まないようにする
sudo mv /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf.bak
ここまでで、IPマスカレードの設定は完了です。
k8sクラスタの設定
ここからが本題のk8sクラスタの設定になります。
まず、これから使用する「kubeadm」コマンドで、swapが有効だとエラーが発生するため、swapの無効化を全てのノードで行います。
sudo dphys-swapfile swapoff
sudo systemctl stop dphys-swapfile
sudo systemctl disable dphys-swapfile
次に、全てのノードでdockerをインストールします。
dockerのバージョンは固定化しておき、piユーザーにdockerの実行権限を与えます。
sudo apt -y install docker docker-compose
sudo apt-mark hold docker docker-compose
sudo usermod -aG docker pi
そして、全てのノードに「kubelet, kubeadm, kubectl」のコマンドをインストールします。
sudo bash -c "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -"
sudo bash -c "echo 'deb https://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list"
sudo apt -y update
sudo apt -y install kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# ラズパイ起動時の設定を行う
sudo vim /boot/cmdline.txt
# "cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory"を追記する
sudo reboot
mainノードの設定
下記のコマンドで、mainノードの設定を行います。
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
このコマンド終了後「You can now join any number of machines by running the following on each node as root:」という、他のノードが参加するためのコマンドが出力されるので、内容をメモしておきます。
また、他にも設定を行うための指示が出力されるので、コマンドを実行します。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
ここまで実行すると、下記のコマンドでノードの状態を確認できるようになります。
ただし、今の状態だとSTATUSが「NotReady」となります。
kubectl get node
# ------------------------------------------------
# NAME STATUS ROLES AGE VERSION
# m256-main NotReady control-plane,master 3m57s v1.23.4
状態を有効にするため、CNIプラグインのFlannelをインストールします。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
インストールに成功すると、STATUSが「Ready」になります。
subノードの追加
最後に、mainノードに他ノードの追加を行います。
mainノードの設定時、他のノードが参加するためのコマンドが表示されているので、それを実行するのみです。
下記のコマンドは、subノードで実行します。
kubeadm join <Kubernetes APIのアドレス>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
# もしコマンドをメモし忘れている場合は、mainノードで下記のコマンドを実行すると、tokenとhashの値を取得できる
# ---------------------------------------------------------------
# token ⇒ $ kubeadm token list
# hash ⇒ $ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
k8sクラスタの状態確認
最後に、mainノードで下記のコマンドを実行し、クラスタが作成されていれば完了です。
kubectl get node
# ------------------------------------------------
# NAME STATUS OLES AGE VERSION
# m256-main Ready control-plane,master 30m v1.23.4
# m256-sub1 Ready <none> 92s v1.23.4
# m256-sub2 Ready <none> 100s v1.23.4
おわりに
今回は、k8sクラスタの作成方法のみを記事にしました。
せっかく作ったので、今後何か良さそうな運用方法があれば、ブログに書いてみようと思います。
今回は以上になります。
ここまで読んでいただき、ありがとうございました!
参考文献
- Raspberry Pi×4台によるKubernetesクラスター構築
- Raspberry Pi 上に Kubernetes クラスタを作る
- ラズパイでKubernetesクラスタを構築する
- ラズパイをルーター化する(NAT超えWake on LAN[4])
- iptablesの設定と設定の永続化
- How to Forget a Saved Wi-Fi Network on Your Raspberry Pi
- Kubernetes v1.17 から kubeadm token list で -o が指定できるようになった