containerd实战

容器运行时

容器运行时(ContainerRuntime),运行于 kubernetes(k8s)集群的每个节点中,负责容器的整个生命周期。

其中 docker 是目前应用最广的。随着容器云的发展,越来越多的容器运行时涌现。为了解决这些容器运行时和 k8s 的集成问题,在 k8s1.5 版本中,社区推出了 CRI(ContainerRuntimeInterface,容器运行时接口)(如图 1 所示),以支持更多的容器运行时。

Kubelet 通过 CRI 和容器运行时进行通信,使得容器运行时能够像插件一样单独运行。可以说每个容器运行时都有自己的优势,这就允许用户更容易选择和替换自己的容器运行时。

img

CRI和OCI

img

OCI(OpenContainerInitiative,开放容器计划)定义了创建容器的格式和运行时的开源行业标准,包括镜像规范(ImageSpecification)和运行时规范(RuntimeSpecification)。

镜像规范定义了 OCI 镜像的标准。如图 2 所示,高层级运行时将会下载一个 OCI 镜像,并把它解压成 OCI 运行时文件系统包(filesystembundle)。

运行时规范则描述了如何从 OCI 运行时文件系统包运行容器程序,并且定义它的配置、运行环境和生命周期。如何为新容器设置命名空间(namepsaces)和控制组(cgroups),以及挂载根文件系统等等操作,都是在这里定义的。它的一个参考实现是 runC。我们称其为低层级运行时(Low-levelRuntime)。除 runC 以外,也有很多其他的运行时遵循 OCI 标准,例如 kata-runtime。

为什么弃用docker

目前 docker 仍是 kubernetes 默认的容器运行时。那为什么会选择换掉 docker 呢?主要的原因是它的复杂性。

如图 3 所示,我们总结了 docker,containerd 以及 cri-o 的详细调用层级。Docker 的多层封装和调用,导致其在可维护性上略逊一筹,增加了线上问题的定位难度(貌似除了重启 docker,我们就毫无他法了)。

Containerd 和 cri-o 的方案比起 docker 简洁很多。因此我们更偏向于选用更加简单和纯粹的 containerd 和 cri-o 作为我们的容器运行时。

img

我们对 containerd 和 cri-o 进行了一组性能测试,包括创建、启动、停止和删除容器,以比较它们所耗的时间。

如图 4 所示,containerd 在各个方面都表现良好,除了启动容器这项。从总用时来看,containerd 的用时还是要比 cri-o 要短的。

img

从功能性来讲,containerd 和 cri-o 都符合 CRI 和 OCI 的标准。从稳定性来说,单独使用 containerd 和 cri-o 都没有足够的生产环境经验。

但庆幸的是,containerd 一直在 docker 里使用,而 docker 的生产环境经验可以说比较充足。

可见在稳定性上 containerd 略胜一筹。所以我们最终选用了 containerd

Containerd历史

很久以前,Docker 强势崛起,以“镜像”这个大招席卷全球,对其他容器技术进行致命的降维打击,使其毫无招架之力,就连 Google 也不例外。Google 为了不被拍死在沙滩上,被迫拉下脸面(当然,跪舔是不可能的),希望 Docker 公司和自己联合推进一个开源的容器运行时作为 Docker 的核心依赖,不然就走着瞧。Docker 公司觉得自己的智商被侮辱了,走着瞧就走着瞧,谁怕谁啊!

很明显,Docker 公司的这个决策断送了自己的大好前程,造成了今天的悲剧。

紧接着,Google 联合 Red Hat、IBM 等几位巨佬连哄带骗忽悠 Docker 公司将 libcontainer 捐给中立的社区(OCI,Open Container Intiative),并改名为 runc,不留一点 Docker 公司的痕迹~~

