内容目录

容器发展史

在2020年底,kubernetes宣布不再推荐使用docker作为容器运行时,并在后续的版本中停止支持docker
这个决定肯定会对原有的kubernetes用户产生一定的影响,同时也引发了一系列问题:如果不使用docker,使用什么替代品?
kubernetes为什么要停止支持docker
为了回答这些问题,我们需要简要回顾一下容器技术的发展史。

初始阶段

docker的发展经历了一系列的改革,docker最初使用的架构是container+libcontainer
在这个阶段,docker主要分为两个部分:docker daemon(守护进程)和docker client(客户端)

  • 1.docker daemon负责处理docker client发送的请求,并对请求进行相应的操作(如:镜像、容器的管理)。
  • 2.而docker daemon依赖libcontainer这个库来完成底层的容器操作。例如:容器创建启动、停止和销毁容器等;

通过libcontainerdocker daemon可以实现对容器的完整管理。

file

docker为了推动容器技术的标准化和通用性,docker将核心库libcontainer赠送给了open container initiative(OCI)并重命名为runc
OCI是一个致力于指定容器技术标准的组织,旨在使容器技术更加开放、透明和互相兼容。
OCI定义了两个主要标准:

  • 镜像标准:规定了容器镜像的解构和内容,包括镜像文件的组织方式、文件和目录的类型,以及如何创建符合标准的镜像文件。
  • 运行时标准:指定了从运行时文件系统启动容器程序的方法,包括接收的指令类型、行为、生命周期管理,以及名称空间、Cgroup和文件系统挂载的配置。

runc是一个独立的可执行程序,按照OCI标准启动和管理容器进程。
这样的设计使得docker容器运行时的核心组件,即容器的创建和管理不再依赖于docker守护进程。
而是直接调用runc来管理容器,从而与内部的libcontainer库解耦。

file

发展阶段

docker1.11版本开始,docker容器的运行和管理不再完全依赖于docker daemon
它整合container、runccontainer-shim等组件共同完成。
docker daemon仍然负责与docker client交互,以及docker镜像的管理,但将容器的底层运行时操作交给了containerdrunc

  • 1.docker daemon通过grpc请求containerd进行容器的创建。
  • 2.containerd不直接创建容器,因为containerd如果故障,所有容器都会故障,因此引入了containerd=shim,来进行容器的创建。
  • 3.containerd-shim调用runc(符合OCI标准)来创建容器
  • 4.runc创建容器后退出,contained-shim成为容器进程的父进程,负责对容器进行监控和清理。

通过引入containerdcontainerd-shimdocker架构变得更加模块化,各个组件之间的职责分工更加明确,从而有助于提高整体的稳定性和可维护性。

file

CRI诞生

随着容器技术的快速发展,docker逐渐将重心转移至编排工具的开发,并将containerd捐赠给了云原生计算基金会(CNCF)。
这一策略不仅促进了容器技术的进一步发展,也吸引了更多社区成员的参与,使得docker能够专注于开发如swarm这样的编排工具。

然而,随着kubernetes编排工具出现,它为了保持中立性、支持多种容器运行时与kubernetes对接,以避免对特定技术的依赖和docker公司一家独大的局面,因此kubernetes在1.5版本引入了CRI

CRI(container runtime interface,容器运行时接口)是kubernetes设计的一组接口,用于与容器运行时接口对接。
简单来说,只要容器运行时实现了CRI接口,就可以与kubernetes平台集成。
然而,并非所有的容器运行时都会直接实现CRI接口,因此出现了shim(垫片)这个概念。
shim的作用类似于适配器(usbtype-c),将各种不同的容器运行时的接口适配到kuburnetesCRI接口上。

由于docker在容器领域的地位举足轻重,kubenetes便直接将dockershim嵌入到kubelet中。
因此,对于使用docker容器运行时的用户而言,无需额外安装配置适配器。

弃用阶段

在使用kubernetesdocker的场景中,为了实现docker的无缝对接,kubernetes开发了dockershim垫片。
虽然docker可以与kuburnetes无缝集成,但也导致了整个调用链变得更长。
尽管docker的调用链较长,但其受欢迎程度未受影响。
然而,对于kubernetes来说,这些额外的调用并不是必需的。
实际上,对于运行一个容器而言,直接使用containerd已经足够了。

file

随着时间的推移,kubernetes的使用群体持续增长,同时containerd也在CNCF顺利毕业,并显著增强了其健壮性。
在这种情况下,kubernetes终于可以考虑移出dockershim垫片。
因为在维护dockershim时,kubernetes遇到了许多问题,首先kubernetes需要处理docker中很多与其核心功能无关的内容。
此外,随着docker版本的升级,dockershim不得不进行相应的适配,并进行兼容性测试,这为kubernetes的维护工作带来了额外的复杂性。

containerd 1.0版本开始,它通过一个独立的进程CRI-containerd,来适配kubernetes的容器运行时接口(CRI)。
这是因为containerd最初需要兼容多个系统,如swarm,所以并未直接实现CRI。这个适配过程最初由CRI-containerd shim组件完成。

file

containerd 1.1版本中,CRI-containerd shim被移除,并且将适配器以插件形式集成到containerd主进程中。
整个调用过程变得更加简介和高效。

file

CRI-O

kubernetes社区也开发了一个专门用于kubernetesCRI运行时,名为CRI-OCRI-O直接兼容CRIOCI规范,为kubernetes提供了更加高效的容器运行时支持。

containerd

  1. 安装
    yum install containerd

  2. 生成containerd配置
    containerd config default > /etc/containerd/config.toml

  3. 运行containerd

systemctl start containerd
systemctl status containerd
  1. 检查containerdrunc的版本
