在未来的kubernetes版本会计划彻底放弃Docker支持,会弃用kubelet中的docker-shim组件;也就是k8s不能默认直接使用docker引擎了,所以在以后可能containerd可能会成为主流,很多大企业现在都已经换成containerd了,包括我之前在阿里云上创建ACK的时候,会出现让选择容器运行时的一个选项,上面就涵盖了containerd和docker两项;
docker-shim组件是k8s为了专门与docker适配的,能够与Docker Engine进行通信;
这篇文章我们来一起学习下将k8s集群下的容器引擎切换为Containerd以及Containerd如何去使用的;
我直接用之前kubeadm部署的单master集群来进行操作;有需要k8s单集群部署的可以看下:kubeadm部署k8s集群手册
软件环境:
软件 | 版本 |
---|---|
操作系统 | Centos 7.9_x64 |
docker | 20-ce |
kubernetes | v1.20.0 |
containerd | v1.6.4 |
服务器规划:
角色 | IP |
---|---|
k8s-master | 192.168.1.1 |
k8s-node1 | 192.168.1.2 |
k8s-node2 | 192.168.1.3 |
我们用于测试修改容器引擎,只需要在其中一个节点测试下就可以了,我在node2节点上进行修改;
[root@k8s-node2 ~]# lsmod | grep overlay
overlay 91659 6
[root@k8s-node2 ~]# lsmod | grep netfilter
br_netfilter 22256 0
bridge 151336 1 br_netfilter
这两个内核模块在操作系统中是默认加载的,可以使用lsmod来进行查看
提示:如果这两个内核模块没有加载的话可以执行下面的命令进行加载:
[root@k8s-node2 ~]# sudo modprobe overlay
[root@k8s-node2 ~]# sudo modprobe br_netfilter
[root@k8s-node2 ~]# cat <
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1 #启动路由转发功能
EOF
[root@k8s-node2 ~]# sysctl --system #进行加载配置
我们前面说过,containerd之前是docker的一部分,所以我们切换docker容器引擎为containerd的话则不需要安装containerd了
此时使用containerd容器引擎的流程图是这样的
如图:
提示:下面这些安装containerd的命令是针对之前容器引擎不是docker的或者没有安装过docker的亲们:
[root@k8s-node2 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
[root@k8s-node2 ~]# yum install -y containerd.io
[root@k8s-node2 ~]# mkdir -p /etc/containerd
[root@k8s-node2 ~]# containerd config default > /etc/containerd/config.toml
[root@k8s-node2 ~]# ps -ef |grep containerd #查看containerd的守护进程
root 1051 1 0 19:00 ? 00:00:08 /usr/bin/containerd
root 1237 1 0 19:00 ? 00:00:15 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 3425 1 0 19:03 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 0f2011ed7771da01d3077e0286076a77b4376195028e6d5845b6069af5d7786f -address /run/containerd/containerd.sock
...
提示:默认的containerd配置文件(/etc/containerd/config.toml)里的内容只有一行,是默认禁用cri的,如下图
[root@k8s-node2 ~]# containerd config default > /etc/containerd/config.toml
[root@k8s-node2 ~]# vim /etc/containerd/config.toml
disabled_plugins = []#可以看到此时生成的配置文件已经没有禁用cri了
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2"
[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options]
SystemdCgroup = true
...
sandbox_image = “registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2” #设置管理容器(负责网络)的镜像为阿里云的镜像;
SystemdCgroup = true #需要在[plugins.“io.containerd.grpc.v1.cri”.containerd.default_runtime.options]下添加 ;设置cgroup的驱动为systemd
编辑kubelet配置文件/etc/sysconfig/kubelet
提示:这个配置文件是kubelet可以向对外提供参数的地方,我们想加参数的时候可以在这里加;
[root@k8s-node2 ~]# vim /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock --cgroup-driver=systemd
–container-runtime=remote #表示我们使用的不是docker引擎(只要不是docker引擎的话都是remote这个值);
–container-runtime-endpoint=/run/containerd/containerd.sock #指定containerd的容器引擎地址,这个sock文件就相当于是个api;
–cgroup-driver=systemd #设置cgroup的驱动为systemd;
加的kubelet这些启动参数可以通以下命令查看
[root@k8s-node2 ~]# kubelet --help | grep runtime
--container-runtime string The container runtime to use. Possible values: 'docker', 'remote'. (default "docker")
#可以看到kubelet使用的容器引擎由两个只,一个是docker,还有一个值是只要使用的不是docker引擎 那么值为remote;
--container-runtime-endpoint string [Experimental] The endpoint of remote runtime service. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows. Examples:'unix:///var/run/dockershim.sock', 'npipe:./pipe/dockershim' (default "unix:///var/run/dockershim.sock")
#指定容器引擎的api的地址,sock文件的地址,可以看到默认使用的是docker-shim的sock;
最后再重启下Containerd的进程
提示:Containerd是可以独立的去管理的,例如做start,stop操作;
[root@k8s-node2 ~]# systemctl restart containerd
[root@k8s-node2 ~]# systemctl status containerd
● containerd.service - containerd container runtime
Loaded: loaded (/usr/lib/systemd/system/containerd.service; disabled; vendor preset: disabled)
Active: active (running) since Wed 2022-06-15 22:40:30 CST; 16s ago
Docs: https://containerd.io
Process: 21876 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
Main PID: 21878 (containerd)
Tasks: 71
Memory: 133.4M
CGroup: /system.slice/containerd.service
...
这时我们去master节点查看下node2这个节点使用的容器引擎是什么
提示:现在应该还是默认的docker,因为需要重启一下node2节点上的kubelet才会变成containerd引擎
[root@k8s-master ~]# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane,master 8d v1.20.11 192.168.1.1 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node1 Ready <none> 8d v1.20.11 192.168.1.2 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node2 Ready <none> 8d v1.20.11 192.168.1.3 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
注意看最后CONTAINER-RUNTIME这一列,这一列表示的就是节点使用的容器引擎,可以看到现在还是使用的默认的引擎docker 20.10版本;
[root@k8s-node2 ~]# systemctl restart kubelet
[root@k8s-node2 ~]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Wed 2022-06-15 22:51:00 CST; 9min ago
Docs: https://kubernetes.io/docs/
Main PID: 29912 (kubelet)
Tasks: 14
Memory: 40.2M
CGroup: /system.slice/kubelet.service
└─29912 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --...
...
再次查看node2节点使用的容器引擎
[root@k8s-master ~]# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane,master 8d v1.20.11 192.168.1.1 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node1 Ready <none> 8d v1.20.11 192.168.1.2 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node2 Ready <none> 8d v1.20.11 192.168.1.3 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 containerd://1.6.4
可以看到node2的容器引擎已经变成了containerd 1.6.4版本;
这就已经顺利的将docker切换成了containerd,现在如果创建个容器分配到这个节点上的话,就是containerd负责创建这个容器,包括销毁这样的动作,就不会再调用docker了;
提示:与此同时,docker还是会运行在此节点上的,但是有关容器的动作不会去调用docker,而是直接使用containerd,所以完全可以把docker这个进程干掉;
containerd提供了ctr命令行工具管理容器,但功能比较简单,所以一般会用crictl工具检查和调试容器。
提示:crictl这个工具,不只是给containerd提供的,而是所有适配CRI的容器引擎都可以用这个工具进行调试;
项目地址:https://github.com/kubernetes-sigs/cri-tools/
crictl这个工具默认是已经装了的
crictl这个工具最大的好处就是它与docker命令的使用风格是一毛一样的;
例如:
[root@k8s-node2 ~]# crictl images
WARN[0000] image connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock uni As the default settings are now deprecated, you should set the endpoint instead.
ERRO[0000] unable to determine image API version: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial uninect: connection refused"
IMAGE TAG IMAGE ID SIZE
docker.io/calico/cni v3.23.1 90d97aa939bbf 111MB
docker.io/calico/node v3.23.1 fbfd04bbb7f47 76.6MB
docker.io/library/busybox latest 62aedd01bd852 778kB
docker.io/library/nginx latest 0e901e68141fd 56.7MB
registry.aliyuncs.com/google_containers/coredns 1.7.0 bfe3a36ebd252 14MB
registry.aliyuncs.com/google_containers/kube-proxy v1.23.0 e03484a90585e 39.3MB
registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5de 300kB
噶,我们可以看到报错了,
这个Warnning是因为默认的引擎是一个列表,会一个一个的去连接尝试一下;这个列表里面包含了dockershim.sock、containerd.sock、 cri-dockerd.sock(红帽的容器引擎);但是现在已经弃用了,所以报Warnning;
这个ERROR报的是连接不上docker导致的;但是结果最终还是给我们输出了镜像信息,还是因为那个默认引擎是个列表,docker连不上,就给我们连上了containerd这个引擎 列出了镜像;
提示:我们在上面的引擎列表里可以看到有个dockershim.sock,这可能是docker已经做出了向k8s CRI适配的一个动作喔;
下面写下这个错误的解决办法,否则他会一直尝试连接这个列表的
[root@k8s-node2 ~]# vim /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10 #超时时间
debug: false #debug是否输出debug信息
/etc/crictl.yaml是crictl这个工具默认的配置文件,需要创建;
然后需要指定下endpoint的为containerd的sock地址;
再次查看镜像就没有warnning和error信息了;
[root@k8s-node2 ~]# crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/library/busybox latest 62aedd01bd852 778kB
[root@k8s-node2 ~]# crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
ff073f3b0c45b bfe3a36ebd252 3 minutes ago Running coredns 0 220dcdcae5aff coredns-5879556fbc-ghxfx
b16aa39b0554a e03484a90585e 3 minutes ago Running kube-proxy 0 64bccc538f5b4 kube-proxy-jhh5p
435bd9ba245eb fbfd04bbb7f47 4 minutes ago Running calico-node 0 4b01fffd2aea7 calico-node-gk86n
bd9d6caa5a8f9 0e901e68141fd 5 minutes ago Running my-nginx 0 69f53f8f4e577 my-nginx-64cc7f8db7-b64gb
198c13cf5d94f 0e901e68141fd 5 minutes ago Running my-nginx 0 cc4506ed4c87a my-nginx-64cc7f8db7-2hcvb
[root@k8s-node2 ~]# crictl exec -it bd9d6caa5a8f9 bash
root@my-nginx-64cc7f8db7-b64gb:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@my-nginx-64cc7f8db7-b64gb:/#
[root@k8s-node2 ~]# crictl pods
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
220dcdcae5aff 9 minutes ago Ready coredns-5879556fbc-ghxfx kube-system 0 (default)
69f53f8f4e577 9 minutes ago Ready my-nginx-64cc7f8db7-b64gb default 0 (default)
cc4506ed4c87a 9 minutes ago Ready my-nginx-64cc7f8db7-2hcvb default 0 (default)
64bccc538f5b4 9 minutes ago Ready kube-proxy-jhh5p kube-system 0 (default)
4b01fffd2aea7 9 minutes ago Ready calico-node-gk86n kube-system 0 (default)
这里就先演示这几个crictl命令;更多的命令我会在下面列出来
镜像:
镜像相关功能 | Docker | Containerd |
---|---|---|
显示本地镜像列表 | docker images | crictl images |
下载镜像 | docker pull | crictl pull |
上传镜像 | docker push | 无,需要使用buildkit等工具构建并上传镜像 |
删除本地镜像 | docker rmi | crictl rmi |
查看镜像详情 | docker inspect | crictl inspecti IMAGE-ID |
容器:
容器相关功能 | Docker | Containerd |
---|---|---|
显示容器列表 | docker ps | crictl ps |
创建容器 | docker create | crictl create |
启动容器 | docker start | crictl start |
停止容器 | docker stop | crictl stop |
删除容器 | docker rm | crictl rm |
查看容器详情 | docker inspect | crictl inspect |
附加容器 | docker attach | crictl attach |
进入容器/执行命令 | docker exec | crictl exec |
查看日志 | docker logs | crictl logs |
查看容器资源 | docker stats | crictl stats |
Pod:
Pod相关功能 | Docker | Containerd |
---|---|---|
显示Pod列表 | 无 | crictl pods |
查看Pod详情 | 无 | crictl inspectp |
运行Pod | 无 | crictl runp |
停止Pod | 无 | crictl stopp |
提示:containerd只是作为测试练习,建议练习后还切回Docker引擎,就是把kubelet配置参数去掉并重启kubelet即可;
[root@k8s-node2 ~]# vim /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=
[root@k8s-node2 ~]# systemctl restart kubelet
然后去master节点上查看node2节点是否切换回了docker容器引擎
[root@k8s-master ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane,master 8d v1.20.11 192.168.1.1 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node1 Ready <none> 8d v1.20.11 192.168.1.2 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
k8s-node2 Ready <none> 8d v1.20.11 192.168.1.3 <none> CentOS Linux 7 (Core) 3.10.0-1160.66.1.el7.x86_64 docker://20.10.16
到这里,切换contained容器引擎就结束了;
通过学习,总结了以下几个切换contianerd的相关问题: