👌

ラズパイでK8s…は重そうなのでK3sしてみた話

2023/01/05に公開

きっかけ

仕事でkubernetes(以下K8s)を設定したのはいいがいろいろブラックボックス過ぎて自分の理解が進んでいないと感じた。なんかちょっとアップデートするとスペランカー並みにすぐ死ぬのも気に入らないし基礎がわからないと対処もできない(大昔の、version 2か3あたりのPHP思い出してしまった)。
そこでお正月休みを利用して最近練習用にしているRaspberry Pi 3でその辺がいい感じでいじれたらいいなと思った。
とはいうもののK8sは基本的に富豪な環境を必要とするしそもそもラズパイのARM系で動くのこれ・・・と思っていたら軽量なKubernetesであるK3sというのがあるらしい。これで行こう。

とりあえずの目標はなんか簡単なコンテナアプリを複数個立ててアクセスするところまで。
以下、やったことのメモ書きです。

使っている環境

Raspberry Pi 3(メモリ1GB)を2台(ホスト名rpi3v2, rpi3v3, v1はどうしたか?元々あったんだけど他の用途に転用してしまったの)。どちらもRaspberry Pi OS(旧Raspbian)のBullseyeを使っている。

tamori@rpi3v2:~ $ uname -a
Linux rpi3v2 5.15.76-v7+ #1597 SMP Fri Nov 4 12:13:17 GMT 2022 armv7l GNU/Linux
tamori@rpi3v2:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

K3s

公式サイトはこちら。インストール方法はじめドキュメントは以下。
https://docs.k3s.io/

Lightweight Kubernetes. Easy to install, half the memory, all in a binary of less than 100 MB.
Great for:
Edge
IoT
CI
Development
ARM
Embedding K8s
Situations where a PhD in K8s clusterology is infeasible

「軽量Kubernetesでインストールが簡単で使用メモリは半分、全てが100MB以下のワンバイナリに収まっている」「Edge、IoT、CI、開発、ARM、組み込みK8s(※そういう需要ってあるのだろうか)、K8sでのクラスタ学で博士号が取れなさそうなところ(※笑、既に一般的なK8sではネタが掘り尽くされているのでIoT絡みで論文を書けということか)に適する」だそうで。名前の由来も笑えるな…作った人は結構ユーモアのセンスがあるに違いない[1]

事前準備

初期状態ではRaspberry Pi OSではcgroupsが有効化されていないので/boot/cmdline.txt に以下を追加して再起動する必要がある。
ググって先にこの指示を見つけたのでよかったがK3sサイトの下の方Advanced Options and Configurationの項にあるので気づかずに踏んでしまった人がそこそこいる模様。

cgroup_memory=1 cgroup_enable=memory

うちのラズパイのcmdline.txtはこんな感じになった。

console=serial0,115200 console=tty1 root=PARTUUID=68d5d2e9-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles cgroup_memory=1 cgroup_enable=memory

さらにk8sにはswapの利用は非推奨なのでこれも切ってしまおう。ラズパイは/etc/fstabでswap領域指定ではなくdphys-swapfile.serviceでswapfileを作成してswapを有効化しているので

$ sudo swapoff --all
$ sudo systemctl stop dphys-swapfile.service
$ sudo systemctl disable dphys-swapfile.service

でswapが恒久的に切れる。

tamori@rpi3v2:~ $ free
               total        used        free      shared  buff/cache   available
Mem:          944268      558000       85360        2748      300908      307208
Swap:              0           0           0

Swapのtotalが0なので切れている[2]。または cat /proc/swapsでも確認できる。

tamori@rpi4:~ $ cat /proc/swaps
Filename                                Type            Size            Used            Priority

Raspberry Pi OSに入っているiptablesのバージョンが古い(1.8.3以前)だとiptablesのバグでルールが重複すると高負荷になるので回避するにはiptablesをアンインストールするか、最新(2022年12月版)のK3sでは--prefer-bundled-binでK3s自体が持っているiptables(1.8.8)を使うように指示する必要がある。確認したらうちのラズパイのiptablesは 1.8.7 なのでまあ大丈夫だろう。

