Docker Engine - Containerd

庆云2周前技术文章28

1、背景

  • Docker 崛起
    很久以前,Docker 强势崛起,以 “镜像” 这个大招席卷全球,对其他技术进行致命的降维打击,使其毫无招架之力,就连 Google 也不例外。Google 为了不被拍死在沙滩上,被迫拉下脸面,希望 Docker 公司和自己联合推进一个开源的容器运行时作为 Docker 的核心依赖,然而 Docker 公司的这个决策断送了自己的大好前程,造成了今天的悲剧。


  • libcontainer 捐赠
    Google 联合 Red Hat、IBM 等几位巨佬将 Docker 公司 libcontainer 捐给中立的社区(OCI,Open Container Intiative),并改名为 runc。


  • CNCF(云原生计算基金会)
    为了彻底扭转 Docker 一家独大的局面,几位大佬又合伙成立了 CNCF(Cloud Native Computing Fundation),CNCF 的目标很明确,既然容器的的维度上比不过 Docker,干脆升级到大规模容器编排的维度,以此来击败 Docker。造成了 Swarm 和 Kubernetes PK 的场面,最后的结局 Swarm 战败。
    然后 Docker 公司将自己的核心依赖 Containerd 捐给了 CNCF,以此来标榜 Docker 是一个 PaaS 平台。很明显,这个小聪明又加速了 Docker 的失败。
    为了表示 Kubernetes 的中立性,当然要有个标准化的容器运行时接口,只要适配了这个接口的容器运行时,都可以和 Kubernetes 集成,第一个支持这个接口的当然就是 Containerd。至于这个标准化的容器运行时接口的名字,它叫 CRI(Container Runntime Interface)。


  • 温水煮青蛙,养肥了再杀
    Kubernetes 在自己的组件中集成了一个 Shim,用来将 CRI 的调用翻译成 Docker 的 API,让 Docker 也能和 Kubernetes 集成。就这样,Kubernetes 一边和 Docker 继承,一边不断优化 Containerd 的健壮性以及和 CRI 对接的丝滑性。现在 Containerd 的兼容性已经很好的情况下,是时候和 Docker say bye bye 了,最终在 Kubernetes 1.24 版本中从 Kubelet 中删除了 Dockershim 的代码,至此 Kubernetes 彻底舍弃 Docker。


  • 时至今日
    时至今日,Containerd 已经变成一个工业级的容器运行时了,连口号都有了:超简单!超健壮!可移植性超强!
    当然,为了不让 Docker 误会,Containerd 声称自己的设计目的主要是为了嵌入到一个更大的系统中(暗指 Kubernetes),而不是直接由开发人员或终端用户使用。
    事实上,Containerd 现在基本上啥都能干了,开发人员或者终端用户可以在宿主机中管理完整的容器生命周期,包括容器镜像的传输和存储、容器的执行和管理、存储和网络等。


2、Containerd 架构

architecture.png


Containerd 仍然采用标准的 C/S 架构,服务端通过 GRPC 协议提供稳定的 API,客户端通过调用服务端的 API 进行高级的操作。


为了解耦,Containerd 将不同的职责划分给不同的组件,每个组件就相当于一个子系统(subsystem),连接不同子系统的组件被称为模块。

总体上 Containerd 被划分为两个子系统:

  • Bundle
    在 Containerd 中,Bundle 包含了配置、元数据和根文件系统数据,你可以理解为容器的文件系统。而 Bundle 子系统允许用户从镜像中提取和打包 Bundles。

  • Runtime
    Runtime 子系统用来执行 Bundles,比如创建容器。 


其中,每一个子系统的行为都由一个或多个模块协作完成。每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的。例如,上图中的每一个长虚线的方框都表示一种类型的插件,包括 Service PluginMetadata PluginGC PluginRuntime Plugin 等,其中 Service Plugin 又会依赖 Metadata PluginGC PluginRuntime Plugin。每一个小方框都表示一个细分的插件,例如 Metadata Plugin 依赖 Containers PluginContent Plugin 等。总之,万物皆插件,插件就是模块,模块就是插件。

