kindのノードイメージを手動でビルドする

何かしらの理由でkind(Kubernetes IN Docker)のノードイメージを自分でビルドしたいことがあるかもしれません。
そのときの手順をまとめます。

# 環境
- MacBook Pro (2021, M1 Pro)
- Docker Desktop for Mac (Apple sillocon) 4.13.0 (89412)
- kind v0.16.0 go1.19.1 darwin/arm64

# 事前準備
以下の作業を行っておいてください。
この記事では手順は省略します。
- Docker Desktopをインストールして起動しておく
- homebrewをインストールしておく
- kindをインストールしておく

# 手順
1. kindのベースイメージをビルドする
1. ビルドしたベースイメージを使ってノードイメージをビルドする
1. ビルドしたノードイメージを使ってkindクラスターを作成する

## kindのベースイメージをビルドする
kindのソースコードをクローンします。

```shell-session
$ git clone https://github.com/kubernetes-sigs/kind.git
```

もしM1 Mac向けにビルドしたい場合には、Makefileの```PLATFORMS```をamd64からarm64に書き換えてください。

```shell-session
$ sed -i "" 's|\(^quick.*\)amd64$|\1arm64|' kind/images/Makefile.common.in
```

baseフォルダに移動して```make quick```を実行します。

```shell-session
$ cd kind/images/base
$ make quick
./../../hack/build/init-buildx.sh
docker buildx build --platform=linux/arm64 --load --progress=auto -t kindest/base:v20221028-2a1658eb-dirty --pull  .

（省略）

 => importing to docker
```

以下のようなDockerイメージが作成されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244425/b3d41d96-a4d0-8157-3cfc-3d3768b92190.png)

## ビルドしたベースイメージを使ってノードイメージをビルドする

先ほどビルドしたDockerイメージを使ってノードイメージをビルドします。

ビルドするには```$GOPATH```や```$HOME/go```以下にkubernetesのソースコードが必要ですので、もしなければクローンします。
```shell-session
$ mkdir -p $GOPATH/src/k8s.io
$ cd $GOPATH/src/k8s.io
$ git clone https://github.com/kubernetes/kubernetes
```

ビルドするためのコマンドは以下のようになります。

```shell-session
$ kind build node-image --base-image=kindest/base:v20221028-2a1658eb-dirty
```

コマンドを実行したときに、もしかしたら「bashのバージョンが古い」「gnu-tarがない」といったエラーが出るかもしれません。
その場合にはエラーメッセージのとおりにインストールしましょう。
```shell-session
$ brew install bash
$ brew install gnu-tar
```

その後もbashバージョンのエラーが出るようであれば、環境変数```PATH```の検索順序を見直す必要があります。
```/opt/homebrew/bin```が```/bin```よりも前になるようにしてください。

問題なくビルドが完了すれば、以下のようなDockerイメージが作成されるはずです。

```shell-session
$ kind build node-image --base-image=kindest/base:v20221028-2a1658eb-dirty
Starting to build Kubernetes

（省略）

Finished building Kubernetes
Building node image ...
Building in container: kind-build-1666966022-30023755
Image "kindest/node:latest" build completed.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244425/07ce4af1-9e1f-1305-172e-a75d2b15eb1a.png)

## ビルドしたノードイメージを使ってkindクラスターを作成する

ビルドしたノードイメージを使用してkindクラスターを作成します。
```yaml:kind.yaml
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
  image: kindest/node:latest
- role: control-plane
  image: kindest/node:latest
- role: control-plane
  image: kindest/node:latest
- role: worker
  image: kindest/node:latest
- role: worker
  image: kindest/node:latest
- role: worker
  image: kindest/node:latest
```

```shell-session
$ kind create cluster --config kind.yaml --name kindcluster
Creating cluster "kindcluster" ...
 ✓ Ensuring node image (kindest/node:latest) 🖼
 ✓ Preparing nodes 📦 📦 📦 📦 📦 📦
 ✓ Configuring the external load balancer ⚖️
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining more control-plane nodes 🎮
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-kindcluster"
You can now use your cluster with:

kubectl cluster-info --context kind-kindcluster

Thanks for using kind! 😊

```

以上です。