ctr version
Client:
  Version:  1.6.33
  Revision: d2d58213f83a351ca8f528a95fbd145f5654e957
  Go version: go1.21.11

Server:
  Version:  1.6.33
  Revision: d2d58213f83a351ca8f528a95fbd145f5654e957
  UUID: 8e2e5be1-ced2-41c6-8678-3ed2107c662b

runc --version
runc version 1.1.12
commit: v1.1.12-0-g51d5e94
spec: 1.0.2-dev
go: go1.21.11
libseccomp: 2.3.1

镜像管理

  1. 拉取镜像:ctr images pull <image_name>
# 公开镜像
ctr images pull docker.io/library/alpine:latest
# 私有镜像
Bash
ctr images pull --user admin:Harbor12345 harbor.oldxu.net/infra/nginx:1.20
  1. 查看镜像:ctr images list -q
ctr images ls -q
 docker.io/library/alpine:latest
  1. 删除镜像:ctr images remove <image_name>
    ctr images remove docker.io/library/alpine:latest

  2. 由于containerddocker存储数据目录不一致,因此互相之间的镜像无法查看,那么docker构建的镜像如何提供给containerd

# 1、dockerfile构建镜像
# 2、docker push 推送私有仓库
# 3、containerd通过私有仓库获取镜像即可

容器管理

  1. 启动容器,ctr containers run <options> <image_name> <container_name>
ctr  run -d docker.io/library/alpine:latest mytest1 /bin/sh # 后台运⾏

ctr  run -t docker.io/library/alpine:latest mytest2 /bin/sh # 前台运行
  1. 查看容器
ctr c list
CONTAINER    IMAGE                              RUNTIME
mytest1      docker.io/library/alpine:latest    io.containerd.runc.v2
mytest2      docker.io/library/alpine:latest    io.containerd.runc.v2

ctr task list
TASK       PID       STATUS
mytest1    122141    RUNNING
  1. 进入容器(--exec-id sh mytest1 /bin/sh)
    ctr task exec -t --exec-id sh mytest1 /bin/sh

  2. 删除容器,ctr containers delete <containers_name>

ctr task kill --signal 9 mytest1
ctr containers delete mytest1

nerdctl

前面使用ctr工具来管理containerd的镜像与容器,不是特别直观,特别是已经习惯使用docker命令行的用户

为了让这部分用户更容易过渡到containerd,社区开发了一个新的命令行工具:nerdctl
这个工具模仿了docker的命令行界面,使得用户能够更顺畅地从docker迁移到containerd

  1. 下载nerdctl
wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-amd64.tar.gz
# 加速地址
wget https://mirror.ghproxy.com/https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-amd64.tar.gz
  1. 安装nerdctl
tar xf nerdctl-full-1.7.6-linux-amd64.tar.gz -C nerdctl-full-1.7.6/
cp nerdctl-full-1.7.6/bin/nerdctl /usr/local/bin/
  1. 配置nerdctl命令补全功能
echo 'source <(nerdctl completion bash)' >> /etc/profile
source /etc/profile
  1. 测试nerdctl命令
nerdctl pull nginx:1.26
nerdctl images
  1. nerdctl运行容器
wget https://mirror.ghproxy.com/https://github.com/containernetworking/plugins/releases/download/v1.5.0/cni-plugins-linux-amd64-v1.5.0.tgz

mkdir /opt/cni/bin -p
tar xf cni-plugins-linux-amd64-v1.4.1.tgz -C /opt/cni/bin/
nerdctl run -d -p8888:80 nginx:1.26

buildkitd

buildkit是用于构建容器镜像的工具,它包含了两个主要组件:buildctlbuildkitd

  • buildctl是一个命令行工具(客户端),负责与buildkitd守护进程进行通信。开发者使用buildctl提交镜像构建请求。
  • buildkitdbuildkit的守护进程(服务端),这是一个后台进程,专门处理来自客户端的构建请求。
  1. 编写dockerfile

  2. 使用nerdctl执行build
    nerdctl build -t harbor.oldxu.net/app/nginx:1.26 .会报错。

  3. 拷贝buildctl、buildkitd以及buildkitd启动脚本

cp nerdctl-full-1.7.6/bin/buildctl nerdctl-full-1.7.6/bin/buildkitd /usr/local/bin/
cp nerdctl-full-1.7.6/lib/systemd/system/buildkit.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl start buildkit.service
systemctl status buildkit.service
  1. 再次执行build构建命令
nerdctl build -t harbor.oldxu.net/app/nginx:1.26 .
nerdctl images

容器内使用nerdctl

nerdctl run -d --name jenkins \
--hostname "jenkins.oldxu.net" \
--restart=always \
-p 8080:8080 \
-p 50000:50000 \
-u root \
--privileged=true \
-e TZ=Asia/Shanghai \
-v /etc/localtime:/etc/localtime:ro \
-v jenkins_home:/var/jenkins_home \
-v /usr/local/bin/nerdctl:/usr/local/bin/nerdctl \
-v /run/containerd/containerd.sock:/run/containerd/containerd.sock \
-v /usr/local/bin/buildctl:/usr/local/bin/buildctl \
-v /run/buildkit/buildkitd.sock:/run/buildkit/buildkitd.sock \
--add-host gitlab.oldxu.net:10.0.0.110 \
--add-host nexus.oldxu.net:10.0.0.121 \
--add-host sonar.oldxu.net:10.0.0.130 \
--add-host harbor.oldxu.net:10.0.0.185 \
uhub.service.ucloud.cn/oldxu/jenkins:2.452.1-lts-jdk17
最后修改日期: 2024年9月21日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。