安装

我使用的系统是 CentOS 7.6,首先需要安装 seccomp 依赖:

1
2
3
4
5
6
rpm -qa |grep libseccomp
libseccomp-2.3.1-4.el7.x86_64
# 如果没有安装 libseccomp 包则执行下面的命令安装依赖
yum install wget -y
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/libseccomp-2.3.1-4.el7.x86_64.rpm
yum install libseccomp-2.3.1-4.el7.x86_64.rpm -y

由于 containerd 需要调用 runc,所以我们也需要先安装 runc,不过 containerd 提供了一个包含相关依赖的压缩包 cri-containerd-cni-${VERSION}.${OS}-${ARCH}.tar.gz,可以直接使用这个包来进行安装。首先从 release 页面下载最新版本的压缩包,当前为 1.5.5 版本(最新的1.5.7版本在CentOS7下面执行 runc 会报错:https://github.com/containerd/containerd/issues/6091):

1
2
3
wget https://github.com/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz
# 如果有限制,也可以替换成下面的 URL 加速下载
# wget https://download.fastgit.org/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz

直接将压缩包解压到系统的各个目录中

1
tar -C / -xzf cri-containerd-cni-1.5.5-linux-amd64.tar.gz

/usr/local/bin/usr/local/sbin 追加到 ~/.bashrc 文件的 PATH 环境变量中:

1
export PATH=$PATH:/usr/local/bin:/usr/local/sbin

然后执行下面的命令使其立即生效:

1
source ~/.bashrc

配置

containerd 的默认配置文件为 /etc/containerd/config.toml,我们可以通过如下所示的命令生成一个默认的配置:

1
2
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

对于使用 systemd 作为 init system 的 Linux 的发行版,使用 systemd 作为容器的 cgroup driver 可以确保节点在资源紧张的情况更加稳定,所以推荐将 containerd 的 cgroup driver 配置为 systemd。

修改前面生成的配置文件 /etc/containerd/config.toml,在 plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options 配置块下面将 SystemdCgroup 设置为 true

1
2
3
4
5
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
....

然后再为镜像仓库配置一个加速器,需要在 cri 配置块下面的 registry 配置块下面进行配置 registry.mirrors

1
2
3
4
5
6
7
8
9
10
11
[plugins."io.containerd.grpc.v1.cri"]
...
# sandbox_image = "k8s.gcr.io/pause:3.5"
sandbox_image = "registry.aliyuncs.com/k8sxio/pause:3.5"
...
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://bqr1dr1n.mirror.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://registry.aliyuncs.com/k8sxio"]

由于上面我们下载的 containerd 压缩包中包含一个 etc/systemd/system/containerd.service 的文件,这样我们就可以通过 systemd 来配置 containerd 作为守护进程运行了,现在我们就可以启动 containerd 了,直接执行下面的命令即可:

1
2
systemctl daemon-reload
➜ ~ systemctl enable containerd --now

启动完成后就可以使用 containerd 的本地 CLI 工具 ctrcrictl 了,比如查看版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ctr version
Client:
Version: v1.5.5
Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
Go version: go1.16.6

Server:
Version: v1.5.5
Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
UUID: cd2894ad-fd71-4ef7-a09f-5795c7eb4c3b
crictl version
Version: 0.1.0
RuntimeName: containerd
RuntimeVersion: v1.5.5
RuntimeApiVersion: v1alpha2

使用

我们知道 Docker CLI 工具提供了需要增强用户体验的功能,containerd 同样也提供一个对应的 CLI 工具:ctr,不过 ctr 的功能没有 docker 完善,但是关于镜像和容器的基本功能都是有的。接下来我们就先简单介绍下 ctr 的使用。

帮助

直接输入 ctr 命令即可获得所有相关的操作命令使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ctr
NAME:
ctr -
__
_____/ /______
/ ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/

containerd CLI


USAGE:
ctr [global options] command [command options] [arguments...]

VERSION:
v1.5.5

...

镜像操作

拉取镜像

拉取镜像可以使用 ctr image pull 来完成,比如拉取 Docker Hub 官方镜像 nginx:alpine,需要注意的是镜像地址需要加上 docker.io Host 地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ctr image pull docker.io/library/nginx:alpine
docker.io/library/nginx:alpine: resolved |++++++++++++++++++++++++++++++++++++++|
index-sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce: exists |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:ce6ca11a3fa7e0e6b44813901e3289212fc2f327ee8b1366176666e8fb470f24: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:9a6ac07b84eb50935293bb185d0a8696d03247f74fd7d43ea6161dc0f293f81f: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:e82f830de071ebcda58148003698f32205b7970b01c58a197ac60d6bb79241b0: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:d7c9fa7589ae28cd3306b204d5dd9a539612593e35df70f7a1d69ff7548e74cf: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:bf2b3ee132db5b4c65432e53aca69da4e609c6cb154e0d0e14b2b02259e9c1e3: done |++++++++++++++++++++++++++++++++++++++|
config-sha256:7ce0143dee376bfd2937b499a46fb110bda3c629c195b84b1cf6e19be1a9e23b: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:3c1eaf69ff492177c34bdbf1735b6f2e5400e417f8f11b98b0da878f4ecad5fb: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:29291e31a76a7e560b9b7ad3cada56e8c18d50a96cca8a2573e4f4689d7aca77: done |++++++++++++++++++++++++++++++++++++++|
elapsed: 11.9s total: 8.7 Mi (748.1 KiB/s)
unpacking linux/amd64 sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce...
done: 410.86624ms

也可以使用 --platform 选项指定对应平台的镜像。当然对应的也有推送镜像的命令 ctr image push,如果是私有镜像则在推送的时候可以通过 --user 来自定义仓库的用户名和密码。

列出本地镜像

1
2
3
4
5
ctr image ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce 9.5 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
ctr image ls -q
docker.io/library/nginx:alpine

使用 -q(--quiet) 选项可以只打印镜像名称。

检测本地镜像

1
2
3
ctr image check
REF TYPE DIGEST STATUS SIZE UNPACKED
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce complete (7/7) 9.5 MiB/9.5 MiB true

主要查看其中的 STATUScomplete 表示镜像是完整可用的状态。

重新打标签

同样的我们也可以重新给指定的镜像打一个 Tag:

1
2
3
4
5
ctr image tag docker.io/library/nginx:alpine harbor.k8s.local/course/nginx:alpine
harbor.k8s.local/course/nginx:alpine
ctr image ls -q
docker.io/library/nginx:alpine
harbor.k8s.local/course/nginx:alpine

删除镜像

不需要使用的镜像也可以使用 ctr image rm 进行删除:

1
2
3
4
ctr image rm harbor.k8s.local/course/nginx:alpine
harbor.k8s.local/course/nginx:alpine
ctr image ls -q
docker.io/library/nginx:alpine

加上 --sync 选项可以同步删除镜像和所有相关的资源。

将镜像挂载到主机目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ctr image mount docker.io/library/nginx:alpine /mnt
sha256:c3554b2d61e3c1cffcaba4b4fa7651c644a3354efaafa2f22cb53542f6c600dc
/mnt
tree -L 1 /mnt
/mnt
├── bin
├── dev
├── docker-entrypoint.d
├── docker-entrypoint.sh
├── etc
├── home
├── lib
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── sys
├── tmp
├── usr
└── var

18 directories, 1 file

将镜像从主机目录上卸载

1
2
ctr image unmount /mnt
/mnt

将镜像导出为压缩包

1
ctr image export --all-platforms nginx.tar.gz docker.io/library/nginx:alpine

从压缩包导入镜像

1
ctr image import nginx.tar.gz

直接导入可能会出现类似于 ctr: content digest sha256:xxxxxx not found 的错误,要解决这个办法需要 pull 所有平台镜像:

1
2
3
4
ctr i pull --all-platforms docker.io/library/nginx:alpine
ctr i export --all-platforms nginx.tar.gz docker.io/library/nginx:alpine
ctr i rm docker.io/library/nginx:alpine
ctr i import nginx.tar.gz

容器操作

容器相关操作可以通过 ctr container 获取。

创建容器

1
ctr container create docker.io/library/nginx:alpine nginx

列出容器

1
2
3
ctr container ls
CONTAINER IMAGE RUNTIME
nginx docker.io/library/nginx:alpine io.containerd.runc.v2

同样可以加上 -q 选项精简列表内容:

1
2
ctr container ls -q
nginx

查看容器详细配置

类似于 docker inspect 功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ctr container info nginx
{
"ID": "nginx",
"Labels": {
"io.containerd.image.config.stop-signal": "SIGQUIT"
},
"Image": "docker.io/library/nginx:alpine",
"Runtime": {
"Name": "io.containerd.runc.v2",
"Options": {
"type_url": "containerd.runc.v1.Options"
}
},
"SnapshotKey": "nginx",
......

删除容器

1
2
3
ctr container rm nginx
ctr container ls
CONTAINER IMAGE RUNTIME

除了使用 rm 子命令之外也可以使用 delete 或者 del 删除容器。

任务

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

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

Task 相关操作可以通过 ctr task 获取,如下我们通过 Task 来启动容器:

1
2
3
ctr task start -d nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/

启动容器后可以通过 task ls 查看正在运行的容器:

1
2
3
ctr task ls
TASK PID STATUS
nginx 3630 RUNNING

同样也可以使用 exec 命令进入容器进行操作:

1
2
ctr task exec --exec-id 0 -t nginx sh
/ #

不过这里需要注意必须要指定 --exec-id 参数,这个 id 可以随便写,只要唯一就行。

暂停容器,和 docker pause 类似的功能:

1
ctr task pause nginx

暂停后容器状态变成了 PAUSED

1
2
3
ctr task ls
TASK PID STATUS
nginx 3630 PAUSED

同样也可以使用 resume 命令来恢复容器:

1
2
3
4
ctr task resume nginx
ctr task ls
TASK PID STATUS
nginx 3630 RUNNING

不过需要注意 ctr 没有 stop 容器的功能,只能暂停或者杀死容器。杀死容器可以使用 task kill 命令:

1
2
3
4
ctr task kill nginx
ctr task ls
TASK PID STATUS
nginx 3630 STOPPED

杀掉容器后可以看到容器的状态变成了 STOPPED。同样也可以通过 task rm 命令删除 Task:

1
2
3
ctr task rm nginx
ctr task ls
TASK PID STATUS

除此之外我们还可以获取容器的 cgroup 相关信息,可以使用 task metrics 命令用来获取容器的内存、CPU 和 PID 的限额与使用量。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 重新启动容器
ctr task metrics nginx
ID TIMESTAMP
nginx 2021-08-12 08:50:46.952769941 +0000 UTC

METRIC VALUE
memory.usage_in_bytes 8855552
memory.limit_in_bytes 9223372036854771712
memory.stat.cache 0
cpuacct.usage 22467106
cpuacct.usage_percpu [2962708 860891 1163413 1915748 1058868 2888139 6159277 5458062]
pids.current 9
pids.limit 0

还可以使用 task ps 命令查看容器中所有进程在宿主机中的 PID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ctr task ps nginx
PID INFO
3984 -
4029 -
4030 -
4031 -
4032 -
4033 -
4034 -
4035 -
4036 -
ctr task ls
TASK PID STATUS
nginx 3984 RUNNING

其中第一个 PID 3984 就是我们容器中的1号进程。

命名空间

另外 Containerd 中也支持命名空间的概念,比如查看命名空间:

1
2
3
ctr ns ls
NAME LABELS
default

如果不指定,ctr 默认使用的是 default 空间。同样也可以使用 ns create 命令创建一个命名空间:

1
2
3
4
5
ctr ns create test
ctr ns ls
NAME LABELS
default
test

使用 remove 或者 rm 可以删除 namespace:

1
2
3
4
5
ctr ns rm test
test
ctr ns ls
NAME LABELS
default

有了命名空间后就可以在操作资源的时候指定 namespace,比如查看 test 命名空间的镜像,可以在操作命令后面加上 -n test 选项:

1
2
ctr -n test image ls
REF TYPE DIGEST SIZE PLATFORMS LABELS

我们知道 Docker 其实也是默认调用的 containerd,事实上 Docker 使用的 containerd 下面的命名空间默认是 moby,而不是 default,所以假如我们有用 docker 启动容器,那么我们也可以通过 ctr -n moby 来定位下面的容器:

1
ctr -n moby container ls

同样 Kubernetes 下使用的 containerd 默认命名空间是 k8s.io,所以我们可以使用 ctr -n k8s.io 来查看 Kubernetes 下面创建的容器。

课程内容:https://youdianzhishi.com/web/course/1030