なおUbuntuではなくRaspberry Pi OSなのでlinux-modules-extra-raspiの追加インストールは不要(そもそもそんなモジュールはない)

K3sのインストール

インストールは

$ curl -sfL https://get.k3s.io | sh -

一発で終わる…ようですがこちらによれば/etc/rancher/k3s/k3s.yamlの読み取り属性が不足していてコケるので(※試してみたら実際コケました)

$ curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644

で実行します。インストールとサービス起動までにはうちの環境で2分程度でした(systemdからk3sサービスを起動するところが時間がかかる)。

サービスが起動しているか確認してみます。

tamori@rpi3v2:~ $ systemctl status k3s
● k3s.service - Lightweight Kubernetes
     Loaded: loaded (/etc/systemd/system/k3s.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-01-03 11:00:42 JST; 29s ago
       Docs: https://k3s.io
    Process: 4117 ExecStartPre=/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service (code=exited, status=0/SUCC>
    Process: 4119 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS)
    Process: 4120 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
   Main PID: 4121 (k3s-server)
      Tasks: 39
     Memory: 432.0M
        CPU: 2min 40.064s
     CGroup: /system.slice/k3s.service
             ├─4121 /usr/local/bin/k3s server
             └─4140 containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --stat>

 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.373302    4121 node_lifecycle_controller.go:532] Sending events to api server.
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.373862    4121 node_lifecycle_controller.go:543] Starting node controller
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.374010    4121 shared_informer.go:255] Waiting for caches to sync for taint
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.525718    4121 controllermanager.go:603] Started "persistentvolume-binder"
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.525962    4121 pv_controller_base.go:318] Starting persistent volume controller
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.527918    4121 shared_informer.go:255] Waiting for caches to sync for persistent vo>
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.831760    4121 controllermanager.go:603] Started "horizontalpodautoscaling"
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.832763    4121 horizontal.go:168] Starting HPA controller
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.833431    4121 shared_informer.go:255] Waiting for caches to sync for HPA
 1月 03 11:01:08 rpi3v2 k3s[4121]: I0103 11:01:08.881973    4121 node_ipam_controller.go:91] Sending events to api server.

無事起動しているようです。次にK3sが動いているかkubectlコマンドを打ってみます。

tamori@rpi3v2:~ $ kubectl get services --all-namespaces
NAMESPACE     NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                                            PORT(S)
           AGE
default       kubernetes       ClusterIP      10.43.0.1       <none>                                                 443/TCP
           14m
kube-system   kube-dns         ClusterIP      10.43.0.10      <none>                                                 53/UDP,53/TCP,9153/TCP       14m
kube-system   metrics-server   ClusterIP      10.43.168.211   <none>                                                 443/TCP
           14m
kube-system   traefik          LoadBalancer   10.43.178.213   192.168.0.21,fdc5:9a66:a4ce:4526:358d:5afd:4b2b:3d52   80:31110/TCP,443:32113/TCP   11m

大丈夫ぽい。ついでにdeployment一覧を見てみると

tamori@rpi3v2:~ $ kubectl get deployments --all-namespaces -o wide
NAMESPACE     NAME                     READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS               IMAGES
           SELECTOR
kube-system   local-path-provisioner   1/1     1            1           107m   local-path-provisioner   rancher/local-path-provisioner:v0.0.23   app=local-path-provisioner
kube-system   coredns                  1/1     1            1           107m   coredns                  rancher/mirrored-coredns-coredns:1.9.4   k8s-app=kube-dns
kube-system   metrics-server           1/1     1            1           107m   metrics-server           rancher/mirrored-metrics-server:v0.6.1   k8s-app=metrics-server
kube-system   traefik                  1/1     1            1           105m   traefik                  rancher/mirrored-library-traefik:2.9.4   app.kubernetes.io/instance=traefik-kube-system,app.kubernetes.io/name=traefik
  • local-path-provisionerはk8sの各ノードのローカルディスクを永続化ボリューム(PV)として使うためのツール
  • corednsはDNSサービス
  • metrics-serverはリソース監視用のデータ収集サービス
  • traefikはリバースプロキシ/ロードバランサー