这还不够,为了彻底扭转 Docker 一家独大的局面,几位大佬又合伙成立了一个基金会叫 CNCF(Cloud Native Computing Fundation),这个名字想必大家都很熟了,我就不详细介绍了。CNCF 的目标很明确,既然在当前的维度上干不过 Docker,干脆往上爬,升级到大规模容器编排的维度,以此来击败 Docker。

Docker 公司当然不甘示弱,搬出了 Swarm 和 Kubernetes 进行 PK,最后的结局大家都知道了,Swarm 战败。然后 Docker 公司耍了个小聪明,将自己的核心依赖 Containerd 捐给了 CNCF,以此来标榜 Docker 是一个 PaaS 平台。

很明显,这个小聪明又大大加速了自己的灭亡。

img

巨佬们心想,想当初想和你合作搞个中立的核心运行时,你死要面子活受罪,就是不同意,好家伙,现在自己搞了一个,还捐出来了,这是什么操作?也罢,这倒省事了,我就直接拿 Containerd 来做文章吧。

首先呢,为了表示 Kubernetes 的中立性,当然要搞个标准化的容器运行时接口,只要适配了这个接口的容器运行时,都可以和我一起玩耍哦,第一个支持这个接口的当然就是 Containerd 啦。至于这个接口的名字,大家应该都知道了,它叫 CRI(Container Runntime Interface)。

这样还不行,为了蛊惑 Docker 公司,Kubernetes 暂时先委屈自己,专门在自己的组件中集成了一个 shim(你可以理解为垫片),用来将 CRI 的调用翻译成 Docker 的 API,让 Docker 也能和自己愉快地玩耍,温水煮青蛙,养肥了再杀。。。

就这样,Kubernetes 一边假装和 Docker 愉快玩耍,一边背地里不断优化 Containerd 的健壮性以及和 CRI 对接的丝滑性。现在 Containerd 的翅膀已经完全硬了,是时候卸下我的伪装,和 Docker say bye bye 了。后面的事情大家也都知道了~~

Docker 这门技术成功了,Docker 这个公司却失败了。

开始Containerd

作为接替Docker运行时的Containerd在早在Kubernetes1.7时就能直接与Kubelet集成使用,只是大部分时候我们因熟悉Docker,在部署集群时采用了默认的dockershim。

V1.24起的版本的kubelet就彻底移除了dockershim,改为默认使用Containerd了,当然也可以使用 cri-dockerd 适配器来将 Docker Engine 与 Kubernetes 集成。可以参考官方文档

在这里插入图片描述

ontainerd是一个高级容器运行时,又名容器管理器。简单来说,它是一个守护进程,在单个主机上管理完整的容器生命周期:创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。

  • Containerd被设计成可以很容易地嵌入到更大的系统中。

  • Docker使用containerd来运行容器。

  • Kubernetes可以通过CRI使用containerd来管理单个节点上的容器。

但是较小的项目也可以从与containerd集成的便利中获益——例如,faasd使用containerd在独立的服务器上运行一个成熟的功能即服务解决方案。

image-20230311190848398

但是,以编程方式使用 containerd 并不是唯一的选择。它还可以通过可用客户端之一从命令行使用。由此产生的容器 UX 可能不像docker客户端提供的那样全面和用户友好,但它仍然是有用的,例如,用于调试或学习目的。

客户端命令

image-20230311191512455

由于新版本的k8s直接采用containerd作为容器运行时,因此,后续创建的服务,通过docker的命令无法查询,因此,如果有需要对节点中的容器进行操作的需求,需要用containerd的命令行工具来替换,目前总共有三种,包含:

  • ctr
  • crictl
  • nerdctl

ctr为最基础的containerd的操作命令行工具,安装containerd时已默认安装,因此无需再单独安装。

ctr的可操作的命令很少,且很不人性化,因此极力不推荐使用

Containerd 也有 namespaces 的概念,对于上层编排系统的支持,ctr 客户端 主要区分了 3 个命名空间分别是k8s.iomobydefault

比如操作容器和镜像:

