在Kubernetes 的早期版本(v1.5之前)仅支持这一个特定的容器运行时:Docker Engine。
后来k8s为了增加对使用其他容器运行时的支持,制定一个标准,让任何符合标准的容器都可以接入。这就是在2016年底的1.5版本中,K8s引入的新的接口标准,CRI: Container Runtime Interface 容器运行时接口[1]。
(图片来源:kubernetes.io)
CRI:一个插件接口,它使 kubelet 能够使用各种容器运行时,而无需重新编译。 Kubelet使用gRPC框架通过Unix sockets与容器运行时(或运行时的CRI shim)通信。其中Kubelet充当客户端,CRI shim充当服务端。 |
但由于Docker Engine 没有实现(CRI)接口,因此 Kubernetes 项目为了兼容Docker Engine,创建了特殊代码(shim)来进行过渡, 并使 dockershim 代码成为 Kubernetes 的一部分(内置在Kubelet)。
(图片来源:kubernetes.io)
dockershim 代码是一个临时解决方案(因此得名:shim)。它的存在拉长了调用链。同时也为Kubernetes维护者增加了沉重的负担。
移除dockershim之后,便不能直接使用docker engine(如需继续使用,需要额外安装对应的运行时cri-dockerd[2])。更换其他符合标准的容器运行时后,可以直接通过CRI进行调用(下图以containerd为例)。
因此,移除dockershim和docker engine之后。更换符合标准的运行时,其调用链更短,组件更少,更稳定。性能也更高,占用节点资源也更少。
除了docker,Kubernetes还支持其他容器运行时,如containerd、CRI-O 等可以供我们选择。根据官网《移除 Dockershim 的常见问题[3]》指引, 从Docker Engine 迁移到 containerd 是一个相对容易的转换,并将获得更好的性能和更少的开销。
各云厂商也在自己支持的k8s集群进行了变更,如:
AWS EKS 在官网《Amazon EKS 结束了对 Dockershim 的支持[4]》中宣布: 从 1.24
版开始,正式发布的 Amazon EKS AMI 将 containerd
作为唯一运行时。
阿里云也在官网《将节点容器运行时从Docker迁移到Containerd (aliyun.com)[5]》中说明:"如果您正在使用Docker作为容器运行时,则必须先迁移到使用containerd
作为容器运行时,否则将无法在ACK的后续更新中升级到Kubernetes 1.24
及更高版本。"
因此,containerd也成为了我们首选的替代品。
摘自官方文档: 《弃用 Dockershim 的常见问题 | Kubernetes[6]》
Ⅰ.现有的 Docker 镜像还能正常工作吗?
当然可以,docker build
创建的镜像适用于任何 CRI 实现。所有我们现有的镜像和往常一样工作,没有任何影响。
Ⅱ.私有镜像还能正常工作吗?
当然可以。所有 CRI 运行时均支持 Kubernetes 中相同的拉取(pull)Secret 配置, 不管是通过 PodSpec 还是通过 ServiceAccount 均可。
Ⅲ.当切换 CRI 底层实现时,应该注意什么?
Docker 和大多数 CRI(包括 containerd)的底层容器化代码是相同的,但其周边部分却存在一些不同。迁移时一些常见的关注点是:
日志配置
运行时的资源限制
直接访问 docker 命令或通过控制套接字调用 Docker 的节点供应脚本
需要访问 docker 命令或控制套接字的 kubectl 插件
需要直接访问 Docker 的 Kubernetes 工具(例如:kube-imagepuller)
配置像 registry-mirrors
和不安全的镜像仓库等功能
需要 Docker 保持可用、且运行在 Kubernetes 之外的,其他支持脚本或守护进程(例如:监视或安全代理)
GPU 或特殊硬件,以及它们如何与你的运行时和 Kubernetes 集成
如果只是用了 Kubernetes 资源请求/限制或基于文件的日志收集 DaemonSet,它们将继续稳定工作,但是如果你用了自定义了 dockerd 配置,则可能需要为新容器运行时做一些适配工作。
在containerd下调试镜像和容器
我们使用containerd
之后,很多人担心,没有了docker,我们平时的调试操作,如查看镜像(docker images)、查看容器(docker ps)等还能怎么进行下去?
Containerd 不支持 docker API 和 docker CLI,但是可以通过 cri-tool 命令实现类似的功能。
更换Containerd后,以往我们常用的docker命令也不再使用,可替代的分别是crictl和ctr两个命令客户端。
安装
#ctr在containerd 安装之后就默认安装好了,无需额外安装。
#crictl需要额外安装
#官网地址 https://github.com/kubernetes-sigs/cri-tools
VERSION="v1.24.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz
#首次使用,需要配置crictl连接到containerd的sockets
crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock
区别
(图片来源:zhihu.com)
ctr是 containerd 的一个客户端工具。 crictl 是 CRI 兼容的容器运行时命令行接口,可以使用它来检查和调试 k8s 节点上的容器运行时和应用程序,需要额外安装。 |
ctr -v 输出的是 containerd 的版本,crictl -v 输出的是当前 k8s 的版本。
从结果显而易见,你可以认为 crictl 是用于 k8s 的。
Containerd增加了namespace的概念
Containerd 相比于docker , 多了namespace(命名空间)的概念, 每个image和container 都会在各自的namespace下可见,但这不影响我们的使用。
k8s会默认使用k8s.io 作为命名空间,所以用ctr调试的时候需要指定。
如果再安装了docker engin的话,会使用moby命名空间。
(图片来源:cnblogs.com)
从上图可以看到,ctr 需要指定namespace, 而crictl 不需要指定namespace,它默认就是使用k8s.io这个namespace。
所以在大多数的情况下,调试时 crictl xxx 约等于 ctr -n k8s.io xxx ,他们操作的都是k8s相关内容,功能也相似。
使用crictl和ctr调试镜像和容器
ctr -n k8s.io images ls | grep -v '@'
#注意: 这里 grep -v '@'只是为了简化输出
crictl image ls
可以看出,执行 crictl image list 和 ctr -n k8s.io image list 的结果非常相似,区别在于ctr -n k8s.io images ls显示的结果更全。
ctr -n k8s.io container ls
crictl ps
注意: crictl ps的结果不包括一些特殊的容器(例如pause),仅显示业务使用到的容器。 而ctr 显示的所有的容器。
前文说到,crictl是用于k8s的,它比docker和ctr 更强大的地方在于可以查看本机的所有pod状态。而ctr是无法看到pod信息的。
crictl pods
#显示pod状态pods
crictl inspectp 0a619c781a705
#查询容器id
ctr -n k8s.io container ls | grep 0edb8f67f200a
# ctr task 才是对容器操作的子命令
ctr -n k8s.io task ls | grep 0edb8f67f200a
# 容器id要用全称才能识别
ctr -n k8s.io task exec -t --exec-id bash_1 0edb8f67f200a bash
# 进入容器,--exec-id 可以指定任意值,不要和已有的--exec-id 重复即可。
ctr -n k8s.io task exec -t --exec-id bash_1 0edb8f67f200a666df58a915355538a78c2a419bec2d3a8d134929ed2c79ed4e bash
#查询容器id
crictl ps | grep 0edb8f67f200a
#同样进入容器
crictl exec -it 0edb8f67f200a bash
更多命令对比
镜像相关功能 | Docker | (containerd) | (kubernetes) |
---|---|---|---|
显示本地镜像列表 | docker images | ctr image ls | crictl images |
拉取镜像 | docker pull | ctr image pull | crictl pull |
推送镜像 | docker push | ctr image push | 无 |
删除本地镜像 | docker rmi | ctr image rm | crictl rmi |
导入镜像 | docker load | ctr image import | 无 |
导出镜像 | docker save | ctr image export | 无 |
查看容器数据信息 | docker inspect | ctr container info | crictl inspect |
容器相关功能 | Docker | ctr (containerd) | (kubernetes) |
---|---|---|---|
显示容器列表 | docker ps | ctr task ls ctr container ls | crictl ps |
创建新的容器 | docker create | ctr container create | crictl create |
运行新的容器 | docker run | ctr run | 无 (最小单元为pod) |
启动/关闭已有的容器 | docker start/stop | ctr task start/kill | crictl start/stop |
删除容器 | docker rm | crictl rm | |
查看容器详情 | docker inspect | crictl inspect | |
查看容器日志 | docker logs | 无 | crictl logs |
attach | docker attach | crictl attach | |
在容器内部执行命令 | docker exec | 无 | crictl exec |
查看容器资源 | docker stats | 无 | crictl stats |
Pod 相关功能 | Docker | ctr (containerd) | crictl (kubernetes) |
---|---|---|---|
显示 Pod 列表 | 无 | 无 | crictl pods |
查看 Pod 详情 | 无 | 无 | crictl inspectp |
运行 Pod | 无 | 无 | crictl runp |
停止 Pod | 无 | 无 | crictl stopp |
参考链接:
[1]标准CRI: https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes
[2]容器运行时cri-dockerd:https://kubernetes.io/docs/setup/production-environment/container-runtimes
[3][6]移除 Dockershim 的常见问题: https://kubernetes.io/zh-cn/blog/2022/02/17/dockershim-faq/#which-cri-implementation-should-i-use
[4]Amazon EKS 结束了对 Dockershim 的支持: https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/dockershim-deprecation.html
[5]将节点容器运行时从Docker迁移到Containerd (aliyun.com): https://help.aliyun.com/document_detail/451213.html