Battery Includedと言うだけあって一通り必要なものが入っているようだ。

K3sサーバー単体で何か動かしてみる

ラズパイ2台でクラスターを組もうと思ったが手元に余ってるハブがないので(古いの捨てちゃったんだよな…失敗…)Amazonでポチった。WiFiを家のネットワーク、今は未接続の有線LANをクラスターマシン間接続で組もうと考えたので…。

目標とする構成はこんな感じ。

まずはサーバー単体でkubernetesとしてどのぐらい動くのか試してみる。

nginx

もうk8sのHello, Worldですかというぐらい使われているネタ。

apiVersion: apps/v1 # APIバージョン
kind: Deployment # リソースの種類(Deployment)
metadata:
  name: nginx-test
spec:
  selector:
    matchLabels:
      app: nginx # テンプレートを指定
  replicas: 3 # レプリカ数(Podの数)
  template:
    metadata:
      labels:
        app: nginx # nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80 # ポート番号
---
apiVersion: v1
kind: Service # リソースの種類(Service)
metadata:
  name: nginx-service-test
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30000
  selector: # 下記のLabel(ラベル)を指定したPodに転送
    app: nginx

これをnginx-sample.yaml として保存しkubectlでapplyする。

tamori@rpi3v2:~ $ kubectl apply -f nginx-sample.yaml
deployment.apps/nginx-test created
service/nginx-service-test created

http://localhost:30000/ にアクセスするとおなじみの画面が。

ということでK3s、きっちり動作している。

go言語のアプリをコンテナ化して動かす

nginxをたくさん動かしても区別がつかず面白くもなんともないのでここ
https://sysadmins.co.za/develop-build-and-deploy-a-golang-app-to-k3s/
の説明に沿ってやってみます。

Goソース

これは上記サイトの「自分のホスト名を返すプログラム」をちょっと改造してuptime, load average, メモリ容量・使用量を表示するようにした。

package main

import (
	"fmt"
	"net/http"
	"os"
	sigar "github.com/cloudfoundry/gosigar"
)

func hostnameHandler(w http.ResponseWriter, r *http.Request) {
	myhostname, _ := os.Hostname()
	uptime := sigar.Uptime{}
	uptime.Get()
	loadavg := sigar.LoadAverage{}
	loadavg.Get()
        mem := sigar.Mem{}
        mem.Get()
	fmt.Fprintf(w, "%s  uptime: %s  Load average: %.2f, %.2f, %.2f Mem(MB): Total %d, Used %d, Free %d\n",
		myhostname, uptime.Format(), loadavg.One, loadavg.Five, loadavg.Fifteen, mem.Total/1024, mem.Used/1024, mem.Free/1024)
}

func main() {
	const port string = "8000"
	fmt.Println("Server listening on port", port)
	http.HandleFunc("/", hostnameHandler)
	http.ListenAndServe(":"+port, nil)
}

Docker

Dockerも入れよう…

tamori@rpi3v2:~ $ curl -fsSL https://get.docker.com | sudo sh -
# Executing docker install script, commit: 4f282167c425347a931ccfd95cc91fab041d414f
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sh -c mkdir -p /etc/apt/keyrings && chmod -R 0755 /etc/apt/keyrings
+ sh -c curl -fsSL "https://download.docker.com/linux/raspbian/gpg" | gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg
+ sh -c chmod a+r /etc/apt/keyrings/docker.gpg
+ sh -c echo "deb [arch=armhf signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/raspbian bullseye stable" > /etc/apt/sources.list.d/docker.list
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null
+ version_gte 20.10
+ [ -z  ]
+ return 0
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker-ce-rootless-extras >/dev/null
+ sh -c docker version
Client: Docker Engine - Community
 Version:           20.10.22
 API version:       1.41
 Go version:        go1.18.9
 Git commit:        3a2c30b
 Built:             Thu Dec 15 22:27:51 2022
 OS/Arch:           linux/arm
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.22
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.18.9
  Git commit:       42c8b31
  Built:            Thu Dec 15 22:25:41 2022
  OS/Arch:          linux/arm
  Experimental:     false
 containerd:
  Version:          1.6.14
  GitCommit:        9ba4b250366a5ddde94bb7c9d1def331423aa323
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

================================================================================

To run Docker as a non-privileged user, consider setting up the
Docker daemon in rootless mode for your user:

    dockerd-rootless-setuptool.sh install

Visit https://docs.docker.com/go/rootless/ to learn about rootless mode.


To run the Docker daemon as a fully privileged service, but granting non-root
users access, refer to https://docs.docker.com/go/daemon-access/

WARNING: Access to the remote API on a privileged Docker daemon is equivalent
         to root access on the host. Refer to the 'Docker daemon attack surface'
         documentation for details: https://docs.docker.com/go/attack-surface/

================================================================================

そのままだとDockerはrootでないと動かせないので

tamori@rpi3v2:~ $ sudo usermod -aG docker tamori
tamori@rpi3v2:~ $ sudo chmod a+rw /var/run/docker.sock

を実行。

またまた確認のためにnginxを動かしてみる(さっきのk8sのnginxは30000だったがこちらは8080)

tamori@rpi3v2:~ $ docker run --name some-nginx -d -p 8080:80 nginx

http://localhost:8080 をアクセスしてnginxが動作していることを確認

同じ絵ですみません…

Dockerイメージを作ってDocker Hubにpush

Dockerfile


# syntax=docker/dockerfile:1

FROM golang:1.19-alpine

WORKDIR /app

COPY go.mod ./
COPY go.sum ./

RUN go mod download

COPY *.go ./

RUN go build -o /k3ssample

EXPOSE 8000

CMD [ "/k3ssample" ]

イメージの作成と(docker loginと)push

tamori@rpi3v2:~/go/k3ssample $ docker build -t htamori/k3ssample:latest .

docker hubにアカウントを作ってお試ししたまま3年ほど放置していた模様…

tamori@rpi3v2:~/go/k3ssample $ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: htamori
Password:
WARNING! Your password will be stored unencrypted in /home/tamori/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
tamori@rpi3v2:~/go/k3ssample $ docker push htamori/k3ssample:latest
The push refers to repository [docker.io/htamori/k3ssample]
f1c74f028761: Pushed
3d7bc52b8fc8: Pushed
6e2f359e6e4a: Pushed
5db6bcfa503d: Pushed
b97f661a692e: Pushed
2f8036526674: Pushed
b4b0b3d5affb: Mounted from library/golang
4a8943de4381: Mounted from library/golang
6c173b100072: Mounted from library/golang
e824cba1a7fa: Mounted from library/golang
latest: digest: sha256:a879f64d764d5a28fd2b1679e25911676d40ee4c7593513649f9014df6f761d0 size: 2407

k3sにデプロイする

デプロイとサービス定義用のyaml(k3ssample.yaml)はこんな感じ。

apiVersion: apps/v1 # APIバージョン
kind: Deployment # リソースの種類(Deployment)
metadata:
  name: k3ssample
spec:
  selector:
    matchLabels:
      app: k3ssample # テンプレートを指定
  replicas: 3 # レプリカ数(Podの数)
  template:
    metadata:
      labels:
        app: k3ssample # k3ssample
    spec:
      containers:
      - name: k3ssample
        image: htamori/k3ssample:latest
        ports:
        - containerPort: 8000 # ポート番号
---
apiVersion: v1
kind: Service # リソースの種類(Service)
metadata:
  name: k3ssample-service-test
spec:
  type: NodePort
  ports:
    - port: 8000
      nodePort: 30000 # ポート8000を30000で受ける
  selector: # 下記のLabel(ラベル)を指定したPodに転送
    app: k3ssample

これをk3sにapply

tamori@rpi3v2:~ $ kubectl apply -f k3ssample.yaml
deployment.apps/k3ssample created
service/k3ssample-service-test created

一応サービスが立ち上がっているか確認