# 查看containerd的命名空间
ctr ns ls;

# 查看containerd启动的容器列表
ctr -n k8s.io container ls

# 查看镜像列表
ctrl -n k8s.io image ls

# 导入镜像
ctr -n=k8s.io image import dashboard.tar

# 从私有仓库拉取镜像,前提是/etc/containerd/certs.d下已经配置过该私有仓库的非安全认证
ctr images pull --user admin:admin  --hosts-dir "/etc/containerd/certs.d"  172.21.65.226:5000/eladmin/eladmin-api:v1-rc1

# ctr命令无法查看容器的日志,也无法执行exec等操作

crictl

crictl 是遵循 CRI 接口规范的一个命令行工具,通常用它来检查和管理kubelet节点上的容器运行时和镜像。

主机安装了 k8s 后,命令行会有crictl 命令,无需单独安装。

crictl 命令默认使用k8s.io 这个名称空间,因此无需单独指定,使用前,需要先加一下配置文件:

cat /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

常用操作:

更换Containerd后,以往我们常用的docker命令也不再使用,取而代之的分别是 crictlctr 两个命令客户端。

  • crictl 是遵循CRI接口规范的一个命令行工具,通常用它来检查和管理kubelet节点上的容器运行时和镜像。
  • ctrcontainerd 的一个客户端工具。
  • ctr -v 输出的是 containerd 的版本,crictl -v 输出的是当前 k8s 的版本,从结果显而易见你可以认为 crictl 是用于 k8s 的。
  • 一般来说你某个主机安装了 k8s 后,命令行才会有 crictl 命令。而 ctr 是跟 k8s 无关的,你主机安装了 containerd 服务后就可以操作 ctr 命令。

使用crictl命令之前,需要先配置/etc/crictl.yaml如下:

runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

也可以通过命令进行设置:

crictl config runtime-endpoint unix:///run/containerd/containerd.sock
crictl config image-endpoint unix:///run/containerd/containerd.sock
命令 docker ctr(containerd) crictl(kubernetes)
查看运行的容器 docker ps ctr task ls/ctr container ls crictl ps
查看镜像 docker images ctr image ls crictl images
查看容器日志 docker logs crictl logs
查看容器数据信息 docker inspect ctr container info crictl inspect
查看容器资源 docker stats crictl stats
启动/关闭已有的容器 docker start/stop ctr task start/kill crictl start/stop
运行一个新的容器 docker run ctr run 无(最小单元为pod)
打标签 docker tag ctr image tag
创建一个新的容器 docker create ctr container create crictl create
导入镜像 docker load ctr image import
导出镜像 docker save ctr image export
删除容器 docker rm ctr container rm crictl rm
删除镜像 docker rmi ctr image rm crictl rmi
拉取镜像 docker pull ctr image pull ctictl pull
推送镜像 docker push ctr image push
登录或在容器内部执行命令 docker exec crictl exec
清空不用的容器 docker image prune crictl rmi --prune

更多命令操作,可以直接在命令行输入命令查看帮助。

docker --help
ctr --help
crictl --help

常规操作

# 查看容器列表
crictl ps

# 查看镜像列表
crictl images 

# 删除镜像
crictl rmi 172.21.65.226:5000/eladmin/eladmin-api:v1-rc1

# 拉取镜像, 若拉取私有镜像,需要修改containerd配置添加认证信息,比较麻烦且不安全
crictl pull nginx:alpine

# 执行exec操作
crictl ps 
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID              POD
d23fe516d2eeb       8b0e63fd4fec6       5 hours ago         Running             eladmin-api               0                   5dbae572dcb6b       eladmin-api-5d979bb778-tc5kz

# 注意只能使用containerid
crictl exec -ti d23fe516d2eeb bash

# 查看容器日志
crictl logs -f d23fe516d2eeb

# 清理镜像
crictl rmi --prune

推荐用这个(nerdctl)

