えんじにあメモ

試してみた技術とか、たまに家電ネタ

Raspberry Pi 4 でおうちk8sクラスタを構築する

概要

だいたいこの手の構築手順はいろいろな方がまとめられてますが、自分がやった作業の備忘録も兼ねてまとめておきます

構成はmaster×1、worker×2として、raspberry piを3台使って作ります

物理構築

物理的な構築は以下の記事とほぼ同じ手順でやりました qiita.com

また、ルータの設定については以下記事と同じ手順で行っています qiita.com この記事自体がだいたい↑これと同じ手順となるのでコレだけ読めば良い説

完成した様子がこちら(良い良い) f:id:shosfs:20200125124454j:plain

Raspberry Pi 4で」というタイトルになってますが、もともとRaspberry Pi 3(Model 3+)を持っていたのでMasterNodeには3を使おうと思います
(下から3番目のラズパイが3)

今回のクラスタ構成のために買ったものを以下にまとめておきます

もの 製品
ラズパイ Raspberry Pi 4 Model B 2
ケース 積層式ケース for Raspberry Pi 4 / Pi 3 Model B+ 1
SDカード KEXIN MicroSDカード UHS-I Class10 SDHC 16GB(3個セット) 3枚
USD充電器 AUKEY USB充電器 50W/10A ACアダプター 5ポート 1
LANケーブル(15cm) エレコム LANケーブル 0.15m×2本 3本(1本は余ってる)
LANケーブル(30cm) TWS-63BK [スリムLANケーブル CAT.6 0.3m 黒] 1
USBケーブル(type-c) USB C ケーブル 30cm SUNGUY 【2本セット0.3m】 2本
スイッチングハブ TP-Link 5ポート スイッチングハブ 1
無線ルータ BUFFALO 無線LAN親機 WMR-433W2-BK 1
  • スイッチングハブは他記事などではよくこちらの商品が使われていて、自分も最初使いましたが、ネットワークがよく途切れるので買い替えました
    • TP-Linkだと電源が必要になりサイズも大きくなりましたが、サイズ的にはケース下のネジが挟まれるようになってちょうど良いサイズだった
  • LANケーブルはすべて15cmでもつなげられるが、ケース最上段に置く無線ルータへはギリギリでケーブルに負荷がかかるため30cmのほうがおすすめ

論理構築

全台共通

https://www.raspberrypi.org/downloads/raspbian/ からOSイメージをダウンロード

今回はk8sクラスタ用でdesktopは不要なのでRaspbian Buster Liteを選びました f:id:shosfs:20200125122401p:plain

他の記事などではddコマンドなどを利用してSDへイメージを書き込んでいますが、自分は balenaEtcher というアプリケーションを利用して書き込みました(弱い)

Select imageに解凍したimgファイル、Select targetに対象のSDを選択して"Flash!"を実行します f:id:shosfs:20200125122910p:plain

書き込みには少し時間かかるのでお茶でも飲みながら待ちましょう

書き込みが完了したらsshdとcgroupsの設定のために以下を実行します(SDカードに対して)

$ cd /Volumes/boot
$ touch ssh

cmdline.txtの末尾にcgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1を追記

$ cd /Volumes/boot
$ cat cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=6c586e13-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

SDをラズパイにセットして電源を入れます

arp -aをラズパイと同じLANに繋がれたPC(自分はmac使ってる)から実行してラズパイのIPを調べます

$ arp -a
? (192.168.13.1) at 18:c2:bf:ea:d5:9a on en1 ifscope [ethernet]
? (192.168.13.2) at dc:a6:32:6e:d6:92 on en1 ifscope [ethernet]
...

192.168.13.1はルータのIPなので、192.168.13.2の方っぽいです

sshで入ってみます

$ ssh pi@192.168.13.2

piユーザの初期パスワードはraspberryです

pi@raspberrypi:~ $

無事ログインできました
piユーザ/rootユーザのパスワードを変えておきましょう

$ passwd
$ sudo passwd

作業用のユーザを作成します(パスワード設定も)

$ sudo useradd --groups adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,spi,i2c,gpio -m sminamot
$ sudo passwd sminamot