tamori@rpi3v2:~ $ kubectl get services
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes               ClusterIP   10.43.0.1       <none>        443/TCP          29h
k3ssample-service-test   NodePort    10.43.179.205   <none>        8000:30000/TCP   44m

podの一覧を取ってみる。

tamori@rpi3v2:~ $ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
k3ssample-7b6f9dbfc5-7zngl   1/1     Running   0          49m
k3ssample-7b6f9dbfc5-llp2h   1/1     Running   0          49m
k3ssample-7b6f9dbfc5-lwsjz   1/1     Running   0          49m

この状態でcurl http://localhost:30000 を何度か実行すると…

tamori@rpi3v2:~ $ curl http://localhost:30000
k3ssample-7b6f9dbfc5-7zngl  uptime: 14:16  Load average: 1.72, 7.84, 9.93 Mem(MB): Total 944268, Used 1308, Free 942960
tamori@rpi3v2:~ $ curl http://localhost:30000
k3ssample-7b6f9dbfc5-7zngl  uptime: 14:16  Load average: 1.72, 7.84, 9.93 Mem(MB): Total 944268, Used 1332, Free 942936
tamori@rpi3v2:~ $ curl http://localhost:30000
k3ssample-7b6f9dbfc5-lwsjz  uptime: 14:16  Load average: 1.72, 7.84, 9.93 Mem(MB): Total 944268, Used 1352, Free 942916
tamori@rpi3v2:~ $ curl http://localhost:30000
k3ssample-7b6f9dbfc5-7zngl  uptime: 14:16  Load average: 1.72, 7.84, 9.93 Mem(MB): Total 944268, Used 1488, Free 942780

podの名前をホスト名にしていることがわかる。uptimeやメモリの量はシステム全体のデータしか取れないんですね。
ついでにpodの数を増やしてみよう。

tamori@rpi3v2:~ $ kubectl scale deployments k3ssample --replicas=6
deployment.apps/k3ssample scaled
tamori@rpi3v2:~ $ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
k3ssample-7b6f9dbfc5-7zngl   1/1     Running   0          59m
k3ssample-7b6f9dbfc5-llp2h   1/1     Running   0          59m
k3ssample-7b6f9dbfc5-lwsjz   1/1     Running   0          59m
k3ssample-7b6f9dbfc5-k669x   1/1     Running   0          22s
k3ssample-7b6f9dbfc5-l2dbp   1/1     Running   0          22s
k3ssample-7b6f9dbfc5-tpf6n   1/1     Running   0          22s

増えた(当たり前)。

K3s Agentを追加する

イーサネットHUBが届いたので次は1台K3s Agentを追加してクラスターを組んでみます。
まずここまでで起動して動作確認したK3sサーバーのtokenを取得。

tamori@rpi3v2:~ $ sudo cat /var/lib/rancher/k3s/server/node-token

次に追加するもう1台のラズパイ(rpi3v3)で

tamori@rpi3v3:~ $ curl -sfL https://get.k3s.io | K3S_URL=https://192.168.100.1:6443 \
K3S_TOKEN="K10e6d************************************ef0e74d6ab0" sh -
[INFO]  Finding release for channel stable
[INFO]  Using v1.25.5+k3s1 as release
[INFO]  Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.25.5+k3s1/sha256sum-arm.txt
[INFO]  Downloading binary https://github.com/k3s-io/k3s/releases/download/v1.25.5+k3s1/k3s-armhf
[INFO]  Verifying binary download
[INFO]  Installing k3s to /usr/local/bin/k3s
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Creating /usr/local/bin/crictl symlink to k3s
[INFO]  Creating /usr/local/bin/ctr symlink to k3s
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-agent-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s-agent.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s-agent.service
[INFO]  systemd: Enabling k3s-agent unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s-agent.service → /etc/systemd/system/k3s-agent.service.
[INFO]  systemd: Starting k3s-agent

を実行し、しばらく経ってからサーバー側(rpiv2)でkubectlでノードの情報を取ってみると

