Kubernetes 棄用 Docker 后如何切換到 Containerd
Kubernetes 從 v1.20 開始棄用 Docker[1],并推薦用戶切換到基于容器運(yùn)行時(shí)接口(CRI)[2]的容器引擎,如 containerd、cri-o 等。如果你使用了云服務(wù)商提供的托管 Kubernetes 服務(wù),那你不用擔(dān)心,像 GKE、AKS 等云服務(wù)商都已經(jīng)在新版集群中把默認(rèn)的運(yùn)行時(shí)切換到 containerd 。

那對(duì)于那些自管的集群,又如何把容器運(yùn)行時(shí)從 Docker 切換到 Containerd 呢?
切換容器運(yùn)行時(shí)的方法
首先,標(biāo)記節(jié)點(diǎn)為維護(hù)模式,并驅(qū)逐其上正在運(yùn)行的 Pod,避免切換過程中影響應(yīng)用的正常運(yùn)行:
kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets
然后以 root 用戶登錄到 Node 上面,停止 docker 和 kubelet,并刪除 docker:
systemctl stop kubelet
systemctl stop docker
apt purge docker-ce docker-ce-cli
接下來,生成 containerd 配置文件:
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
由于國內(nèi)環(huán)境無法訪問 GCR,需要修改默認(rèn) pause 鏡像為國內(nèi)可以訪問的地址,比如替換為 MCR:
...
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "mcr.microsoft.com/oss/kubernetes/pause:1.3.1"
...
接下來,打開 /etc/default/kubelet,修改 kubelet 啟動(dòng)選項(xiàng),配置容器運(yùn)行時(shí)為 containerd:
KUBELET_FLAGS=... --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock
修改完成后, 重啟 containerd 和 kubelet:
systemctl daemon-reload
systemctl restart containerd
systemctl restart kubelet
最后,退出 Node,使用 kubectl 命令驗(yàn)證節(jié)點(diǎn)的容器運(yùn)行時(shí):
# kubectl get node <node-name> -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
<node-name> Ready agent 13d v1.18.2 10.241.0.21 <none> Ubuntu 18.04.5 LTS 5.4.0-1039 containerd://1.4.3
可以發(fā)現(xiàn),容器運(yùn)行時(shí)已經(jīng)切換到了 containerd,其版本為 1.4.3。
最后,把節(jié)點(diǎn)重新加回集群中:
kubectl uncordon <node-name>
對(duì)其他的節(jié)點(diǎn)重復(fù)以上步驟,就可以把集群的 docker 替換成 containerd。
鏡像構(gòu)建的方法
除了以上的步驟,切換到 containerd 之后,還需要注意 docker.sock 不再可用,也就意味著不能再在容器里面執(zhí)行 docker 命令來構(gòu)建鏡像了。這里,我推薦幾種不需要 docker.sock 也可以構(gòu)建鏡像的方法。
第一個(gè)是 Docker Buildx[3],這也是 Kubernetes 社區(qū)用于構(gòu)建多體系結(jié)構(gòu)鏡像的方法。比如,你可以執(zhí)行下面的命令來構(gòu)建鏡像:
docker buildx create --driver kubernetes --driver-opt replicas=3 --use
docker buildx build -t example.com/foo --push .
第二個(gè)是 Redhat 開源的 Buildah[4]。Buildah 是 Openshift 默認(rèn)的鏡像構(gòu)建工具,同時(shí)支持 OCI 和 Docker 鏡像格式。Buildah 的使用方法類似于 docker build,如:
# 構(gòu)建鏡像
buildah bud -t example.com/foo:latest .
# 查詢鏡像列表
buildah images
第三個(gè)是 Google 開源的 kaniko[5]。Kaniko 不需要 docker daemon 就可以從 Dockerfile 構(gòu)建鏡像。在使用 Kaniko 時(shí)要注意,它在構(gòu)建鏡像時(shí)需要把構(gòu)建上下文(context)傳入到 kaniko 命令行中,構(gòu)建上下文可以放到標(biāo)準(zhǔn)輸入中,也可以放到 AWS S3、Azure Blob Storage、GCS Bucket 等云存儲(chǔ)中。
如下是一個(gè) Kaniko 的使用示例:
echo -e 'FROM alpine \nRUN echo "created from standard input"' > Dockerfile | tar -cf - Dockerfile | gzip -9 | kubectl run kaniko \
--rm --stdin=true \
--image=gcr.io/kaniko-project/executor:latest --restart=Never \
--overrides='{
"apiVersion": "v1",
"spec": {
"containers": [
{
"name": "kaniko",
"image": "gcr.io/kaniko-project/executor:latest",
"stdin": true,
"stdinOnce": true,
"args": [
"--dockerfile=Dockerfile",
"--context=tar://stdin",
"--destination=gcr.io/my-repo/my-image"
],
"volumeMounts": [
{
"name": "cabundle",
"mountPath": "/kaniko/ssl/certs/"
},
{
"name": "docker-config",
"mountPath": "/kaniko/.docker/"
}
]
}
],
"volumes": [
{
"name": "cabundle",
"configMap": {
"name": "cabundle"
}
},
{
"name": "docker-config",
"configMap": {
"name": "docker-config"
}
}
]
}
}'
總結(jié)
Docker 棄用后,可以把 Kubernetes 容器運(yùn)行時(shí)切換到社區(qū)維護(hù)并支持 CRI 的容器引擎,如 containerd、cri-o 等。切換之后,也需要注意,原來使用 docker build 構(gòu)建鏡像的應(yīng)用需要切換到無需 Dockerd 就可以構(gòu)建鏡像的工具,如 docker buildx、buildah、kaniko 等。
參考資料
Kubernetes 棄用 Docker: https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/
[2]容器運(yùn)行時(shí)接口(CRI): https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/
[3]Docker Buildx: https://docs.docker.com/buildx/working-with-buildx/
[4]Buildah: https://github.com/containers/buildah
[5]kaniko: https://github.com/GoogleContainerTools/kaniko