image.png


  • Content Plugin
    提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里。

  • Snapshot Plugin
    用来管理容器镜像的文件系统快照。镜像中的每一个 layer 都会被解压成文件系统快照,类似于 Docker 中的 graphdriver。

  • Metrics
    暴露各个组件的监控指标。 


从总体来看,Containerd 被分为三个大块:StorageMetadataRuntime,可以将上面的架构图提炼一下:

architecture1.png

这是使用 bucketbench 对 DockercrioContainerd 的性能测试结果,包括启动、停止和删除容器,以比较它们所耗的时间:

xingn.png


3、Containerd 安装

3.1 环境

操作系统:Ubuntu 20.04

3.2 安装


  1. 先决条件

$ cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

$ sudo modprobe overlay
$ sudo modprobe br_netfilter

"设置必需的sysctl参数,这些参数在重新启动后仍然存在"
$ cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

"应用sysctl参数而无需重新启动"
$ sudo sysctl --system

  1. 卸载原有 docker or containerd

$ sudo apt-get remove docker docker-engine docker.io containerd runc

  1. 更新 apt 程序包并安装程序包,以允许 apt 通过 https 使用存储库

$ sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

  1. 添加 docker 的官方 GPG 密钥

$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key --keyring /etc/apt/trusted.gpg.d/docker.gpg add -

  1. 设置存储库

$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

  1. 下载并安装

$ wget https://github.com/containerd/containerd/releases/download/v1.6.1/cri-containerd-cni-1.6.1-linux-amd64.tar.gz
$ sudo tar --no-overwrite-dir -C / -xzf cri-containerd-cni-1.6.1-linux-amd64.tar.gz
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now containerd
$ sudo mkdir -p /etc/containerd
$ sudo su
# containerd config default > /etc/containerd/config.toml
# exit

"配置systemd cgroup为驱动程序:编辑/etc/containerd/config.toml设置SystemdCgroup = true"
$ sudo vim /etc/containerd/config.toml

"启动containerd"
$ sudo systemctl start containerd
$ sudo systemctl enable containerd
$ sudo systemctl status containerd

"验证containerd"
$ sudo ctr version
Client:
  Version:  v1.6.1
  Revision: 10f428dac7cec44c864e1b830a4623af27a9fc70
  Go version: go1.17.2

Server:
  Version:  v1.6.1
  Revision: 10f428dac7cec44c864e1b830a4623af27a9fc70
  UUID: 5dc8deba-a794-4b39-bacb-aa9c790f7465

4、Containerd 使用


4.1 命名空间

Containerd 也支持命名空间,如果不指定,ctr 默认是 default 空间。

# 列出命名空间
$ sudo ctr ns list

# 创建命名空间
$ sudo ctr ns create myns

# 删除命名空间
$ sudo ctr ns remove myns

# 为命名空间设置标签
$ sudo ctr ns label myns env=prod

4.2 镜像操作

# 拉取镜像
$ sudo ctr images pull docker.io/library/nginx:alpine

# 列出镜像
$ sudo ctr images list

# 挂载镜像
$ sudo ctr images mount docker.io/library/nginx:alpine /mnt/nginx

# 卸载镜像
$ sudo ctr images unmount /mnt/nginx

# 导入镜像
$ sudo ctr -n=k8s.io images import kube-apiserver.tar

4.3 容器操作

# 创建容器
$ sudo ctr containers create docker.io/library/nginx:alpine nginx

# 查看容器
$ sudo ctr containers list

# 查看容器详细配置
$ sudo ctr containers info nginx

# 删除容器
$ sudo ctr containers delete nginx

4.4 任务