tamori@rpi3v2:~ $ kubectl get nodes -o wide
NAME     STATUS   ROLES                  AGE     VERSION        INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                           KERNEL-VERSION   CONTAINER-RUNTIME
rpi3v2   Ready    control-plane,master   32h     v1.25.4+k3s1   192.168.0.21   <none>        Raspbian GNU/Linux 11 (bullseye)   5.15.76-v7+      containerd://1.6.8-k3s1
rpi3v3   Ready    <none>                 2m35s   v1.25.5+k3s1   192.168.0.4    <none>        Raspbian GNU/Linux 11 (bullseye)   5.15.76-v7+      containerd://1.6.12-k3s1

増えている(rpiv3)。

しかしよく見ると、せっかくハブを用意したのにINTERNAL-IPがWiFi経由でおうちのネットのままであった。サーバー側は

tamori@rpi3v2:~ $ curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644 --node-ip="192.168.100.1"

のように--node-ipオプションを追加することで有線LANのアドレスに変更できたがエージェント側がうまく設定できない。どうやら一旦走っているpodを全て停止してからでないと切り替えられないようだ[3]

tamori@rpi3v2:~ $ kubectl scale deployments k3ssample --replicas=0
deployment.apps/k3ssample scaled
tamori@rpi3v2:~ $ kubectl get pods -o wide
No resources found in default namespace.

この状態で

tamori@rpi3v3:~ $ curl -sfL https://get.k3s.io | K3S_URL=https://192.168.100.1:6443 \
K3S_TOKEN="K10e6d************************************ef0e74d6ab0" sh -s - \
--node-ip="192.168.100.2"

を実行したら無事

tamori@rpi3v2:~ $ kubectl get nodes -o wide
NAME     STATUS   ROLES                  AGE     VERSION        INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                           KERNEL-VERSION   CONTAINER-RUNTIME
rpi3v2   Ready    control-plane,master   37h     v1.25.5+k3s1   192.168.100.1   <none>        Raspbian GNU/Linux 11 (bullseye)   5.15.76-v7+      containerd://1.6.12-k3s1
rpi3v3   Ready    <none>                 4h22m   v1.25.5+k3s1   192.168.100.2   <none>        Raspbian GNU/Linux 11 (bullseye)   5.15.76-v7+      containerd://1.6.12-k3s1

と有線LAN側を使って通信するようになった。

やってみての感想

  • K3s、非力なメモリ1GBのRaspberry Pi 3でもそこそこ動く。重い処理を走らせたら厳しいだろうけど本家Kubernetesはもちろん、minikubeですらそのものを動かすだけで精一杯らしいのでこれは驚異的。
    • コマンドもサブセットではなくフルセットで動く
  • インストール(設定変更しての上書き再インストールも)がcurlを叩くスクリプトを実行するだけで済むのが楽だった。
    • ただし当然オプション指定などはちゃんと理解していないとダメ。
      • --write-kubeconfig-mode 644 のつけ忘れはみんな引っかかってる感じ
    • アンインストールがコマンド一発で済むのも素晴らしい。
  • 本家ドキュメントはよくできているがところどころ落とし穴(先にここを読んでおかないとダメ、というのが見つけにくい場所にある)があるように感じた。
    • ネットで試している人がたくさんいたので情報収集大事。
  • オールインワンでいろいろ動くのですぐに使えるのがいい。
    • 逆にpod間ネットワーク構築(K3sの場合flannelが最初から設定されて動いている)などを手動で設定して中身を理解する勉強、というのは別にやる必要がある。
    • Flannelを切って他のものを使うオプションやデータベースを標準のSQliteから他のものに置き換える方法もあるのでそのうちCalicoを試してみたい。
  • で、これで何やるの?というのは…まだちょっと思いつかない。K3sに向いている、とサイトにある「組み込みk8s」ってどういうものなのだろう。
脚注
  1. 以前はK8sから要素を5つ取ったからK3s…という説明をしていたようだ。 ↩︎

  2. 調べるうちに「うちはswap有効のままでも平気だったよ」みたいな話も見かけたのでそこまで気にしなくてもいいのかもしれない。 ↩︎

  3. サーバー側ではうまくいくがエージェント側ではだめということらしい ↩︎

Discussion