最後にpiユーザを無効化しておきます

$ sudo passwd --lock pi

コレ以降は作ったユーザで作業を進めます

$ ssh sminamot@192.168.13.2

初期設定

$ sudo raspi-config
  • 4 Localisation Options -> I1 Change Locale
    • en_GB.UTF-8 UTF-8のチェックを外す
    • en_US.UTF-8 UTF-8にチェックを入れる
    • OKを押したあとに聞かれるDefault localeをen_US.UTF-8にする
  • 4 Localisation Options -> I2 Change Timezone
    • Asia -> Tokyo
  • 8 Update

ラズパイ自体のアップデートも行います

$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt dist-upgrade
$ sudo rpi-update

設定書き換えなどのためにvimを入れておきます

$ sudo apt-get install vim -y

次にIPの固定化を行います
設定内容は以下のとおり(hostnameの設定は後ほど)

Node IP hostname
master 192.168.13.101 raspberrypi-master
node1 192.168.13.102 raspberrypi-node01
node2 192.168.13.103 raspberrypi-node02

/etc/dhcpcd.confに以下を追記します(それぞれのNodeに合わせて設定値を変える)

interface eth0
static ip_address=192.168.13.101/24
static routers=192.168.13.1
static domain_name_servers=192.168.13.1 8.8.8.8

反映します

$ sudo service dhcpcd reload

固定したIPでログインができることを確認しておきましょう

$ ssh sminamot@192.168.13.101

SSHの設定をしてパスワードログインはできないようにしておきます

$ sudo vim /etc/ssh/sshd_config
- #PermitRootLogin prohibit-password
+ PermitRootLogin no
- #PubkeyAuthentication yes
+ PubkeyAuthentication yes
- #PasswordAuthentication yes
- #PermitEmptyPasswords no
+ PasswordAuthentication no
+ PermitEmptyPasswords no
- UsePAM yes
+ UsePAM no

手元のmacから公開鍵を書き込んでおきます(ここでは公開鍵は事前に作成してあるものを利用する)

$ ssh-copy-id -i ~/.ssh/id_rsa_raspberrypi sminamot@192.168.13.101

公開鍵の登録が完了したらsshの再起動を行います

$ sudo systemctl restart ssh

※ 手元のmacから秘密鍵を利用したログインができることを確認しておきましょう

iptablesのバージョン更新
コレをやっておかないとk8s構築した際にPodから他Podや外部への通信がうまくできません

$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy

swapの無効化もしておきます(しておかないとk8sインストール時に失敗します)

$ sudo dphys-swapfile swapoff
$ sudo systemctl stop dphys-swapfile
$ sudo systemctl disable dphys-swapfile

続いてhost名の設定 /etc/hostnameを更新します(それぞれのNodeに合わせて設定値を変える)

$ cat /etc/hostname
raspberrypi-master

/etc/hostsも修正します(それぞれのNodeに合わせて設定値を変える)

127.0.0.1       localhost
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

-127.0.1.1       raspberrypi
+127.0.1.1       raspberrypi-master

ここまでの作業ができたらラズパイを再起動しましょう

$ sudo reboot

パッケージインストール

ここからk8sクラスタ構築に必要なパッケージをインストールしていきます

まずはDocker

$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common -y
$ curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
$ echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
     $(lsb_release -cs) stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list
$ sudo apt-get update
$ sudo apt-get install docker-ce -y
Errors were encountered while processing:
 aufs-dkms
E: Sub-process /usr/bin/dpkg returned an error code (1)

インストール中に上記のエラーで失敗した場合、以下を実行してから再度インストールを行います

$ sudo rm /var/lib/dpkg/info/aufs-dkms.postinst
$ sudo rm /var/lib/dpkg/info/aufs-dkms.prerm
$ sudo dpkg --configure aufs-dkms

# 再度インストール
$ sudo apt-get install docker-ce -y

インストールされたことを確認します

 $ sudo docker version
Client: Docker Engine - Community
 Version:           19.03.5
 API version:       1.40
 Go version:        go1.12.12
 Git commit:        633a0ea
 Built:             Wed Nov 13 07:37:22 2019
 OS/Arch:           linux/arm
 Experimental:      false