推荐使用nerdctl,使用效果与docker命令的语法一致 github下载链接:https://github.com/containerd/nerdctl/releases

  • 精简 (nerdctl--linux-amd64.tar.gz): 只包含nerdctl
  • 完整 (nerdctl-full--linux-amd64.tar.gz): 包含 containerd, runc, and CNI等依赖

nerdctl 的目标并不是单纯地复制 docker 的功能,它还实现了很多 docker 不具备的功能,例如延迟拉取镜像(lazy-pulling)、镜像加密(imgcrypt)等。具体看nerdctl。

在这里插入图片描述

推荐使用 nerdctl,使用效果与 docker 命令的语法基本一致 , 官网https://github.com/containerd/nerdctl

安装:

# 下载精简版安装包,精简版的包无法使用nerdctl进行构建镜像
wget https://github.com/containerd/nerdctl/releases/download/v0.23.0/nerdctl-0.23.0-linux-amd64.tar.gz


# 解压后,将nerdctl 命令拷贝至$PATH下即可
cp nerdctl /usr/bin/

常用操作:

# 查看镜像列表
nerdctl -n k8s.io ps -a

# 执行exec
[root@k8s-slave1 ~]#nerdctl -n k8s.io exec -it ebb bash
root@eladmin-api:/opt/eladmin# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 Mar11 ?        00:00:00 sh -c java -Dspring.profiles.a
root          7      1  0 Mar11 ?        00:02:03 java -Dspring.profiles.active=
root         70      0  0 15:08 pts/0    00:00:00 bash
root         76     70  0 15:08 pts/0    00:00:00 ps -ef
root@eladmin-api:/opt/eladmin# 



# 登录镜像仓库
[root@k8s-slave1 ~]#nerdctl login 10.0.0.66:5000
Enter Username: admin
Enter Password: 
WARNING: Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@k8s-slave1 ~]#cat ~/.docker/config.json 
{
    "auths": {
        "10.0.0.66:5000": {
            "auth": "YWRtaW46YWRtaW4="
        }
    }
}[root@k8s-slave1 ~]#



# 拉取镜像,如果是想拉取了让k8s使用,一定加上-n k8s.io,否则会拉取到default空间中, k8s默认只使用k8s.io
[root@k8s-slave1 ~]#nerdctl -n k8s.io pull 10.0.0.66:5000/eladmin/eladmin-api:v1
10.0.0.66:5000/eladmin/eladmin-api:v1:                                            resolved       |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:a5227dad3ebd4bb165718a77e5144aa0ac3d32d91b6058ce387fe250d22951e9: done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:8875c67d330d7259065435373e94f8489f2d2fd71c29c00712f24042bdc8969a:   done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 0.1 s                                                                    total:   0.0 B (0.0 B/s)                                         
[root@k8s-slave1 ~]#



# 启动容器
nerdctl -n k8s.io run -d --name test nginx:alpine

# exec
nerdctl -n k8s.io  exec -ti test sh

# 查看日志, 注意,nerdctl 只能查看使用nerdctl命令创建从容器的日志,k8s中kubelet创建的产生的容器无法查看
nerdctl -n k8s.io logs -f test

# 构建,但是需要额外安装buildkit的包
nerdctl build . -t xxxx:tag -f Dockerfile

工作里怎么用nerdctl

  • 用了k8s后,对于业务应用的基本操作,90%以上都可以通过kubectl命令行完成
  • 对于镜像的构建,仍然推荐使用docker build 来完成,推送到镜像仓库后,containerd可以直接使用
  • 对于查看containerd中容器的日志,使用 crictl logs完成,因为ctr、nerdctl均不支持
  • 对于其他常规的containerd容器操作,建议使用nerdctl完成
Copyright © www.yuchaoit.cn 2025 all right reserved,powered by Gitbook作者:于超 2024-03-31 19:24:48

results matching ""

    No results matching ""