+-
Containerd 入门实战

Containerd 入门实战

上一篇文章中我们八卦了一下 containerd 的前世今生,以及在当前云原生生态中的位置(不小心鸽了这么久,小弟深感惭愧,现附上一篇文章的链接~)。那么本篇文章就来看看怎么使用 containerd 吧!

安装部署

安装包下载

containerd 提供了两种压缩包,一种是 containerd-${version}-${os}-${arch}.tar.gz,这个压缩包中仅包含了 containerd 相关的二进制文件;另外一个是cri-containerd-cni-${version}-${os}-${arch}.tar.gz,这里面是一个比较全的压缩包,除了 containerd 相关的二进制,还包含了 runc(containerd 运行所依赖的底层容器运行时)以及相关命令的二进制(比如 ctr),如果作为 K8s 的容器运行时,建议直接选择第二种压缩包。压缩包地址都在github release中。

友情提示,目前github 中 containerd 的 release 版本仅支持 amd64 架构(即x86),团队只在 openlab上维护了 arm架构的 CI 流程: arm ci 记录。目前我的树莓派上,由于安装部署了依赖 containerd 的 K3s,间接的部署了 arm 架构的 containerd 。

下载之后解压缩、配置环境变量,就可以使用cri命令查看 containerd 的版本了

$ export PATH=$PATH:/usr/local/bin:/usr/local/sbin
$ ctr version
Client:
  Version:  1.3.7
  Revision: 8fba4e9a7d01810a393d5d25a3621dc101981175

Server:
  Version:  1.3.7
  Revision: 8fba4e9a7d01810a393d5d25a3621dc101981175
  UUID: c05a8353-d52c-44cd-88fe-af5b58f32b5b

配置相关

containerd 的配置文件默认在/etc/containerd/config.toml,也可以使用命令 containerd config default > /etc/containerd/config.toml 生成一个默认的配置文件。最简单配置文件如下:

subreaper = true
oom_score = -999

[debug]
        level = "debug"

[metrics]
        address = "127.0.0.1:1338"

[plugins.linux]
        runtime = "runc"
        shim_debug = true

启动 containerd

linux 系统中可以直接使用 systemd 启动守护进程,systemd 配置文件也在压缩包中:

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity

[Install]
WantedBy=multi-user.target

启动之后,就可以使用命令 systemctl status containerd 查看运行状态了。

上面的配置文件中,有 Delegate 的参数,设置为 yes 的意思是,系统允许 Containerd 创建 Cgroups, 并将 containerd 主进程创建的子进程(也就是容器进程)加入到自己的 Cgroups 中。否则容器进程将被 systemd 移动到自己的 cgroups 中,containerd 主进程则无法读取到子进程的资源情况。

此外还有一个 KillMode,设置为 process 意味着如果 containerd 主进程退出或被杀死时,不会影响其创建的子进程,从而做到了 containerd 与 容器是互不影响的。

存储

与docker 一样, containerd 将容器相关的数据持久化在 /var/lib/containerd/中(docker 默认在 /var/lib/docker/),但存储的数据却大相径庭。containerd 的目录中全部存放的是插件数据(与 containerd 架构图中,一切皆为插件的理念相同),这里面包括了插件的 Snapshots 、元数据等。其中 io.containerd.runtime.v1.linux 目录下则是保存了containerd shim 的log

.
├── io.containerd.content.v1.content
│   └── ingest
├── io.containerd.grpc.v1.introspection
│   └── uuid
├── io.containerd.metadata.v1.bolt
│   └── meta.db
├── io.containerd.runtime.v1.linux
│   └── moby
├── io.containerd.runtime.v2.task
├── io.containerd.snapshotter.v1.aufs
│   └── snapshots
├── io.containerd.snapshotter.v1.btrfs
├── io.containerd.snapshotter.v1.native
│   └── snapshots
├── io.containerd.snapshotter.v1.overlayfs
│   └── snapshots
└── tmpmounts

ctr 指令使用

启动了 containerd 的主进程之后,我们就可以愉快的运行容器了。ctr 是 containerd 依据自身开发的命令行工具,对容器和镜像的api操作进行了基本封装。

也许有小伙伴也看到过 crictl 这个命令行工具,其实这个是 K8s 社区根据 CRI 规范所定义的 CLI,使用范畴类似于 docker 命令,但可以应用于所有符合 CRI 规范的容器运行时。

对镜像操作

# 拉取镜像
> ctr image pull docker.io/library/busybox:stable

docker.io/library/busybox:stable:                                                 resolved       |++++++++++++++++++++++++++++++++++++++| 
index-sha256:b5fc1d7b2e4ea86a06b0cf88de915a2c43a99a00b6b3c0af731e5f4c07ae8eff:    done           |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:f2686aeee8a057e351a70e58d19ad530e4a4cd16e66eab6932d028153b74c96b: done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:d9d6c2bcb75096ffcf2c389eb491d2bc3d5b9f41b6a6de35f4cc9e3f2057c12e:   done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:3f18b27a912188108c8590684206bd9da7d81bbfd0e8325f3ef0af3234b4c257:    done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 6.5 s                                                                    total:  3.5 Ki (544.0 B/s)                     
unpacking linux/arm64/v8 sha256:b5fc1d7b2e4ea86a06b0cf88de915a2c43a99a00b6b3c0af731e5f4c07ae8eff...
done

# 查询镜像
> ctr image list
# 镜像挂载到主机
> ctr image mount docker.io/library/busybox:stable /mnt
# 其他
> ctr image -h
拉取镜像时,需要输入镜像的完全地址,如果镜像在 docker hub 中,则为 docker.io/library/xxx

对容器操作

# 创建容器 
ctr c create docker.io/library/busybox:stable test /bin/bash -c sleep 1000

执行上述命令后,containerd 仅仅对容器进行了初始化,例如分配 namespace,rootfs 和容器配置,并没有真正启动容器,这个初始化的容器通过 Task 的概念存在,使用 ctr task start -d test 运行容器,即在容器中运行了 /bin/bash -c sleep 1000命令,当然也可以直接使用

# 直接创建并运行容器
ctr c run docker.io/library/busybox:stable test /bin/bash -c sleep 1000

对运行时的容器进行操作时,均通过 task 进行操作,如暂停容器 ctr task pause xxx,进入容器 ctr task exec --exec-id 0 -t test sh, 查看容器内进程 ctr task ps test ,获取容器的统计信息ctr task metrics test

命名空间

K8s 中存在 namespace 的概念,containerd 中也有,默认启动的容器在 default 中。如果通过 docker 启动容器,则在 moby 中,而 K8s 使用 containerd 启动的容器放在了 k8s.io 的 namespace 中。

欢迎大家关注我的公众号,交换思想,多多交流~