Raspberry Pi4でK3Sをansibleを使って導入する

# はじめに

rak8sはもはや更新されていないので、k3sをraspberry piに導入することにしました。
導入方法自体については解説もされているので、もう少し手間を省くべく、ansibleによる導入を目指します。

初稿はRaspbian 32bit版を前提に作成しましたが、Ubuntu 20.04 LTSのイメージを利用して、64bit版のk3sを後からテストしたので、その結果を最後に加えています。

# References

* [Raspberry pi 4におけるK3Sクラスタ構築](https://qiita.com/Tsu_hao_Zhang/items/7d4f5d62bed584766881) https://qiita.com/Tsu_hao_Zhang/items/7d4f5d62bed584766881 
* [Running K3S](https://www.rancher.co.jp/docs/k3s/latest/en/running/) https://www.rancher.co.jp/docs/k3s/latest/en/running/

# 環境

* Hardware: Raspberry Pi 4 (4GB) x4台
* Image: 2020-02-13-raspbian-buster-lite.img
* K3S version: v1.17.4+k3s1

Raspbian Liteを使用せずにDesktop版のイメージを利用している場合には、不要なパッケージを削除するといった作業が必要になると思われますが、ここでは確認していません。

## ネットワーク

* 有線接続 (無線LANは想定していません)
* 192.168.100.0/24
* DHCP有効
* 固定IP (MACアドレスによる固定IP配布)
* DNSによる正引き、逆引き可能

DNS,DHCPサーバーにはdnsmasqを利用しています。

# おおまかな作業の流れ

次のような作業を想定しています。

1. Raspberry Pi4のセットアップ
2. 作業用PCでのansibleとMakefileの準備
3. ansibleによるK3Sの導入

## 作業に使用したファイル

ansible.cfgやMakefileなどは、github上で公開しています。

* https://github.com/YasuhiroABE/myansible-playground-raspi4k3s

# Step#1. Raspberry Pi4のセットアップ

あらかじめSSHサーバーを有効にし、authorized_keysにansibleを実行するホストのSSH公開鍵を登録しておきます。SDカードを編集する方法がおすすめですが、同様の設定を手動で行なうこともできます。

* [【Qiita】Raspberry PiのRaspbian SDイメージにあらかじめ設定を追加する](https://qiita.com/YasuhiroABE/items/1e82db1a822693734261)

また、MACアドレスから固定IPアドレスが割り当てられるようにDHCPサーバーを設定しておきます。

# Step2. ansible, Makefileの準備

ansibleを実行するホスト上で、準備を続けます。

```bash:必要なファイルの準備
$ git clone https://github.com/YasuhiroABE/myansible-playground-raspi4k3s
$ cd myansible-playground-raspi4k3s
```

hostsファイルを編集し、準備しているRaspberry Pi4の台数とIPアドレスに適宜修正します。

```text:github.com/YasuhiroABE/myansible-playground-raspi4k3s/blob/master/hosts
[master]
node1 ansible_host=192.168.100.11 ansible_python_interpreter=/usr/bin/python3

[slave]
node2 ansible_host=192.168.100.12 ansible_python_interpreter=/usr/bin/python3
node3 ansible_host=192.168.100.13 ansible_python_interpreter=/usr/bin/python3
node4 ansible_host=192.168.100.14 ansible_python_interpreter=/usr/bin/python3
```

ここまでの設定が正しければ、次のようなコマンドが全てのraspberry pi4上で動作するはずです。

```bash:ansible.cfg,hostsファイル設定の確認
$ ansible all -m ping
node1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
...

$ ansible all -m command -a uptime
node1 | CHANGED | rc=0 >>
 15:54:04 up  4:08,  2 users,  load average: 0.50, 0.66, 0.55
...
```

[Makefile](https://github.com/YasuhiroABE/myansible-playground-raspi4k3s/blob/master/Makefile)は、字下げをTab文字で行なう点に注意してください。

```makefile:github.com/YasuhiroABE/myansible-playground-raspi4k3s/blob/master/Makefile
K3S_URL = https://192.168.100.11:6443
K3S_TOKEN = K10735fb645c84e6eb1a5b3fa0a273439ef00a7b36bf95e7883fd034f8621faf313::server:b7078e87ce5a278527684026d20a3157

.PHONY: all references check-cmdline setup-cmdline disable-swapfile setup-k3s-master check-token setup-k3s-slave setup-roles

all:
	ansible-playbook site.yml

references:
	@echo https://qiita.com/Tsu_hao_Zhang/items/7d4f5d62bed584766881

check-cmdline:
	ansible all -m shell -a 'cat /boot/cmdline.txt'

setup-cmdline:
	ansible all -b -m replace -a "path=/boot/cmdline.txt regexp='^(.* rootwait)$$' replace='\1 cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset'"

check-swapfile:
	ansible all -b -m command -a 'grep SwapTotal /proc/meminfo'

disable-swapfile:
	ansible all -b -m systemd -a "enabled=no state=stopped name=dphys-swapfile.service"

setup-k3s-master:
	ansible master -b -m shell -a "curl -sfL https://get.k3s.io | sh -"
	ansible master -b -m systemd -a "enabled=yes state=started name=k3s"

check-token:
	ansible master -b -m command -a "cat /var/lib/rancher/k3s/server/node-token"

setup-k3s-slave:
	ansible slave -b -m shell -a "curl -sfL https://get.k3s.io | K3S_URL=$(K3S_URL) K3S_TOKEN=$(K3S_TOKEN) sh -"
	ansible slave -b -m systemd -a "daemon_reload=yes"
	ansible slave -b -m systemd -a "enabled=yes state=started name=k3s-agent"

setup-roles:
	mkdir -p roles
	ansible-galaxy install YasuhiroABE.myfavorite-setting
```

# Step#3. ansibleによるK3Sの導入

Makefileを利用してコマンドを実行していきます。

```bash:makeコマンドによる設定の反映
$ make setup-roles
## ホスト名の変更や、パスワードによるsshログインの禁止＋趣味な設定を追加
$ make all

## swapをoffにする  ## Ubuntu 20.04では最初からswapを使用していないため不要
$ make disable-swapfile
## swapの状況を確認する
$ make check-swapfile
## SwapTotal: 0 kB のようにSwapのサイズが0になっている事を確認

## マスター側でのk3sのインストール
$ make setup-k3s-master

## スレーブ側を設定する前にMakefileのK3S_URL, K3S_TOKENを設定する
```

## スレーブ側でのK3Sのインストール

ここまで無事に完了すれば、マスター側のk3sで使用しているTOKENを確認します。

```bash:tokenの確認
$ make check-token
ansible master -b -m command -a "cat /var/lib/rancher/k3s/server/node-token"
node1 | CHANGED | rc=0 >>
K10735fb645c84e6eb1a5b3fa0a273439ef00a7b36bf95e7883fd034f8621faf313::server:b7078e87ce5a278527684026d20a3157
```

1. ここで最下行に表示された1行をMakefileの先頭にある、K3S_TOKENに設定します。
2. 同じくMakefileの先頭にある、K3S_URLのIPアドレスをマスターノードのIPアドレスに変更します。

```bash:スレーブ側K3Sのインストール
$ make setup-k3s-slave
```

# 参考にした手順との違い

試した結果、最新のインストーラーで対応している部分や、必要がないと思われるものは削除しました。
一応ansibleで実行した部分についてはメモを残しておきます。

## cgroupsの機能について

使用したraspbian liteのイメージを利用して、/proc/cgroupsの内容を確認したところ、次のようになっています。

```bash:/proc/cgroupsの確認
$ ansible all -m command -a 'cat /proc/cgroups'
node1 | CHANGED | rc=0 >>
#subsys_name    hierarchy       num_cgroups     enabled
cpuset  6       22      1
cpu     5       50      1
cpuacct 5       50      1
blkio   2       50      1
memory  8       106     1
devices 7       50      1
freezer 9       22      1
net_cls 3       22      1
pids    4       55      1
...
```

もし/boot/cmdline.txtを変更したいのであれば、次のようなタスクが考えられます。

```makefile:/boot/cmdline.txtを更新するMakefileの記述例
check-cmdline:
        ansible all -m shell -a 'cat /boot/cmdline.txt'

setup-cmdline:
        ansible all -b -m replace -a "path=/boot/cmdline.txt regexp='^(.* rootwait)$$' replace='\1 cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset'"
```

## systemdの設定について

参考にしたRunning K3S (https://www.rancher.co.jp/docs/k3s/latest/en/running/) にも、k3s.serviceユニットの例が掲載されていますが、現在のインストーラーは、マスター側では、k3s.serviceを、(K3S_URL, K3S_TOKENを指定した)スレーブ側では、k3s-agent.serviceを有効にするようになっています。

コマンドラインの引数に、TOKENが残ってしまうのは適切ではないので、現状に合わせて、設定例のようなk3s-agent.service用のファイルを準備してはいません。

## /etc/hostsへの全ノード情報の追記について

私の環境ではdnsmasqを利用する事で、DHCPクライアントから指定されたホスト名をそのままDNSに登録しています。正引き、逆引きが問題なく行なえるため/etc/hostsの更新はしていませんが、必要な場合には次のようなタスクを実行することで、全ノードの/etc/hostsを更新することができます。

```makefile:/etc/hostsを更新するMakefileの記述例
check-hosts:
        ansible all -m shell -a 'cat /etc/hosts'

setup-hosts:
        ansible all -b -m lineinfile -a 'path=/etc/hosts regexp="^192\.168\.100\.11" line="192.168.100.11 node1"'
        ansible all -b -m lineinfile -a 'path=/etc/hosts regexp="^192\.168\.100\.12" line="192.168.100.12 node2"'
        ansible all -b -m lineinfile -a 'path=/etc/hosts regexp="^192\.168\.100\.13" line="192.168.100.13 node3"'
        ansible all -b -m lineinfile -a 'path=/etc/hosts regexp="^192\.168\.100\.14" line="192.168.100.14 node4"'
```

# Ubuntu 20.04 LTSを利用した64bit版k3sを試したときのメモ

使用したイメージは、ubuntu-20.04-preinstalled-server-arm64+raspi.img です。

* 追加導入するパッケージ名の変更 (emacs25 → emacs)
* swapは最初からoffだったので一部手順を削除
* 時刻が不正確なことでTLS接続に失敗していたので、別途openntpdを導入
* cgroupsはmemoryのみdisabledになっていたため、Raspbianでは参考情報としていた作業を追加

これらを反映させた内容は gitの"**ubuntu2004**" branchに格納しています。

```bash
## 既にgit cloneしていれば、ここは不要で、単純にcdする
$ git clone https://github.com/YasuhiroABE/myansible-playground-raspi4k3s
$ cd myansible-playground-raspi4k3s

## ubuntu2004ブランチに移動
$ git checkout ubuntu2004

$ make setup-roles
## ホスト名の変更や、パスワードによるsshログインの禁止＋趣味な設定を追加
$ make all

## swapの状況を確認する
$ make check-swapfile
## SwapTotal: 0 kB のようにSwapのサイズが0になっている事を確認

## cgroupsの設定を確認
$ make check-cgroups
## 表示された各行最後の数字が'1'(enabled)であることを確認する

## memoryが0である場合にはcmdline.txtを更新する
$ make setup-cmdline
$ make check-cmdline
## 各行の最後に"cgroup_memory=1 cgroup_enable=memory"が入っていることを確認する
## 最後に一度、全ノードを再起動する
$ ansible all -m command -b -a "shutdown -r now"

## 全ノードが再起動し、pingが成功することを確認する
$ ansible all -m ping
## 問題がなければ、マスター側でのk3sのインストール
$ make setup-k3s-master

## スレーブ側を設定する前にMakefileのK3S_URL, K3S_TOKENを設定する

## Makefileを修正後、他のノードにk3sを導入する
$ make setup-k3s-slave
```

# さいごに

最近のBLM運動に触発されたわけではないですが、用語は"slave"よりも"worker"の方が、kubernetesとしては正しかったかなと反省しています。

以上