本記事は「エーピーコミュニケーションズ Advent Calendar 2022」の21日目のエントリです。
軽量Kubernetesディストリビューションの一つにk3sというものがあります。
以下のコマンドで簡単にクラスタをデプロイでき、少ないリソースで動作し、プラットフォームもARMにも対応しているので幅広く使用できます。(Raspberry Piとか、Oracle Cloud無料枠のARMコンピュートインスタンスとか)
curl -sfL https://get.k3s.io | sh -
実はこのk3sはコンテナ版もあって、Linux OSに直接インストールするのでなく、Dockerコンテナとしてノードを動作させることもできます。Docker上でKubernetesをデプロイできるkindと同じで、Kubernetes in Dockerの構成。
コンテナ版k3sのデプロイには、Docker Composeを使う方法と、CLIツールを使う方法があり、本記事ではそれぞれ紹介します。
CLIの方はkindと使い勝手的にはかなり似ています。k3sは「停止」が用意されているので「使いたいときだけ動かす」がやりやすいかも。(kindだとdocker stop
を直接実行するしかない…よね)
CLIを使った構築
k3d
インストール
k3d
コマンドのインストール
$ curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash Preparing to install k3d into /usr/local/bin k3d installed into /usr/local/bin/k3d Run 'k3d --help' to see what you can do with it.
他にもプラットフォームにあわせてHomebrewやChocolateyを使用可能。
他のバージョンを使いたいなどは、インストールドキュメント参照。
クラスタのデプロイ
最も単純な1ノード(コントロールプレーン・ワーカーのオールインワンシングルノード構成)の場合はオプション指定も特になくcreate
のみでOK
(※この場合コントロールプレーンノードのスケールはあとからできない。後述)
$ k3d cluster create INFO[0000] Prep: Network INFO[0000] Created network 'k3d-k3s-default' INFO[0000] Created image volume k3d-k3s-default-images INFO[0000] Starting new tools node... INFO[0001] Creating node 'k3d-k3s-default-server-0' INFO[0001] Pulling image 'ghcr.io/k3d-io/k3d-tools:5.4.6' INFO[0003] Starting Node 'k3d-k3s-default-tools' INFO[0003] Pulling image 'docker.io/rancher/k3s:v1.24.4-k3s1' INFO[0016] Creating LoadBalancer 'k3d-k3s-default-serverlb' INFO[0017] Pulling image 'ghcr.io/k3d-io/k3d-proxy:5.4.6' INFO[0020] Using the k3d-tools node to gather environment information INFO[0021] HostIP: using network gateway 172.18.0.1 address INFO[0021] Starting cluster 'k3s-default' INFO[0021] Starting servers... INFO[0021] Starting Node 'k3d-k3s-default-server-0' INFO[0027] All agents already running. INFO[0027] Starting helpers... INFO[0027] Starting Node 'k3d-k3s-default-serverlb' INFO[0033] Injecting records for hostAliases (incl. host.k3d.internal) and for 2 network members into CoreDNS configmap... INFO[0036] Cluster 'k3s-default' created successfully! INFO[0036] You can now use it like this: kubectl cluster-info
マルチノードの場合はオプションを指定します。
$ k3d cluster create --servers 3 --agents 2
起動するとホストOSの$HOME/.kube/config
が生成・更新されるので、kubectl
はすぐ使用可能。ノード状態は以下の通り。
zaki@dev-server:~$ kubectl get node NAME STATUS ROLES AGE VERSION k3d-k3s-default-agent-0 Ready <none> 26s v1.24.4+k3s1 k3d-k3s-default-agent-1 Ready <none> 26s v1.24.4+k3s1 k3d-k3s-default-server-0 Ready control-plane,etcd,master 60s v1.24.4+k3s1 k3d-k3s-default-server-1 Ready control-plane,etcd,master 46s v1.24.4+k3s1 k3d-k3s-default-server-2 Ready control-plane,etcd,master 33s v1.24.4+k3s1
クラスタの状態
K3dとしてのクラスタ一覧
$ k3d cluster list NAME SERVERS AGENTS LOADBALANCER k3s-default 1/1 0/0 true
コンテナの状態。
コントロールプレーンノード以外にLBやAPIサーバーとして動作するコンテナが1つ起動しています。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cb7ba9c9a6ed ghcr.io/k3d-io/k3d-proxy:5.4.6 "/bin/sh -c nginx-pr…" About a minute ago Up 54 seconds 80/tcp, 0.0.0.0:43515->6443/tcp k3d-k3s-default-serverlb 75a6838bc838 rancher/k3s:v1.24.4-k3s1 "/bin/k3d-entrypoint…" About a minute ago Up About a minute k3d-k3s-default-server-0
$ kubectl cluster-info Kubernetes control plane is running at https://0.0.0.0:43515 CoreDNS is running at https://0.0.0.0:43515/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Metrics-server is running at https://0.0.0.0:43515/api/v1/namespaces/kube-system/services/https:metrics-server:https/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
zaki@dev-server:~$ kubectl get node NAME STATUS ROLES AGE VERSION k3d-k3s-default-server-0 Ready control-plane,master 3m20s v1.24.4+k3s1 zaki@dev-server:~$ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system local-path-provisioner-7b7dc8d6f5-tt94v 1/1 Running 0 3m8s kube-system coredns-b96499967-q5kbw 1/1 Running 0 3m8s kube-system helm-install-traefik-crd-5w7mv 0/1 Completed 0 3m8s kube-system helm-install-traefik-xqjkn 0/1 Completed 1 3m8s kube-system svclb-traefik-50cc15de-xt892 2/2 Running 0 2m40s kube-system metrics-server-668d979685-j4j62 1/1 Running 0 3m8s kube-system traefik-7cd4fcff68-78nhc 1/1 Running 0 2m41s
ノードをあとから追加する
ワーカー(agent)
ワーカーノードを1台追加するには以下のコマンド。
$ k3d node create agent
zaki@dev-server:~$ k3d node list NAME ROLE CLUSTER STATUS k3d-agent-0 agent k3s-default running k3d-k3s-default-server-0 server k3s-default running k3d-k3s-default-serverlb loadbalancer k3s-default running zaki@dev-server:~$ kubectl get node NAME STATUS ROLES AGE VERSION k3d-k3s-default-server-0 Ready control-plane,master 12d v1.24.4+k3s1 k3d-agent-0 Ready <none> 30s v1.24.4+k3s1
コントロールプレーン(server)
コントロールプレーンを追加するには--role
オプションを指定する。(デフォルトagent
なのでワーカーが追加される)
$ k3d node create master --role server
ただし、「クラスタ作成時に1サーバーノードで作成した場合(--servers n
を指定しなかった場合)」は以下の通りエラーとなります。
zaki@dev-server:~$ k3d node create master --role server INFO[0000] Adding 1 node(s) to the runtime local cluster 'k3s-default'... INFO[0000] Using the k3d-tools node to gather environment information INFO[0000] Starting new tools node... INFO[0000] Starting Node 'k3d-k3s-default-tools' INFO[0000] HostIP: using network gateway 172.22.0.1 address INFO[0000] Starting Node 'k3d-master-0' WARN[0001] warning: encountered fatal log from node k3d-master-0 (retrying 0/10): �time="2022-12-18T03:49:11Z" level=fatal msg="starting kubernetes: preparing server: https://k3d-k3s-default-server-0:6443/v1-k3s/server-bootstrap: 400 Bad Request" WARN[0001] warning: encountered fatal log from node k3d-master-0 (retrying 1/10): �time="2022-12-18T03:49:12Z" level=fatal msg="starting kubernetes: preparing server: https://k3d-k3s-default-server-0:6443/v1-k3s/server-bootstrap: 400 Bad Request" [snip] WARN[0006] warning: encountered fatal log from node k3d-master-0 (retrying 9/10): �time="2022-12-18T03:49:16Z" level=fatal msg="starting kubernetes: preparing server: https://k3d-k3s-default-server-0:6443/v1-k3s/server-bootstrap: 400 Bad Request" FATA[0006] failed to add 1 node(s) to the runtime local cluster 'k3s-default': failed to add one or more nodes: failed to run node 'k3d-master-0': failed to start node 'k3d-master-0': Node k3d-master-0 failed to get ready: error waiting for log line `k3s is up and running` from node 'k3d-master-0': stopped returning log lines: node k3d-master-0 is running=true in status=restarting
🔥 There’s a trap!
If your cluster was initially created with only a single server node, then this will fail. That’s because the initial server node was not started with the
--cluster-init
flag and thus is not using the etcd backend.
構成のコード化
kind
と同様に、クラスタ作成時のオプションを設定ファイルに記述することもできます。
例えばコントロールプレーン3台、ワーカー2台のクラスタであれば以下の通り。
apiVersion: k3d.io/v1alpha4 kind: Simple metadata: name: mycluster servers: 3 agents: 2
このファイルをk3d-config.yaml
として用意し、クラスタ作成時に以下コマンドを実行すれば指定の構成でデプロイされます。
$ k3d cluster create -c k3d-config.yaml
$ k3d cluster list NAME SERVERS AGENTS LOADBALANCER mycluster 3/3 2/2 true
他にもオプションで指定できる様々な値をYAMLで指定できます。
詳細はドキュメント参照。
Docker Composeを使った構築
もう一つの構築方法がDocker Composeを使った方法。
前提としてDockerとDocker Composeがインストール済みであること。
(現在はdocker-compose
コマンドでなくDockerのプラグインとしてインストールする。手順通りにインストールすればdocker-compose-plugin
パッケージに含まれるので使用可能になっているはず)
Composeを使ったコンテナ版k3sのデプロイ方法はドキュメントはあまり詳しく載っておらず、「Running K3s in Docker」や、「日本語版K3sマニュアル(PDF版)」の49ページ「8.9 K3d(Docker で動く k3s)を docker-compose で動かす」という項で確認できます。(が、情報量が少ない)
Composeファイル
デプロイに使用するComposeファイルはk3sリポジトリのルートにあります。
内容を見ればわかりますが、server
(コントロールプレーン)と、agent
(ワーカー)の2つのノードが起動する設定になっています。
また、server上でAPIサーバーやIngress Controllerが動作するためのポートのpublish設定なども確認できます。
クラスタのデプロイ
Docker Composeの通常の操作で、docker compose up
を実行してデプロイします。
ただし準備として、コントロールプレーンとワーカーが互いに通信するためのトークンを環境変数で設定しておく必要があります。
[zaki@cloud-dev2 k3s-compose]$ export K3S_TOKEN=${RANDOM}${RANDOM}${RANDOM} [zaki@cloud-dev2 k3s-compose]$ [zaki@cloud-dev2 k3s-compose]$ docker compose up -d [+] Running 4/4 ⠿ Network k3s-compose_default Created 0.2s ⠿ Volume "k3s-compose_k3s-server" Created 0.0s ⠿ Container k3s-compose-server-1 Started 1.0s ⠿ Container k3s-compose-agent-1 Started 1.0s [zaki@cloud-dev2 k3s-compose]$ [zaki@cloud-dev2 k3s-compose]$ docker compose ps NAME COMMAND SERVICE STATUS PORTS k3s-compose-agent-1 "/bin/k3s agent" agent running k3s-compose-server-1 "/bin/k3s server" server running 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:6443->6443/tcp, :::6443->6443/tcp
デフォルトの動作では、kubeconfig.yaml
はカレントディレクトリに生成されるので、--kubeconfig
で指定すれば(またはKUBECONFIG
環境変数指定)kubectl
が使用可能。
[zaki@cloud-dev2 k3s-compose]$ kubectl get node --kubeconfig ./kubeconfig.yaml NAME STATUS ROLES AGE VERSION 11d52309842b Ready control-plane,master 48s v1.24.3+k3s1 36e609703847 Ready <none> 44s v1.24.3+k3s1
K3S_TOKEN
の値はComposeファイル内に指定の方法が記載されています。
頻繁に作成と削除を繰り返す場合は、$HOME/.bashrc
等で指定しておくのもアリ。ランダムである必要もないので、適当な固定値でもOK
マルチノードの制限
マルチノードについては、Compose版はいろいろ試した限り制限がありそう。
起動時のノード指定
ワーカーノードのみマルチノードにする場合はdocker compose up
の--scale
オプションで対応可能。
以下のコマンドであれば3ワーカーノードのクラスタをデプロイできます。
$ docker compose up -d --scale agent=3
ただし、コントロールプレーンはポートのpublish設定があるため、単純に--scale
しても起動しません。APIサーバー用のコンテナが起動してコントロールプレーンへのLBとして動作するCLI版と異なり、おそらくコンテナ自身がAPIサーバーとして動作する設計になっているため、スケールできないと思われます。
(たぶんCLI版と同じ構成になるようにComposeファイルを作成すれば動く…かも。未検証)
起動後のノード追加
これはできるかと思ったけど今のところうまく行かなかった。
running中の状態でdocker compose up -d --scale agent=X
すると、動作的には新しいワーカーノードは追加されるが、元からrunningだったノードがNot Readyになってしまった。
これも現状未解決。
CLI版と同じ動きになるようにdocker run
でネットワークやボリュームを手動で指定しつつ既存クラスタへ追加することは、技術的には可能と思われるが、こちらも未検証。
まとめ
軽量Kubernetesであるk3sのコンテナ版を2パターン紹介しました。コンテナの特徴である作って壊すが簡単にできるので、検証用途などには特に使い勝手は良いと思います。それぞれ特徴があるので簡単に私見でまとめ。
- CLI版
- Composeに比べるとノードのスケールが容易
- 設定ファイルを使えば環境のコード化も対応できる
- Compose版
- ノードのスケールには向いてないが
docker compose up -d
、docker compose down -v
で簡単にクラスタの作成・削除が可能 - 構成をComposeファイルに記述できるためDocker Composeに慣れてる場合は管理しやすい
- Dockerコンテナとしてのリソース制限等もComposeファイルへ容易に定義可能
- ノードのスケールには向いてないが
資料
- k3d
- k3d-io/k3d: Little helper to run CNCF's k3s in Docker
- K3s - Lightweight Kubernetes | K3s
- K3s日本語資料
K3dだったりk3dだったり、公式の表記ゆれが多くてどっちがただしいんだ。。