kubernetesのコンテナランタイムをdockerからcontainerdに変更する

## はじめに

[RaspberryPi上のkubernetes(kubeadm)をアップグレード](https://qiita.com/yasthon/items/10239c8b70bf19055e2d)で、RaspberryPi上のKubernetesを`v1.22.1`にアップグレードしました。

v1.20 からコンテナランタイムにDockerを使用することが非推奨になっています。
将来のv1.23 からは､Dockershim(kubeletがDockerを使うための仕組み)が削除予定です。
この記事では､コンテナランタイムをDockerからcontainerdに変更した内容を記載しています｡

## 環境

- Raspberry Pi 4 Model B/4GB x 3台 (Mater x 1, Worker x 2)
- Ubuntu 20.04
- Kubernetes(kubeadm, kubelet, kubectl) v1.22.1
- Docker 19.03.13

3台のRaspberryPiは､それぞれ
**master01.example.jp**
**worker01.example.jp**
**worker02.example.jp**
で名前解決できるようにしています｡

:::note warn
この記事では、Podを停止した状態にして作業を行っています。
Podを停止できない場合は、kubectl drain を実施するなど安全面に配慮が必要です。
:::

## Master Nodeの作業

### containerd へ変更 (Master Nodeで実行)

コンテナランタイムが何が使われているか確認します｡
一番後ろの`CONTAINER-RUNTIME`列に表示されます｡

```shell
$ kubectl get node -o wide
NAME                  STATUS   ROLES                  AGE    VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master01.example.jp   Ready    control-plane,master   311d   v1.21.4   192.168.100.101   <none>        Ubuntu 20.04.1 LTS   5.4.0-1038-raspi   docker://19.3.13
worker01.example.jp   Ready    worker                 311d   v1.21.4   192.168.100.102   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   docker://19.3.13
worker02.example.jp   Ready    worker                 311d   v1.21.4   192.168.100.103   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   docker://19.3.13
```

3台ともDockerが使われています｡
containerdは､Dockerと一緒にインストールしているので､バージョンアップを実行します。

```shell
$ sudo apt update
$ apt-cache madison containerd.io | head
$ sudo apt-mark unhold containerd.io
$ sudo apt install containerd.io=1.4.9-1
$ sudo apt-mark hold containerd.io
```

念の為､containerd.sockの存在確認です。

```shell
$ ls /run/containerd/containerd.sock
/run/containerd/containerd.sock
```

コンテナランタイムを設定します。
`KUBELET_KUBEADM_ARGS`は､kubeletの起動時に使用されるオプションです｡
[CRIのインストール](https://kubernetes.io/ja/docs/setup/production-environment/container-runtimes/)の手順だけでは切り替わらなくて､KUBELET_KUBEADM_ARGSに設定を追記して切り替えることができました｡

```shell
$ sudo vi /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2"
    ↓
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --container-runtime remote --container-runtime-endpoint unix:///run/containerd/containerd.sock"
```

containerd の設定をconfig.tomlに書き込みます。

```shell
$ containerd config default | sudo tee /etc/containerd/config.toml
version = 2
root = "/var/lib/containerd"
state = "/run/containerd"
plugin_dir = ""
disabled_plugins = []
required_plugins = []
oom_score = 0

～～～ 長いので中略 ～～～

  [plugins."io.containerd.runtime.v2.task"]
    platforms = ["linux/arm64/v8"]
  [plugins."io.containerd.service.v1.diff-service"]
    default = ["walking"]
  [plugins."io.containerd.snapshotter.v1.devmapper"]
    root_path = ""
    pool_name = ""
    base_image_size = ""
```

containerdとkubeletを再起動します。

```shell
$ sudo systemctl restart containerd
$ sudo systemctl restart kubelet
```

確認です。

```shell
$ kubectl get node -o wide
NAME                  STATUS   ROLES                  AGE    VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master01.example.jp   Ready    control-plane,master   311d   v1.22.1   192.168.100.101   <none>        Ubuntu 20.04.1 LTS   5.4.0-1038-raspi   containerd://1.4.9
worker01.example.jp   Ready    worker                 311d   v1.22.1   192.168.128.194   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   docker://19.3.13
worker02.example.jp   Ready    worker                 311d   v1.22.1   192.168.128.195   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   docker://19.3.13
```

Master Nodeがcontainerdに切り替わりました。

## Worker Node 01の作業

### containerd へ変更 (Worker Node 01で実行)

実行内容は､Master Nodeと同じ内容なので、コマンドだけ羅列します。

```shell
$ sudo apt update
$ apt-cache madison containerd.io | head
$ sudo apt-mark unhold containerd.io
$ sudo apt install containerd.io=1.4.9-1
$ sudo apt-mark hold containerd.io
$ kubectl get node -o wide

$ ls -la /run/containerd/containerd.sock

$ sudo vi /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2"
  ↓
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --container-runtime remote --container-runtime-endpoint unix:///run/containerd/containerd.sock"

$ containerd config default | sudo tee /etc/containerd/config.toml

$ sudo systemctl restart containerd
$ sudo systemctl restart kubelet

$ kubectl get node -o wide
NAME                  STATUS   ROLES                  AGE    VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master01.example.jp   Ready    control-plane,master   311d   v1.22.1   192.168.100.101   <none>        Ubuntu 20.04.1 LTS   5.4.0-1038-raspi   containerd://1.4.9
worker01.example.jp   Ready    worker                 311d   v1.22.1   192.168.100.102   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   containerd://1.4.9
worker02.example.jp   Ready    worker                 311d   v1.22.1   192.168.100.103   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   docker://19.3.13
```

Worker Node 01がcontainerdに切り替わっています。

## Worker Node 02の作業

### containerd へ変更 (Worker Node 02で実行)

実行内容は､Master Nodeと同じ内容なので、コマンドだけ羅列します。

```shell
$ sudo apt update
$ apt-cache madison containerd.io | head
$ sudo apt-mark unhold containerd.io
$ sudo apt install containerd.io=1.4.9-1
$ sudo apt-mark hold containerd.io
$ kubectl get node -o wide

$ ls -la /run/containerd/containerd.sock

$ sudo vi /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2"
  ↓
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --container-runtime remote --container-runtime-endpoint unix:///run/containerd/containerd.sock"

$ containerd config default | sudo tee /etc/containerd/config.toml

$ sudo systemctl restart containerd
$ sudo systemctl restart kubelet

$ kubectl get node -o wide
NAME                  STATUS   ROLES                  AGE    VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master01.example.jp   Ready    control-plane,master   311d   v1.22.1   192.168.100.101   <none>        Ubuntu 20.04.1 LTS   5.4.0-1038-raspi   containerd://1.4.9
worker01.example.jp   Ready    worker                 311d   v1.22.1   192.168.100.102   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   containerd://1.4.9
worker02.example.jp   Ready    worker                 311d   v1.22.1   192.168.100.103   <none>        Ubuntu 20.04.1 LTS   5.4.0-1041-raspi   containerd://1.4.9
```

これですべてのコンテナランタイムがcontainerdに切り替わりました。

## cri-tools のインストール

コンテナの一覧を表示するために､cri-toolsをインストールします｡
ほぼ[kubernetes-sigs/cri-tools](https://github.com/kubernetes-sigs/cri-tools)にかかれている手順のままですが､RaspberryPiを使用しているので`linux-amd64`を`linux-arm64`に変えます｡

```shell
$ VERSION="v1.22.0"
$ curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-${VERSION}-linux-arm64.tar.gz --output crictl-${VERSION}-linux-arm64.tar.gz
$ sudo tar zxvf crictl-$VERSION-linux-arm64.tar.gz -C /usr/local/bin
$ rm -f crictl-$VERSION-linux-amd64.tar.gz
```

設定ファイルを作成します｡

```shell
$ sudo vi /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
```

コマンドを実行します｡

```shell
$ sudo crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID
44286ef6a2044       0729779a30a16       2 weeks ago         Running             kube-flannel              3                   0a288ff5a6c52
a273b1a96343d       3b241671010f1       2 weeks ago         Running             speaker                   1                   6b41a30b2ae90
cf386fe2f5f8a       d9fa9053808ef       2 weeks ago         Running             kube-proxy                1                   46eadd7f5e35e
cdca70b79845e       2252d5eb703b0       2 weeks ago         Running             etcd                      1                   a8f68c582dfbb
16e260b771e1b       7605412e3e072       2 weeks ago         Running             kube-apiserver            2                   aaaaa6a2cae5e
b287a694179c0       d5504eacf2d71       2 weeks ago         Running             kube-controller-manager   1                   f134803880a16
8bf52d7b31c5f       4641e56315a27       2 weeks ago         Running             kube-scheduler            1                   1e6fd1d6ec7a0

```

`Docker container ls`とほぼ同じ出力が得られました｡
Dockerコマンドと違って､`POD ID`なんて表示もあります｡

## 参考

- [CRIのインストール](https://kubernetes.io/ja/docs/setup/production-environment/container-runtimes/)
- [kubeletが使うコンテナランタイムをdockerからcontainerdに変更する](https://repl.info/archives/2894/)
- [Kubernetes 1.20から始まるDockerランタイムの非推奨化に備えよう！我々が知っておくべきこと・すべきこと](https://thinkit.co.jp/article/18024)
- [kubernetes-sigs/cri-tools](https://github.com/kubernetes-sigs/cri-tools)

## 最後に

これでkubernetesを使う限り､Dockerが必要なくなりました｡
Docker-Desktopの有料化もあり､Docker離れが心配になりそうです｡