上面 create 的命令创建了容器后,并没有处于运行状态,只是一个静态的容器。一个 container 对象只是包含了运行一个容器所需的资源及配置的数据结构,这意味着 namespaces、rootfs 和容器的配置都已经初始化成功了,只是用户进程还没有启动。

然而一个容器真正的运行起来是由 Task 对象实现的,task 代表任务的意思,可以为容器设置网卡,还可以配置工具来对容器进行监控等。

所以还需要通过 Task 启动容器:

# 启动容器
$ sudo ctr task start -d nginx

# 查看容器
$ sudo ctr task list

# 进入容器:--exec-id,这个id可以随便写,只要唯一就行
$ sudo ctr task exec --exec-id 0 -t nginx sh

# 暂停容器
$ sudo ctr task pause nginx

# 恢复容器
$ sudo ctr task resume nginx

# 杀掉容器
$ sudo ctr task kill nginx

# 获取容器cgroup信息
$ sudo ctr task metrics nginx

当然,也可以一步到位直接创建并运行容器:

$ sudo ctr run -d docker.io/library/nginx:alpine nginx

4.5 nerdctl

nerdctl 是 containerd 的 cli 客户端,与 docker cli 大部分兼容。
nerdctl 是 containerd 的非核心子项目。

nerdctl 优点:

  • 与 docker 相同的体验

  • 支持 docker compose (nerdctl compose up)

  • 支持 rootless mode

  • 支持 lazy-puling

  • 支持 image 加密

4.5.1 安装

下载地址:https://github.com/containerd/nerdctl/releases

精简 ( nerdctl-0.19.0-linux-amd64.tar.gz):仅 nerdctl

完整 ( nerdctl-full-0.19.0-linux-amd64.tar.gz):包含 containerd、runc、CNI 等依赖

下载完整压缩包解压,配置环境变量即可。

4.5.2 使用

nerdctl 使用与 docker 使用类似,请参考 docker 客户端使用。


相关文章

证书过期问题之IPV6协议

证书过期问题之IPV6协议

1、首先了解情况:客户的SSL/TLS证书要过期了,所以进行了证书替换工作,但是替换之后,有一部分客户端还是提示证书已过期,如图所示:2、看这个报错是非常的清晰的,就是证书过期的问题,但是为什么同事没...

 MySQL性能优化(十)in参数列表过长导致的性能问题

MySQL性能优化(十)in参数列表过长导致的性能问题

有时候可能有人会问:where条件中使用in和or有什么区别,哪种写法性能更好?in参数个数有没有限制?下面就是一个由于in参数列表过长导致的性能问题。一个例子当时使用的是mysql 5.6版本SEL...

Linux系统调优参数应用实践

Linux系统调优参数应用实践

1 基于内存方面的性能参数调优1.1 cache与buffer解读1.1.1 cache出现的原因与功能计算机硬件中CPU、内存、磁盘是最主要的三大部分,其中,CPU发展到今天,执行速度最快,而内存相...

ES运维(五)聚合分析流程及精准度

ES运维(五)聚合分析流程及精准度

1、 概述ES是一个近实时的搜索引擎,提供近实时海量数据的聚合分析功能,但这个海量数据聚合分析是会损失一定的精准度来满足实时性能需要的。 2、 分布式系统的近似统计算法如下图,在分布式数据分...

Trino配置yanagishima-23.0(包含编译)

Trino配置yanagishima-23.0(包含编译)

1 环境介绍1.1 本文采用trino 359yanagishima v23.02 编译yanagishima2.1 安装编译yanagishima需要的工具安装编译yanagishima需要的工具w...

Hadoop集群小文件合并优化建议指导

Hadoop集群小文件合并优化建议指导

1 综述1.1 综述本指导书旨在指导大数据集群使用者在大数据集群小文件较多的情况下,针对小文件进行优化处理,有效减小集群文件对象数目,减缓namenode所承载的压力,减少mapreduce任务扫描文...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。