Server: Docker Engine - Community
...

続いてkubernetes

$ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg|sudo apt-key add -
$ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kube.list
$ sudo apt-get update
$ sudo apt-get install kubelet kubeadm kubectl -y

インストールされたことを確認します

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.2", GitCommit:"59603c6e503c87169aea6106f57b9f242f64df89", GitTreeState:"clean", BuildDate:"2020-01-18T23:30:10Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/arm"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

ここまではラズパイ3台ともに共通(一部Nodeに合わせて設定を分ける部分もある)で行っておきます

ここからはMaster/Workerノードに分けた設定を行っていきます

Master

$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16

コンソールに出力されたコマンドを実行します

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

また、同じくコンソールに出力されたkubeadm join 192.168.13.101:6443 --token XXXはWorkerのセットアップ時に実行するためメモっておく

続いてネットワークプラグインをインストールします

Raspberry Piはarmプロセッサのため、armにも対応したFlannelを利用します
Creating a single control-plane cluster with kubeadm - Kubernetes

Flannelのタブに記載されているコマンドを実行します

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

Podのが正しく稼働していることを確認しておきましょう

$ kubectl get po -n kube-system -o wide
NAME                                         READY   STATUS    RESTARTS   AGE     IP               NODE                 NOMINATED NODE   READINESS GATES
coredns-6955765f44-qrq2s                     1/1     Running   0          13m     10.244.0.3       raspberrypi-master   <none>           <none>
coredns-6955765f44-xhqzt                     1/1     Running   0          13m     10.244.0.2       raspberrypi-master   <none>           <none>
etcd-raspberrypi-master                      1/1     Running   0          13m     192.168.13.101   raspberrypi-master   <none>           <none>
kube-apiserver-raspberrypi-master            1/1     Running   0          13m     192.168.13.101   raspberrypi-master   <none>           <none>
kube-controller-manager-raspberrypi-master   1/1     Running   1          13m     192.168.13.101   raspberrypi-master   <none>           <none>
kube-flannel-ds-arm-gwcv9                    1/1     Running   0          2m39s   192.168.13.101   raspberrypi-master   <none>           <none>
kube-proxy-lg4qn                             1/1     Running   0          13m     192.168.13.101   raspberrypi-master   <none>           <none>
kube-scheduler-raspberrypi-master            1/1     Running   1          13m     192.168.13.101   raspberrypi-master   <none>           <none>

Worker

先ほどメモった、Masterのkubeadm init実行の際に出力されたコマンドを実行します

$ sudo kubeadm join 192.168.13.101:6443 --token XXX \
>     --discovery-token-ca-cert-hash sha256:XXX

確認

workerが追加されたことを確認します

$ kubectl get nodes
NAME                 STATUS   ROLES    AGE     VERSION
raspberrypi-master   Ready    master   21m     v1.17.2
raspberrypi-node01   Ready    <none>   3m40s   v1.17.2
raspberrypi-node02   Ready    <none>   3m38s   v1.17.2

worker nodeにラベルを付けておきます

$ kubectl label node raspberrypi-node01 node-role.kubernetes.io/worker=worker
$ kubectl label node raspberrypi-node02 node-role.kubernetes.io/worker=worker

# 確認
$ kubectl get nodes
NAME                 STATUS   ROLES    AGE     VERSION
raspberrypi-master   Ready    master   25m     v1.17.2
raspberrypi-node01   Ready    worker   7m40s   v1.17.2
raspberrypi-node02   Ready    worker   7m38s   v1.17.2

OK!!

Macのkubectlを利用する

k8sの操作をMac上から行うための設定もしておきます(事前にMac上でkubectlを利用できるようにしておく)

master node環境に入り、~/.kube/configの設定から以下の項目をMac側の~/.kube/configをコピペすればOK

  • clusters
  • contexts
  • users

nameは必要に応じて変更しても問題ありません(自分はraspberrypi-k8sに変更しました)

まとめ

これでおうちk8sライフが過ごせそうです

何やろうかな…

参考