kindind ~Kubernetes in Docker in Dockerでお手軽クラスタ構築~
はじめに
どうも、おのやんです。
みなさん、Kubernetesクラスタ組んでますか?私は大学の卒業研究としてKubernetesを用いたGPUクラスタをオンプレで構築していました。
Kubernetesクラスタを組んでみると、うまくアプリケーションのデプロイができなかったり、思わぬ部分で部分でつまづいたりします。そのため、初めてクラスタを構築するときだったりアプリケーションを試したいときは、簡単にクラスタを作成・削除できると嬉しいです。
しかし、オンプレ環境でクラスタ構築を試行錯誤していると、操作をミスった際にとても面倒です。操作を行う前の状態にクラスタを戻す必要があったり、最悪クラスタをはじめから構築し直す必要があります。
私はけっこうこの問題に悩まされていましたが、kindを使ってDockerコンテナ内にKubernetesクラスタ建てれんか?と思ってやってみたところ意外とすんなりできました。
今回はそんなkindind (Kubernetes in Docker in Docker)のやり方を紹介します。
使用技術
Dockerコンテナ内にKubernetesクラスタを建てるには、Kubernetes in Docker(kind)とDoker in Docker(dind)を使います。
具体的にはdindイメージを使ってコンテナを建てて、その中でkindクラスタを展開します。
kind
kindの公式ドキュメントには、以下のような紹介があります。
kind is a tool for running local Kubernetes clusters using Docker container “nodes”. kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.
kindはDockerコンテナの "ノード "を使ってローカルのKubernetesクラスタを実行するためのツールです。 kindは主にKubernetes自体のテスト用に設計されましたが、ローカル開発やCIに使用することもできます。(DeepLで翻訳)
kindを使えば、1台のマシンの上にKubernetesクラスタを建てることができます。Kubernetesクラスタを構成するノード(ひとつひとつのマシンのこと)はDockerコンテナです。このおかげで、物理クラスタと比べて簡単にクラスタを構築できます。Kubernetes単体のテストに用いられている公式のプロダクトなので、バグなども積極的に修正されており、動作も信頼できます。
しかし実際にクラスタが展開されるのはマシン上であり、複数種のクラスタの展開はできません。またkindやkubectlのインストールも求められるため、いくらか環境が汚れます。
そこで、これらのクラスタを隔離された環境の中で展開し、簡単に作成・管理・削除ができるようにしたいです。つまりDockerの中でDockerコンテナを建てられればいいわけです。
dind (Docker in Docker)
dindのDockerイメージの説明の一部を抜粋します。
Although running Docker inside Docker is generally not recommended, there are some legitimate use cases, such as development of Docker itself.
Dockerの内部でDockerを実行することは一般的に推奨されませんが、Docker自体の開発など、正当なユースケースも存在します。(DeepLで翻訳)
つまりDockerコンテナの中でDockerコンテナを起動できます。このコンテナイメージを使えば、dindコンテナの中でコンテナをノードとしたkindクラスタを構築できそうですね。
Dockerの内部でDockerを実行することは推奨されていません。後述するdocker-composeでのprivileged: trueもセキュリティ上のリスクがあります。そのため、本番環境ではこの方法は使用しないでください。あくまで、「kindのKubernetesクラスタをお試しで構築する」という用途に限定してください。
これらを確認した上で、Dockerコンテナにkindクラスタを構築していきましょう。
kindindクラスタ構築
まず、Dockerfile
, docker-compose.yaml
, kind-config.yaml
の3つのファイルを、以下のように作成します。
こちらのファイルは2023年2月に作成したものです。実際に実行する際は、公式ドキュメントを適宜参照して、コマンドや設定を置き換えてくださいm(_ _)m
FROM docker:stable-dind # Install kind RUN apk update && apk add curl && \ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.17.0/kind-linux-amd64 && \ chmod +x ./kind && \ mv ./kind /usr/local/bin/kind # Install kubectl RUN curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" && \ chmod +x ./kubectl && \ mv ./kubectl /usr/local/bin/kubectl # Install helm RUN curl https://raw.githubusercontent.com/helm/helm/HEAD/scripts/get-helm-3 | ash
version: '3.7' services: kind: build: context: ./ dockerfile: ./Dockerfile tty: true container_name: kind privileged: true volumes: - ../:/app/
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker
このうち、kind-config.yaml
はkindがクラスタを作成する際に参照する設定ファイルです。クラスタがどういう構成になっているのかをyaml形式で記述しています
これらのファイルをすべて同ディレクトリに配置して、Dockerfile
を元にDockerイメージを作成していきます。具体的には、Docker Composeでイメージをビルドします。
$ docker-compose build
イメージをビルドできたら、コンテナを起動します。
$ docker-compose up -d
今回は、/app
直下にDoclerfile
などを展開しています。 今回はコンテナの中に入って、/app/kind
ディレクトリまで移動します。
$ docker-compose exec -it kind ash
# cd app/kind
このkind
ディレクトリ直下でクラスタを作成します。
/app/kind # kind create cluster
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.25.3) ?
✓ Preparing nodes ?
✓ Writing configuration ?
✓ Starting control-plane ?️
✓ Installing CNI ?
✓ Installing StorageClass ?
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Not sure what to do next? ? Check out https://kind.sigs.k8s.io/docs/user/quick-start/
クラスタの作成が完了すると、Dockerコンテナの中にいながらKubernetesクラスタの管理が可能となります!
/app/kind # kubectl get all -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-565d847f94-d9jbg 1/1 Running 0 3m15s
kube-system pod/coredns-565d847f94-h2ggw 1/1 Running 0 3m14s
kube-system pod/etcd-kind-control-plane 1/1 Running 0 3m27s
kube-system pod/kindnet-nkzcb 1/1 Running 0 3m15s
kube-system pod/kube-apiserver-kind-control-plane 1/1 Running 0 3m27s
kube-system pod/kube-controller-manager-kind-control-plane 1/1 Running 0 3m27s
kube-system pod/kube-proxy-88vml 1/1 Running 0 3m15s
kube-system pod/kube-scheduler-kind-control-plane 1/1 Running 0 3m27s
local-path-storage pod/local-path-provisioner-684f458cdd-gf6ld 1/1 Running 0 3m15s
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m29s
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 3m28s
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-system daemonset.apps/kindnet 1 1 1 1 1 <none> 3m26s
kube-system daemonset.apps/kube-proxy 1 1 1 1 1 kubernetes.io/os=linux 3m28s
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 2/2 2 2 3m28s
local-path-storage deployment.apps/local-path-provisioner 1/1 1 1 3m25s
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-565d847f94 2 2 2 3m15s
local-path-storage replicaset.apps/local-path-provisioner-684f458cdd 1 1 1 3m15s
/app/kind # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
53dc503dd135 kindest/node:v1.25.3 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 127.0.0.1:38973->6443/tcp kind-control-plane
これらのファイルや操作は、私のGitHubの卒論ディレクトリにまとめていますので、よければご参照ください。
おわりに
Dockerコンテナの中にKubernetesクラスタを建てることで、複数のクラスタを同時変更で構築・比較できます。さらにコンテナを削除するだけでクラスタをリセットできるため、特にオンプレ環境でKubernetesクラスタを試す時にめちゃくちゃ有用です。私はこれで卒論を乗り切りました。
巷では「オンプレのクラスタ構築はしんどい」とか言われますが、オンプレクラスタ構築に悩んでる人は試しに使ってみてください!では!