Docker Engine - Containerd

庆云2年前技术文章490

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 客户端使用。


相关文章

shell编程基础(二)

1、条件表达式1.1 文件判断常用文件测试操作符:-d文件,d的全拼为directory 文件存在且为目录则为真,即测试表达式成立-f文件,f的全拼为file 文件存在且为普通文件则为真,即测试表达式...

helm简介

helm简介

一、Helm 是什么在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理...

Linux高并发Nginx配置优化

在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题。一般来说nginx配置文件中对优化比较有作用的主要有以下几项:1)nginx进程数,建议按照cpu数目来...

虚拟机三种网络模式详解

虚拟机三种网络模式详解

在电脑里开一台虚拟机,是再常见不过的操作了。无论是用虚拟机玩只有旧版本系统能运行的游戏,还是用来学习Linux、跑跑应用程序都是很好的。而这其中,虚拟机网络是绝对绕不过去的。本篇文章通俗易懂的介绍了常...

Kafka日志管理

Kafka在运行时会生成大量的日志记录信息,包含了运行状态、错误信息、性能指标等。这些日志文件会占用很大的磁盘空间,过多的日志文件也会影响Kafka的性能,因此需要采取一些日志管理措施来清理无用的日志...

CDP实操--动态启停服务

以yarn nodemanager 为例获取role yarn nodemanager:curl -u admin:admin 'http://172.16.106.151:7180/api/v1/c...

发表评论    

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