将K8s运行时从docker切换到containerd
k8s支持多种容器运行时,比如docker、containerd等,如果k8s的版本用的是1.23.5之前的版本,那么直接使用docker即可,如果使用1.24.5版本,默认情况下不支持使用docker,因为dockershim被弃用,k8s无法通过dockershim来使用docker,此时有两种方案
- 使用containerd
- 继续使用docker,但是需要安装组件cri-dockerd,此组件可替代dockershim
如果我们当前使用的版本是1.23.5,并且容器运行时使用的是docker,现在想将k8s版本升级到1.24.5,那么就会报错,会出现错误如下:
msg="validate service connection: CRI v1 image API is not implemented for endpoint \"unix:///var/run/dockershim.sock\
错误表示你的 Kubernetes 集群在升级过程中,试图使用 CRI 接口拉取镜像,但是配置的 CRI 端点 dockershim.sock 不支持 CRI v1版本的镜像服务(ImageService),dockershim 是一个过渡的 CRI 实现,用于兼容 Docker,它只实现了 CRI 的部分接口,不支持镜像服务,因此此时又出现了两种解决方案:
- 将docker切换到containerd
- 将dockershim切换到cri-dockerd
本例子演示如何将docker切换到containerd
环境准备:
- k8s :v1.23.5版本,一个master,两个node,通过kubeadm安装
- docker:20.10.8
- 系统:CentOS7

执行kubectl get nodes -o wide可以查看当前使用的runtime,如图:

上图中的master节点已经升级好了,现在我们演示升级node01节点
一、维护节点
1、设置节点不可调度与pod驱逐,命令如下:

使用如下命令驱逐k8s-node01上面的pod,如下:
kubectl drain k8s-node01 --ignore-daemonsets #daemonset控制器运行的忽略
此时k8s-node01上除了daemonset运行的pod,其余pod 已经全部被驱逐到k8s-node02上
2、停止kubelet和docker
systemctl stop kubelet
systemctl stop docker
二、安装containerd并配置
docker里面自带的containerd一般版本都比较老,因此我们可以手动安装一个较新版本的
可参考教程地址如下:https://blog.ywdevops.cn/index.php/2023/09/13/containerd/,记得要生成默认配置文件
1、修改配置文件/etc/containerd/config.toml,添加镜像下载加速器,如图:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["registry.aliyuncs.com/google_containers"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["registry.aliyuncs.com/google_containers"]

2、继续修改/etc/containerd/config.toml,配置sandbox地址为国内地址,如图:

sandbox 表示容器的沙箱环境。每个容器启动时,都会以一个基础镜像为模板首先启动一个沙箱容器。其他容器将在这个沙箱中运行,对于 Kubernetes 来说,这个基础沙箱镜像就是 pause 镜像。pause 镜像是一个非常精简的 Linux 环境,可以提供基础的命名空间、网络等功能
3、修改/etc/containerd/config.toml,配置 systemd cgroup 驱动,如图:

三、修改kubelet使用containerd
1、修改/var/lib/kubelet/kubeadm-flags.env文件,将containerd参数添加进入,如下:
#注意:前面都是双横岗--
KUBELET_KUBEADM_ARGS="--network-plugin=cni --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.8"
- –container-runtime:用来指定容器运行时,可选值为remote和docker,默认为docker,这里设置为remote,表示除了docker以外的容器运行时(v1.27后将被弃用)
- –container-runtime-endpoint:指定远程的运行时服务的 endpiont 地址的,在 Linux 系统中一般都是使用 unix 套接字的形式,因此这里配置为 unix:///run/containerd/containerd.sock
- –pod-infra-container-image:kubelet安装好后自带的,不是新加,可将镜像版本设置与config.toml中的一样,这里设置为pause:3.8
2、编辑每个节点,修改kubeadm.alpha.kubernetes.io/cri-socket的值,如下:
kubectl edit node k8s-master01/k8s-node01/k8s-node02
将其从 /var/run/dockershim.sock 修改为unix:///run/containerd/containerd.sock
3、启动containerd和kubelet
systemctl daemon-reload
systemctl restart containerd
systemctl restart kubelet
4、再次在master执行命令kubectl get node -o wide 查看运行时,如图:

从上图看出,k8s-node01的容器运行时已经切换到containerd
5、将k8s-node01设置为可调度即可,命令如下:
kubectl uncordon k8s-node01
注意:其余节点都按照此方法切换到containerd即可,如果master节点升级后相关的组件如api-server、controller等会显示错误,查看日志可以看出,是使用containerd运行容器的时候与之前docker运行的冲突了,可将pod删除然后等着自动重启即可


