Raspberry pi 3B+ 3台でkubernetesクラスタを構築したメモ (2019年8月版)
用意したパーツ
- Raspberry Pi 3B+ × 3
- 16GB MicroSDメモリーカード × 3
- Ethernetケーブル × 3
- USB充電ケーブル × 4
- スイッチングハブ(LAN-SW05PSWE) × 1 ※USBケーブルで給電できるタイプ
- RAVPower USB充電器 (60W 6ポート) × 1
- 4層のラズパイスタックケース × 1
- 外付けUSBケースに入れた128GB SSD
- モニタ
- HDMIケーブル
- USBキーボード
はじめに
勉強用に複数台のラズパイを使ってk8sのクラスタを作りたく、過去にもチャレンジしていたのですが、最近ふとHypriot OSが1.11.0となってDockerのバージョンも上がっているのを見つけて、どうせならとKubernetes自体も最新バージョンで再構築してみました。
OSイメージの準備
当方Windows PCで作業していますので、ラズパイOSイメージの書き込みはWin32DiskImagerとUSB接続のSDカードリーダ・ライタを使用しています。
hypriot OSの公式サイトからダウンロードしたイメージをSDカードに書き込んだ後、再度PCに接続します。
ルートディレクトにあるuser-data
を編集し、ホスト名など変更が必要な箇所を修正します。
マスターとする1台に対してはWiFiの有効化も一緒に実施してしまうと楽なので、こちらを参考に以下のように編集します。
#cloud-config
# vim: syntax=yaml
#
# Set your hostname here, the manage_etc_hosts will update the hosts file entries as well
hostname: rpi-k8s-1
manage_etc_hosts: true
# You could modify this for your own user information
users:
- name: pirate
gecos: "Hypriot Pirate"
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
groups: users,docker,video,input
plain_text_passwd: hypriot
lock_passwd: false
ssh_pwauth: true
chpasswd: { expire: false }
# # Set the locale of the system
# locale: "en_US.UTF-8"
# # Set the timezone
# # Value of 'timezone' must exist in /usr/share/zoneinfo
# timezone: "America/Los_Angeles"
# # Update apt packages on first boot
# package_update: true
# package_upgrade: true
# package_reboot_if_required: true
package_upgrade: false
# # Install any additional apt packages you need here
# packages:
# - ntp
# WiFi connect to HotSpot
# - use `wpa_passphrase SSID PASSWORD` to encrypt the psk
write_files:
- content: |
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
path: /etc/network/interfaces.d/wlan0
- content: |
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="YOUR_SSID"
psk="YOUR_PSK"
key_mgmt=WPA-PSK
}
path: /etc/wpa_supplicant/wpa_supplicant.conf
# These commands will be ran once on first boot only
runcmd:
# Pickup the hostname changes
- 'systemctl restart avahi-daemon'
# Activate WiFi interface
- 'ifup wlan0'
残りのノード用はホスト名の部分だけrpi-k8s-2
,rpi-k8s-3
・・・といった変更をしてSDカードに書き込みます。
マスターの起動
マスターとするラズパイにWiFi有効化の設定を実施したSDカードを挿入し、OSを起動します。まだリモートからログインできないので、ラズパイに直接モニター、キーボードを接続して作業してください。
ネットワーク回りの設定
マスターとするラズパイとノードとなる他のラズパイは以下のようなネットワークで構成することとします。
SSHの有効化
sudo raspi-config
でSSHをenableするか、sudo touch /boot/ssh
などを実施し、リブートします。
WiFi設定
最初のOSイメージを準備したときにuser-data
で設定済みの場合、/etc/wpa_supplicant/wpa_supplicant.conf
には無線LANルータ接続に必要なSSIDとPSKがされているはずです。
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP
network={
scan_ssid=1
ssid="YOUR_SSID"
psk="YOUR_PSK"
key_mgmt=WPA-PSK
}
SSHログイン用にIPアドレスを固定にします。
/etc/network/interfaces.d/wlan0
を編集し、ご自身のネットワークに合わせて適切な固定IPアドレスを設定します。
allow-hotplug wlan0
#iface wlan0 inet dhcp
iface wlan0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
設定が終わったらリブートし、192.168.1.100からSSHで入れるかを確認します。ログインできましたら、この先の作業はリモートから行っても良いかと思います。
k8sクラスタで使用するローカルネットワークの設定
マスターがk8sノードに対してIPアドレスを自動で割り当てられるよう、DHCPサーバ(isc-dhcp-server)をインストールします。事前にapt-get update
とapt-get upgrade
を実行しておいてください。
isc-dhcp-serverのインストール
インストールは以下のコマンドで行います。インストール直後はエラーになって立ち上がらない状態になりますが、以降の設定で解消されるようにしていきます。
sudo apt-get install isc-dhcp-server
isc-dhcp-serverの設定
/etc/default/isc-dhcp-server
を編集し、INTERFACESV4の欄に有線LAN(eth0)を追加します。
# Defaults for isc-dhcp-server (sourced by /etc/init.d/isc-dhcp-server)
# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
#DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
#DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf
# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
#DHCPDv4_PID=/var/run/dhcpd.pid
#DHCPDv6_PID=/var/run/dhcpd6.pid
# Additional options to start dhcpd with.
# Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
#OPTIONS=""
# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
# Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACESv4="eth0" ★v4のインターフェースとしてeth0を追加
INTERFACESv6=""
有線LANポートのIPアドレスを固定
/etc/network/interfaces.d/eth0
を編集し、10.0.0.1のIPアドレスで固定されるよう変更します。
allow-hotplug eth0
iface eth0 inet static
address 10.0.0.1
netmask 255.255.255.0
broadcast 10.0.0.255
gateway 10.0.0.1
サブネット設定
/etc/dhcp/dhcpd.conf
を以下のように編集し、DHCPサーバを設定します。
# dhcpd.conf
#
# Sample configuration file for ISC dhcpd
#
# option definitions common to all supported networks...
option domain-name "cluster.home"; ★任意のドメイン名を指定
#option domain-name-servers ns1.example.org, ns2.example.org;
option domain-name-servers 192.168.1.1; ★ネットワークに合わせてDNSサーバを指定
subnet 10.0.0.0 netmask 255.255.255.0 { ★10.0.0.x系でサブネット設定
range 10.0.0.1 10.0.0.10;
option subnet-mask 255.255.255.0;
option broadcast-address 10.0.0.255;
option routers 10.0.0.1;
}
default-lease-time 600;
max-lease-time 7200;
# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative; ★コメントをはずす
・・・以下略
この時点でリブートするとDHCPサーバのエラーは解消されて問題なく立ち上がると思います。
WiFi経由でインターネット接続するための設定
ローカルネットワーク側に接続した機器(あとで増設するk8sノードなど)がインターネットと通信できるよう、以下の設定をします。
-
WiFi側とローカルネットワーク側の優先順位を変更
/etc/dhcpcd.conf
に以下の内容を追加し、WiFi側を優先にします。# set priority interface eth0 metric 1 interface wlan0 metric 0
-
IPフォワーディングの有効化
/etc/sysctl.conf
にある以下の行がコメントアウトされているので有効化します。# Uncomment the next line to enable packet forwarding for IPv4 #net.ipv4.ip_forward=1 ★コメントをはずす
-
iptables-persistentのインストール
再起動してもルールが残るように、iptables-persistentをインストールします。sudo apt-get -y install iptables-persistent
インストール後、現在のルールを保存しますか?というメッセージが出てきたら、Yesを選択して、ルールファイルを作っておきます。
-
ルールの追加
以下のコマンドを実行し、eth0からwlan0(その逆も)へフォワードされるよう、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 iptables-save | sudo tee -a /etc/iptables/rules.v4 > /dev/null
Kubernetesのインストール
マスターへのk8sのインストールとノードの追加に関しては、ラズパイでKubernetesを動かして見たら、驚いた!の記事を参考に一通り実施しました。
apt-cache madison kubeadm
を実行し、利用できるバージョンを調べます。本記事の執筆時点では1.15.2が最新(kubernetes-cniは0.7.5)でしたので、それをインストールします。
sudo su -
apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install kubelet=1.15.2-00 kubeadm=1.15.2-00 kubectl=1.15.2-00 kubernetes-cni=0.7.5-00
参考にさせていただいたサイトにはKUBELET_DNS_ARGSの設定を変更する説明があったのですが、該当のファイルに設定項目がなかったため、とりあえずスキップしています。
kubeletを再起動します。
systemctl daemon-reload && systemctl restart kubelet
参考サイトにならって、マスターノードの初期化を行います。
kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.1.100 --service-cidr=10.244.0.0/16
結構時間がかかりますが、しばらくすると初期化成功のメッセージが出ます。メッセージ内の指示通り、スパーユーザから一般ユーザに戻って以下の3行を実行します。このときにノード追加用のコマンドラインも出力されるため、メッセージは保存しておくことをオススメします。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
ポッド・ネットワークの作成についても参考サイトの通り実行するのですが、flannelのバージョンは0.11.0が最新でしたのでそちらを使います。中身の置換はオライリー本に従って以下のコマンドで書き換えます。
curl https://raw.githubusercontent.com/coreos/flannel/v0.11.0/Documentation/kube-flannel.yml | sed "s/amd64/arm/g" | sed "s/vxlan/host-gw/g" > kube-flannel-arm.yml
ymlファイルができたら、以下のコマンドで適用します。
kubectl apply -f kube-flannel-arm.yml
マスターがReady状態になったときのコマンド結果が若干違っていたので、自分が実行した際の出力結果を参考に載せておきます。
$ kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5c98db65d4-vb8jk 1/1 Running 0 92m
coredns-5c98db65d4-xpx9r 1/1 Running 0 92m
etcd-rpi-k8s-1 1/1 Running 0 92m
kube-apiserver-rpi-k8s-1 1/1 Running 0 92m
kube-controller-manager-rpi-k8s-1 1/1 Running 0 92m
kube-flannel-ds-arm-x4lqb 1/1 Running 0 3m45s
kube-proxy-k2x9x 1/1 Running 0 92m
kube-scheduler-rpi-k8s-1 1/1 Running 0 92m
$ kubectl get node
NAME STATUS ROLES AGE VERSION
rpi-k8s-1 Ready master 93m v1.15.2
以上でマスタの設定は完了です。
flannelのpodがErrorとなって解消されないとき
マスターをリセットしたときに同じ手順でポッド・ネットワークを構築しても、flannelのpodがError→CrashLoopBackOffのループに入ってしまうことがありました。
kubeadm reset
→kubeadm init
で解消されなかったので、kubenetesを一旦アンインストールして再インストールしたところ、事象は解消されました。
apt-get remove --purge kubelet=1.15.2-00 kubeadm=1.15.2-00 kubectl=1.15.2-00 kubernetes-cni=0.7.5-00
リセットだけだとifconfigで表示される中にflannelの設定が残っていたのが気になりましたが、原因を調べるのが大変そうだったので、根本解決ではありませんが再インストールで回避しました。
※2019/08/18追記
flannelのインターフェイスが残っていることの言及や対処方法については、参考サイトにありますRaspberry PiでおうちKubernetes構築【論理編】に書かれていますので参考にしてください。
ノードの追加
ノードの起動と初期設定
ノード用にuser-data
を編集したOSイメージ(SDカード)を挿入して起動すれば、10.0.0.x系に組み込まれて起動されるはずです。初期状態ではSSHログインなどができないため、モニターとキーボードを繋いで作業しますが、ついでにk8sノードとしての設定も行ってしまいます。
-
SSHの有効化
sudo touch /boot/ssh
-
k8sパッケージのインストール
apt-get install kubelet=1.15.2-00 kubeadm=1.15.2-00 kubectl=1.15.2-00 kubernetes-cni=0.7.5-00
-
kubeletの再起動
systemctl daemon-reload && systemctl restart kubelet
マスターでkubeadm init・・・
を実行したときにメッセージに出力されたkubeadm join・・・
を各ノードで実行していきます。
マスターをリセットする場合は子ノードもリセットが必要なので忘れないようにしてください。
確認
ノード側でのコマンド実行が完了したら、マスター上で稼働状態を確認します。
$ kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5c98db65d4-vb8jk 1/1 Running 0 8h
coredns-5c98db65d4-xpx9r 1/1 Running 0 8h
etcd-rpi-k8s-1 1/1 Running 0 8h
kube-apiserver-rpi-k8s-1 1/1 Running 0 8h
kube-controller-manager-rpi-k8s-1 1/1 Running 0 8h
kube-flannel-ds-arm-4b9dp 1/1 Running 2 6m52s
kube-flannel-ds-arm-mnmzr 1/1 Running 0 3m3s
kube-flannel-ds-arm-x4lqb 1/1 Running 0 6h59m
kube-proxy-k2x9x 1/1 Running 0 8h
kube-proxy-p8mzs 1/1 Running 0 6m52s
kube-proxy-rdr7z 1/1 Running 0 3m3s
kube-scheduler-rpi-k8s-1 1/1 Running 0 8h
$ kubectl get node
NAME STATUS ROLES AGE VERSION
rpi-k8s-1 Ready master 8h v1.15.2
rpi-k8s-2 Ready <none> 6m43s v1.15.2
rpi-k8s-3 Ready <none> 2m54s v1.15.2
以上でノードの追加も完了です。
最後に
ラズパイ上にKubernetesを構築するにあたっては、何度かバージョンの組み合わせなどでうまく動作しない状況に陥ったのですが、今回はうまくいったので「おうちKubernetes」を構築しようとお考えの方の参考になれば幸いです。
さて、こいつを使って何をしようか?というところを考えねば・・・。今後試したことで何か面白そうなことができましたらまた記事にしたいと思います。
参考リンク
本記事を書くにあたって参考にさせていただいたサイトや書籍を挙げさせていただきます。
- ラズパイでKubernetesを動かして見たら、驚いた!
- Raspberry PiでおうちKubernetes構築【論理編】
- オライリー「入門 Kubernetes」(Amazon)
- HypriotOS本家サイト https://blog.hypriot.com/
- Raspberry PI で NAT ルータを作る