1 容器发展史
在2020 年底,Kubernetes 宣布不再推荐使⽤Docker作为容器运⾏时,并在后续的版本中停⽌⽀持Docker。这个决定肯定会对原有的Kubernetes⽤户产⽣⼀定的影响,同时也引发了⼀系列问题:如果不使⽤Docker,使⽤什么替代品?
Kubernetes为什么要停⽌⽀持Docker?
为了回答这些问题,我们需要简要回顾⼀下容器技术的发展史。
1.1 初始阶段
Docker 的发展经历了⼀系列的变⾰,Docker最初使⽤的架构是Container+libContainer :在这个阶段,Docker主要分为两个部分:Docker Daemon(守护进程)和 Docker Client(客户端)。
- 1、Docker Daemon 负责处理 Docker Client 发送的请求,并对请求进⾏相应的操作(如:镜像、容器的管理)。
- 2、在管理 Linux 容器时,Docker Daemon 依赖 libContainer 这个库来完成底层的容器操作。
libContainer 提供了⼀系列接⼝和功能,⽤于创建、启动、停⽌和销毁容器,以及配置容器的资源限制、⽹络、存储等。通过 libContainer,Docker Daemon 可以实现对容器的完整管理。
Docker Client <-------请求/响应------------> Docker Daemon <-------使用------------>libContainer
Docker 为了推动容器技术的标准化和通⽤性,将libContainer赠送给了Open Container Initiative(OCI)并将其重命名为 runc 。OCI 是⼀个专⻔制定容器技术标准的组织,⽬的是让容器技术变得更加开放、透明和互相兼容。
- 镜像标准:定义了容器镜像的结构和内容,包括镜像⽂件的组织⽅式、⽂件和⽬录类型等,以及如何创建符合标准的镜像⽂件。
- 运⾏时标准:规定了如何从运⾏时⽂件系统启动容器程序,包括容器接收的指令类型、指令⾏为、⽣命周期管理,以及如何配置名称空间、Cgroup 和⽂件系统挂载等。
runc 是⼀个独⽴的可执⾏程序,根据OCI 标准启动和管理容器进程。这样⼀来,Docker 容器运⾏时的核⼼组件(即容器的创建和管理)不再紧密依赖于 Docker守护进程。
意味着Docker 容器运⾏时的核⼼组件(即 runc)和 Docker 守护进程之间的关联变得更加松散。Docker 守护进程可以直接调⽤ runc 来管理容器,⽽不再需要依赖于内部的 libContainer 库。这使得其他容器运⾏时(如 containerd 或 CRIO)也可以采⽤相同的 OCI 标准,实现与 Docker 更好的兼容性。
1.2 发展阶段
从Docker 1.11 版本开始,Docker 容器的运⾏和管理不再仅依赖于 Docker Daemon。它通过整合 Containerd、runc 和 container-shim 等组件共同完成。 Docker Daemon 仍然负责与 Docker Client 交互,以及管理 Docker 镜像。⽽将容器的底层运⾏时操作交给了containerd和 runc。
容器的⽣命周期管理变得更加模块化,Docker Daemon 和 Containerd 通过gRPC 接⼝进⾏通信。Containerd 进⼀步调⽤ runc 来实际启动和管理容器进程。为了解决容器进程和 runc 之间的依赖,Docker 引⼊了 container-shim。container-shim 是⼀个轻量级的进程,⽤于在容器和 runc 之间进⾏通信,使容器在 runc 退出后能够继续运⾏。
Docker Client <---------请求/响应----------> Docker Daemon<---------gRPC 接⼝----------> Containerd <---------调用----------> container-shim <---------调用----------> runc
当我们要创建⼀个容器的时候,现在Docker Daemon并不能直接帮我们创建了
- 1. Docker Daemon 请求 containerd 进⾏容器的创建。
- 2. containerd 不直接创建容器,因为containerd如果故障,所有容器都会故障,因此引⼊了containerd-shim,来进⾏容器的创建
- 3. containerd-shim 调⽤ runc(符合 OCI 标准)来创建容器。
- 4. runc 创建容器后退出,containerd-shim 成为容器进程的⽗进程,负责状态收集和清理⼯作。
通过引⼊containerd 和 containerd-shim,Docker 架构变得更加模块化,各个组件之间的职责分⼯更加明确,从⽽有助于提⾼整体的稳定性和可维护性。
1.3 CRI诞⽣
在容器技术⻜速发展的背景下,Docker 将重⼼转向到了编排⼯具的开发上,进⽽将 containerd 捐赠给 CNCF。这⼀举措既推动了容器技术的发展,还吸引了更多社区成员的参与,使得 Docker 能够集中精⼒开发 Swarm 等⼯具。此举还能降低 Docker ⾯临的市场竞争⻛险。
然⽽,在Kubernetes 编排⼯具诞⽣之后,它为了保持中⽴性、同时⽀持多种容器运⾏时与Kubernetes 对接,以避免对特定技术的依赖和Docker 公司⼀家独⼤的局⾯,因此Kubernetes 在 1.5 版本引⼊了 CRI 。由Google 和红帽共同推动CRI标准的产⽣。
CRI(Container Runtime Interface,容器运⾏时接⼝)是 Kubernetes 设计的⼀组接⼝,⽤于与容器运⾏时互动。简单来说,只要容器运⾏时实现了 CRI 接⼝,就可以与 Kubernetes 平台集成。然⽽,并⾮所有的容器运⾏时都会直接实现 CRI 接⼝,因此出现了“shim(垫⽚)”这个概念。shim 的作⽤类似于适配器(USB转Type-c),将各种不同的容器运⾏时的接⼝适配到 Kubernetes 的 CRI接⼝上。如,dockershim 就是 Kubernetes 为了将 Docker 接⼝适配到 CRI 接⼝上,⽽设计的⼀种实现
当时,由于Docker 在容器领域的地位举⾜轻重,Kubernetes 便直接将dockershim 嵌⼊到 kubelet 中。因此,对于使⽤Docker 容器运⾏时的⽤户⽽⾔,⽆需额外安装配置适配器,如下图所示:
1.4 弃⽤阶段
实际上,在使⽤Kubernetes 与 Docker 结合的情况下,整个调⽤链相当⻓。然⽽,对于真正的容器相关操作,Containerd 已经完全⾜够。尽管 Docker 的调⽤链很⻓,但这并未影响其受欢迎程度。但对于 Kubernetes 来说,这些功能并⾮必要,因为它仅通过接⼝操作容器。所以 Kubernetes 可以⾃然地将容器运⾏时切换到 Containerd。
其次为了⽀持Docker,Kubernetes 开发了⼀个名为 dockershim 的垫⽚。随着时间的推移,Kubernetes 受众不断扩⼤,同时 Containerd 也成功从 CNCF 毕业,其健壮性得到了显著提升。在这种情况下,Kubernetes 终于可以考虑摒弃dockershim 垫⽚。
因为在维护dockershim 时,Kubernetes 遇到了许多问题,⾸先 Kubernetes 需要处理 Docker 中很多与其核⼼功能⽆关的内容。此外,随着 Docker 版本的升级,dockershim 不得不进⾏相应的适配,并进⾏兼容性测试,这为维护⼯作带来了额外的复杂性。
containerd 1.0 版本开始,通过⼀个独⽴的 CRI-Containerd 进程来适配 CRI,原因是 containerd 最初也需要适配其他系统(如 swarm),因此没有直接实现CRI。这个对接⼯作由 CRI-Containerd shim 完成。
随后,在containerd 1.1 版本中,移除了 CRI-Containerd shim,并将适配逻辑以插件形式集成到 containerd 主进程中。如今,调⽤过程变得更加简洁。
1.5 CRI-O
Kubernetes 社区也开发了⼀个专⻔⽤于 Kubernetes 的 CRI 运⾏时,名为 CRI-O,CRI-O 直接兼容 CRI 和 OCI 规范,为 Kubernetes 提供了更加⾼效的容器运⾏时⽀持。https://cri-o.io/
2 Containerd
2.1 安装
1、安装 libseccomp 依赖,但默认的libseccomp版本为2.3⽆法版本
containerd1.6版本,需要安装2.4版本以上;
wget https://mirrors.aliyun.com/centos/8/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm
rpm -Uvh libseccomp-2.5.1-1.el8.x86_64.rpm
2、下载containerd1.6,⽽后解压
tar -xf cri-containerd-1.6.18-linux-amd64.tar.gz -C /
3、创建Containerd配置
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
4、运⾏containerd
systemctl start containerd
systemctl status containerd
5、检查
2.2 镜像管理
1、拉取镜像
ctr images pull hub.atomgit.com/amd64/alpine:3.15.10
2、查看镜像
ctr images ls
ctr images list -q
3、删除镜像
delete, del, remove, rm remove one or more images by reference
ctr images rm hub.atomgit.com/amd64/alpine:3.15.10
4、由于containerd和docker存储数据⽬录不⼀致,因此互相之间的镜像⽆法查看,那么docker构建的镜像如何提供给containerd
- 1、dockerfile构建镜像
- 2、docker push 推送私有仓库
- 3、containerd通过私有仓库获取镜像即可
- 4、如果私有仓库存在⽤户密码认证
ctr image pull --plain-http --user admin:Harbor12345 192.168.137.130/library/redis-photon:latest
--plain-http默认拉取使用https,此参数运行使用http
2.3 容器管理
1、启动容器
语法:ctr containers run <image_name> <container_name>
示例:
ctr run -d hub.atomgit.com/amd64/alpine:3.15.10 mytest01 /bin/sh# 后台运⾏
ctr run -t hub.atomgit.com/amd64/alpine:3.15.10 mytest02 /bin/sh 前台运⾏
3、进⼊容器(-exec-id 可以指定字符串)
ctr tasks exec -t --exec-id sh mytest01 /bin/sh
4、查看容器
5、删除容器
ctr containers delete mytest02
2.4 私有镜像
默认ctr拉取公开镜像⽆需输⼊⽤户名和密码,但如果是私有仓库镜像则⽆法正常获取;
1、⽅式⼀,需要使⽤--user指定明确指定⽤户名和密码
ctr image pull --plain-http --user admin:Harbor12345 192.168.137.130/library/redis-photon:latest
2、⽅式⼆,通过crictl下载镜像,在配置⽂件中定义对应的私有仓库信息,以及⽤户名称和密码
vim /etc/containerd/config.toml
2.1直接配置文件修改
2.2 配置文件引用配置文件
2.5 Nerdctl
containerd使⽤ctr管理ctr使⽤起来还是不太顺⼿,为了能够让⼤家更好的转到containerd 上⾯来,社区提供了⼀个新的命令⾏⼯具:nerdctl。nerdctl 是⼀个与 docker cli ⻛格兼容的 containerd 客户端⼯具,⽽且直接兼容 docker compose 的语法的,这就⼤⼤提⾼了直接将 containerd 作为本地开发、测试或者单机容器部署使⽤的效率。
1、下载并安装nerdctl
wget https://github.com/containerd/nerdctl/releases/download/v1.4.0/nerdctl-full-1.4.0-linux-amd64.tar.gz
tar xf nerdctl-full-1.4.0-linux-amd64.tar.gz
cp bin/nerdctl bin/buildctl bin/buildkitd /usr/local/bin/
# 添加命令补全
echo 'source <(nerdctl completion bash)' >> /etc/profile
source /etc/profile
2、测试nerdctl命令
2.6 buildkit
1、编写dockerfile
cp dockerfile Containerfile
2、执⾏build
nerdctl build -t 192.168.137.130/library/alpine-test:latest .
3、拷⻉buildkitd启动脚本
cp lib/systemd/system/buildkit.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable buildkit --now
4、再次执⾏build构建命令
5、镜像推送
这个工具默认推送https,直接用ctr解决了
ctr image push --plain-http --user admin:Harbor12345 192.168.137.130/library/alpine-test:latest