【containerd】初识containered

背景说明

在学习 Containerd 之前我们有必要对 Docker 的发展历史做一个简单的回顾,因为这里面牵涉到的组件有点多,平时我们会经常听到,但是不清楚这些组件到底是干什么用的,也没有深入进行研究过,比如 libcontainer、runc、containerd、CRI、OCI 等等。下面我们详细说说。

Docker

从 Docker 1.11 版本开始,Docker 容器运行就不是简单通过 Docker Daemon 来启动了,而是通过集成 containerd、runc 等多个组件来完成的。虽然 Docker Daemon 守护进程模块在不停的重构,但是基本功能和定位没有太大的变化,一直都是 CS 架构,守护进程负责和 Docker Client 端交互,并管理 Docker 镜像和容器。现在的架构中组件 containerd 就会负责集群节点上容器的生命周期管理,并向上为 Docker Daemon 提供 gRPC 接口。

在这里插入图片描述

当我们要创建一个容器的时候,现在 Docker Daemon 并不能直接帮我们创建了,而是请求 containerd 来创建一个容器,containerd 收到请求后,也并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器,我们指定容器进程是需要一个父进程来做状态收集、维持 stdin 等 fd 打开等工作的,假如这个父进程就是 containerd,那如果 containerd 挂掉的话,整个宿主机上所有的容器都得退出了,而引入 containerd-shim 这个垫片就可以来规避这个问题了。

然后创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作,这些操作其实已经有了标准的规范,那就是 OCI(开放容器标准,open container initiative),runc 就是它的一个参考实现(Docker 被逼无奈将 libcontainer 捐献出来改名为 runc 的),这个标准其实就是一个文档,主要规定了容器镜像的结构、以及容器需要接收哪些操作指令,比如 create、start、stop、delete 等这些命令。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。

所以真正启动容器是通过 containerd-shim 去调用 runc 来启动容器的,runc 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程。

而 Docker 将容器操作都迁移到 containerd 中去是因为当前做 Swarm,想要进军 PaaS 市场,做了这个架构切分,让 Docker Daemon 专门去负责上层的封装编排,当然后面的结果我们知道 Swarm 在 Kubernetes 面前是惨败,然后 Docker 公司就把 containerd 项目捐献给了 CNCF 基金会,这个也是现在的 Docker 架构。

CRI

Kubernetes 提供了一个 CRI 的容器运行时接口,那么这个 CRI 到底是什么呢?这个其实也和 Docker 的发展密切相关的。

在 Kubernetes 早期的时候,当时 Docker 实在是太火了,Kubernetes 当然会先选择支持 Docker,而且是通过硬编码的方式直接调用 Docker API,后面随着 Docker 的不断发展以及 Google 的主导,出现了更多容器运行时,Kubernetes 为了支持更多更精简的容器运行时,Google 就和红帽主导推出了 CRI 标准,用于将 Kubernetes 平台和特定的容器运行时(当然主要是为了干掉 Docker)解耦。

CRI(Container Runtime Interface 容器运行时接口)本质上就是 Kubernetes 定义的一组与容器运行时进行交互的接口,所以只要实现了这套接口的容器运行时都可以对接到 Kubernetes 平台上来。不过 Kubernetes 推出 CRI 这套标准的时候还没有现在的统治地位,所以有一些容器运行时可能不会自身就去实现 CRI 接口,于是就有了 shim(垫片), 一个 shim 的职责就是作为适配器将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上,其中 dockershim 就是 Kubernetes 对接 Docker 到 CRI 接口上的一个垫片实现。
在这里插入图片描述

Kubelet 通过 gRPC 框架与容器运行时或 shim 进行通信,其中 kubelet 作为客户端,CRI shim(也可能是容器运行时本身)作为服务器。

CRI 定义的 API主要包括两个 gRPC 服务,ImageService 和 RuntimeService,ImageService 服务主要是拉取镜像、查看和删除镜像等操作,RuntimeService 则是用来管理 Pod 和容器的生命周期,以及与容器交互的调用(exec/attach/port-forward)等操作,可以通过 kubelet 中的标志 --container-runtime-endpoint 和 --image-service-endpoint 来配置这两个服务的套接字。
在这里插入图片描述

不过这里同样也有一个例外,那就是 Docker,由于 Docker 当时的江湖地位很高,Kubernetes 是直接内置了 dockershim 在 kubelet 中的,所以如果你使用的是 Docker 这种容器运行时的话是不需要单独去安装配置适配器之类的,当然这个举动似乎也麻痹了 Docker 公司。
在这里插入图片描述

现在如果我们使用的是 Docker 的话,当我们在 Kubernetes 中创建一个 Pod 的时候,首先就是 kubelet 通过 CRI 接口调用 dockershim,请求创建一个容器,kubelet 可以视作一个简单的 CRI Client, 而 dockershim 就是接收请求的 Server,不过他们都是在 kubelet 内置的。

dockershim 收到请求后, 转化成 Docker Daemon 能识别的请求, 发到 Docker Daemon 上请求创建一个容器,请求到了 Docker Daemon 后续就是 Docker 创建容器的流程了,去调用 containerd,然后创建 containerd-shim 进程,通过该进程去调用 runc 去真正创建容器。

其实我们仔细观察也不难发现使用 Docker 的话其实是调用链比较长的,真正容器相关的操作其实 containerd 就完全足够了,Docker 太过于复杂笨重了,当然 Docker 深受欢迎的很大一个原因就是提供了很多对用户操作比较友好的功能,但是对于 Kubernetes 来说压根不需要这些功能,因为都是通过接口去操作容器的,所以自然也就可以将容器运行时切换到 containerd 来。
在这里插入图片描述

切换到 containerd 可以消除掉中间环节,操作体验也和以前一样,但是由于直接用容器运行时调度容器,所以它们对 Docker 来说是不可见的。 因此,你以前用来检查这些容器的 Docker 工具就不能使用了。你不能再使用 docker ps 或 docker inspect 命令来获取容器信息。由于不能列出容器,因此也不能获取日志、停止容器,甚至不能通过 docker exec 在容器中执行命令。

当然我们仍然可以下载镜像,或者用 docker build 命令构建镜像,但用 Docker 构建、下载的镜像,对于容器运行时和 Kubernetes,均不可见。为了在 Kubernetes 中使用,需要把镜像推送到镜像仓库中去。

从上图可以看出在 containerd 1.0 中,对 CRI 的适配是通过一个单独的 CRI-Containerd 进程来完成的,这是因为最开始 containerd 还会去适配其他的系统(比如 swarm),所以没有直接实现 CRI,所以这个对接工作就交给 CRI-Containerd 这个 shim 了。

然后到了 containerd 1.1 版本后就去掉了 CRI-Containerd 这个 shim,直接把适配逻辑作为插件的方式集成到了 containerd 主进程中,现在这样的调用就更加简洁了。
在这里插入图片描述

与此同时 Kubernetes 社区也做了一个专门用于 Kubernetes 的 CRI 运行时 CRI-O,直接兼容 CRI 和 OCI 规范。
在这里插入图片描述

这个方案和 containerd 的方案显然比默认的 dockershim 简洁很多,不过由于大部分用户都比较习惯使用 Docker,所以大家还是更喜欢使用 dockershim 方案。

但是随着 CRI 方案的发展,以及其他容器运行时对 CRI 的支持越来越完善,Kubernetes 社区在2020年7月份就开始着手移除 dockershim 方案了:https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2221-remove-dockershim,之前的移除计划是在 1.20 版本中将 kubelet 中内置的 dockershim 代码分离,将内置的 dockershim 标记为维护模式,当然这个时候仍然还可以使用 dockershim,目标是在 1.23⁄1.24 版本发布没有 dockershim 的版本(代码还在,但是要默认支持开箱即用的 docker 需要自己构建 kubelet,会在某个宽限期过后从 kubelet 中删除内置的 dockershim 代码)。 那么这是否就意味这 Kubernetes 不再支持 Docker 了呢?当然不是的,这只是废弃了内置的 dockershim 功能而已,Docker 和其他容器运行时将一视同仁,不会单独对待内置支持,如果我们还想直接使用 Docker 这种容器运行时应该怎么办呢?可以将 dockershim 的功能单独提取出来独立维护一个 cri-dockerd 即可,就类似于 containerd 1.0 版本中提供的 CRI-Containerd,当然还有一种办法就是 Docker 官方社区将 CRI 接口内置到 Dockerd 中去实现。

但是我们也清楚 Dockerd 也是去直接调用的 Containerd,而 containerd 1.1 版本后就内置实现了 CRI,所以 Docker 也没必要再去单独实现 CRI 了,当 Kubernetes 不再内置支持开箱即用的 Docker 的以后,最好的方式当然也就是直接使用 Containerd 这种容器运行时,而且该容器运行时也已经经过了生产环境实践的,接下来我们就来学习下 Containerd 的使用。

Containerd 介绍

早之前的 Docker Engine 中就有了 containerd,只不过现在是将 containerd 从 Docker Engine 里分离出来,作为一个独立的开源项目,目标是提供一个更加开放、稳定的容器运行基础设施。分离出来的 containerd 将具有更多的功能,涵盖整个容器运行时管理的所有需求,提供更强大的支持。

containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,containerd 可以负责干下面这些事情:

  • 管理容器的生命周期(从创建容器到销毁容器)
  • 拉取/推送容器镜像
  • 存储管理(管理镜像及容器数据的存储)
  • 调用 runc 运行容器(与 runc 等容器运行时交互)
  • 管理容器网络接口及网络

Containerd的优势

  • 简洁的基于 gRPC 的 API 和 client library
  • 完整的 OCI 支持(runtime 和 image spec)
  • 同时具备稳定性和高性能的定义良好的容器核心功能
  • 一个解耦的系统(让 image、filesystem、runtime 解耦合),实现插件式的扩展和重用

为什么需要独立的 Containerd

  • 以往隶属于docker项目中,现如今从整体 docker 引擎中分离出的项目(开源项目的思路)
  • 可以被 Kubernets CRI 等项目使用(通用化)
  • 为广泛的行业合作打下基础(就像 runC 一样)

Containerd的架构

containerd 可用作 Linux 和 Windows 的守护程序,它管理其主机系统完整的容器生命周期,从镜像传输和存储到容器执行和监测,再到底层存储到网络附件等等。
在这里插入图片描述
上图是 containerd 官方提供的架构图,可以看出 containerd 采用的也是 C/S 架构,服务端通过 unix domain socket 暴露低层的 gRPC API 接口出去,客户端通过这些 API 管理节点上的容器,每个 containerd 只负责一台机器,Pull 镜像,对容器的操作(启动、停止等),网络,存储都是由 containerd 完成。具体运行容器由 runc 负责,实际上只要是符合 OCI 规范的容器都可以支持。

为了解耦,containerd 将系统划分成了不同的组件,每个组件都由一个或多个模块协作完成(Core 部分),每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的,例如,上图中的每一个长虚线的方框都表示一种类型的插件,包括 Service Plugin、Metadata Plugin、GC Plugin、Runtime Plugin 等,其中 Service Plugin 又会依赖 Metadata Plugin、GC Plugin 和 Runtime Plugin。每一个小方框都表示一个细分的插件,例如 Metadata Plugin 依赖 Containers Plugin、Content Plugin 等。比如:

  • Content Plugin: 提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里。
  • Snapshot Plugin: 用来管理容器镜像的文件系统快照,镜像中的每一层都会被解压成文件系统快照,类似于 Docker 中的 graphdriver。

总体来看 containerd 可以分为三个大块:Storage、Metadata 和 Runtime。
在这里插入图片描述

Containerd的安装

Containerd安装分为两种方式:

  • yum安装方式
  • 二进制包安装方式

以下分别演示两种不同的安装。

yum方式安装

4.1.1 环境介绍
系统及软件 版本号
Centos 7.7
Containerd 1.6.19

获取YUM源

添加阿里云yum

 [root@kube-master ~]# wget  https://mirrors.aliyun.com/repo/Centos-7.repo -o /etc/yum.repos.d/Centos-7.repo
 [root@kube-master ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo  
 [root@kube-master ~]# wget https://mirrors.aliyun.com/repo/epel-7.repo 
 [root@kube-master ~]# yum cleanall
 [root@kube-master ~]# yum makecache

查看yum源中containerd.io软件

[root@kube-master ~]# yum info containerd.io
Loaded plugins: fastestmirror
Repository base is listed more than once in the configuration
Repository updates is listed more than once in the configuration
Repository extras is listed more than once in the configuration
Repository centosplus is listed more than once in the configuration
Repository epel is listed more than once in the configuration
Repository epel-debuginfo is listed more than once in the configuration
Repository epel-source is listed more than once in the configuration
Loading mirror speeds from cached hostfile
 * base: mirrors.tuna.tsinghua.edu.cn
 * elrepo: mirrors.tuna.tsinghua.edu.cn
 * extras: mirrors.tuna.tsinghua.edu.cn
 * updates: mirrors.ustc.edu.cn
Installed Packages
Name        : containerd.io
Arch        : x86_64
Version     : 1.6.32
Release     : 3.1.el7
Size        : 117 M
Repo        : installed
From repo   : docker-ce-stable
Summary     : An industry-standard container runtime
URL         : https://containerd.io
License     : ASL 2.0
Description : containerd is an industry-standard container runtime with an emphasis on
            : simplicity, robustness and portability. It is available as a daemon for Linux
            : and Windows, which can manage the complete container lifecycle of its host
            : system: image transfer and storage, container execution and supervision,
            : low-level storage and network attachments, etc.

使用yum安装

安装containerd.io 软件

[root@kube-master ~]# yum install -y containerd.io

验证安装及启动服务

[root@kube-master ~]# rpm -ql containerd.io
/etc/containerd
/etc/containerd/config.toml
/usr/bin/containerd
/usr/bin/containerd-shim
/usr/bin/containerd-shim-runc-v1
/usr/bin/containerd-shim-runc-v2
/usr/bin/ctr
/usr/bin/runc
/usr/lib/systemd/system/containerd.service
/usr/share/doc/containerd.io-1.6.32
/usr/share/doc/containerd.io-1.6.32/README.md
/usr/share/licenses/containerd.io-1.6.32
/usr/share/licenses/containerd.io-1.6.32/LICENSE
/usr/share/man/man5/containerd-config.toml.5
/usr/share/man/man8/containerd-config.8
/usr/share/man/man8/containerd.8
/usr/share/man/man8/ctr.8
# 启动服务及开机自启
[root@kube-master ~]# systemctl enable containerd;systemctl start containerd

验证可用性

安装 containerd 时 ctr 命令作为客户端工具主要用于管理容器及容器镜像等。使用 ctr 命令查看 containerd客户端及服务器信息。

[root@kube-master ~]# ctr version
Client:
  Version:  1.6.32
  Revision: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89
  Go version: go1.21.10

WARN[0000] DEPRECATION: The `tracing` property of `[plugins."io.containerd.internal.v1".tracing]` is deprecated since containerd v1.6 and will be removed in containerd v2.0.Use OTEL environment variables instead: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/ 
Server:
  Version:  1.6.32
  Revision: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89
  UUID: 89bfd965-addc-4a42-936f-85a4e99915d5

二进制方式安装

系统及软件 版本号
Centos 7.6
Containerd 1.7.18
Containerd 有两种安装包:

[root@kube-master ~]# rpm -e containerd.io-1.6.32-3.1.el7.x86_64 --nodeps

安装前可以先把之前安装的containerd卸载掉。
第一种是 containerd-xxx 这种包用于单机测试没问题,不包含runC,需要提前安装;
第二种是 cri-containerd-cni-xxx ,包含runC和k8s里所需的相关文件。k8s集群里需要用到此包,虽然包含runC,但是依赖系统中的 seccomp

获取安装包

下载地址:https://github.com/containerd/containerd/releases,选择对应的包进行下载。

[root@kube-master ~]# wget  https://github.com/containerd/containerd/releases/download/v1.7.18/containerd-1.7.18-linux-amd64.tar.gz

安装containerd

[root@kube-master ~]# tar -xvf containerd-1.7.18-linux-amd64.tar.gz -C /usr/local/

生成并修改配置文件

#创建目录
[root@kube-master ~]# mkdir  /etc/containerd/
#生成配置文件
[root@kube-master ~]# containerd config default > /etc/containerd/config.toml
# 修改如下地方
[root@kube-master ~]# vi /etc/containerd/config.toml
......
ShimCgroup = ""
SystemdCgroup = true
......
# 添加镜像加速
#修改 config.toml 配置文件
[root@kube-master ~]# vi /etc/containerd/config.toml
......
[plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "/etc/containerd/certs.d"  # 镜像地址配置文件
......
[root@kube-master ~]# mkdir /etc/containerd/certs.d/docker.io 
[root@kube-master ~]# cat << EOF >> /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://docker.io"
[host."https://docker.mirrors.ustc.edu.cn"]
EOF

添加启动配置文件,注意启动文件的实际位置

[root@kube-master ~]# cat  /usr/lib/systemd/system/containerd.service 
# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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

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

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# 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=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target

添加自启动并启动 containerd

#重新加载一下防止不能找到containerd这个服务
[root@kube-master ~]# systemctl daemon-reload
[root@kube-master ~]# systemctl enable containerd
[root@kube-master ~]# systemctl start containerd

查看并验证

[root@kube-master ~]# ctr
ctr         ctrlaltdel  
[root@kube-master ~]# ctr version
Client:
  Version:  v1.7.18
  Revision: ae71819c4f5e67bb4d5ae76a6b735f29cc25774e
  Go version: go1.21.11

Server:
  Version:  v1.7.18
  Revision: ae71819c4f5e67bb4d5ae76a6b735f29cc25774e
  UUID: 89bfd965-addc-4a42-936f-85a4e99915d5

安装runC并验证结果

由于二进制包中提供的runC默认需要系统中安装seccomp支持,需要单独安装,且不同版本runC对seccomp版本要求一致,所以建议单独下载runC二进制包进行安装,里面包含了 seccomp 模块支持。

下载地址:https://github.com/opencontainers/runc/releases
image-20230331154050685

下载runC

[root@kube-master ~]# wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64

安装runC

[root@kube-master ~]# cp -a runc.amd64 /usr/local/bin/runc
[root@kube-master ~]# chmod +x /usr/local/bin/runc
# 验证runC
[root@kube-master ~]# runc -v
runc version 1.1.12
commit: v1.1.12-0-g51d5e946
spec: 1.0.2-dev
go: go1.20.13
libseccomp: 2.5.4

Containerd镜像管理

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

Containerd容器镜像管理命令

ctr i ls - 查看镜像
ctr i pull hub.c.163.com/library/nginx:latest - 下载镜像
ctr i mount hub.c.163.com/library/nginx:latest /mnt/ - 挂载镜像
ctr i export --platform linux/amd64 nginx.img hub.c.163.com/library/nginx:latest - 导出镜像
ctr i rm hub.c.163.com/library/nginx:latest - 删除镜像

查看镜像

i 是 images的简写

[root@kube-master ~]# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS 

下载镜像

containerd 支持 OCI 标准镜像,所有可以直接使用 docker 官方或 dockerfile构建的镜像

[root@kube-master ~]# ctr i pull  ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest 
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest:                             resolved       |++++++++++++++++++++++++++++++++++++++| 
index-sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31:    done           |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3: done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2:    done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85:   done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f:    done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 29.1s                                                                    total:  53.2 M (1.8 MiB/s)                                       
unpacking linux/amd64 sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31...
done: 2.821719368s
[root@kube-master ~]# ctr i ls 
REF                                                  TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                               LABELS 
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -   

镜像挂载

方便查看镜像中包含的内容。
把已下载的容器镜像挂载至当前文件系统

[root@kube-master ~]# mkdir /mnt/nginx
[root@kube-master ~]#  ctr i mount ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest /mnt/nginx/
sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
/mnt/nginx/
[root@kube-master ~]# ll /mnt/nginx/
total 16
drwxr-xr-x 2 root root 4096 Dec 20  2021 bin
drwxr-xr-x 2 root root    6 Dec 12  2021 boot
drwxr-xr-x 2 root root    6 Dec 20  2021 dev
drwxr-xr-x 1 root root   41 Dec 30  2021 docker-entrypoint.d
-rwxrwxr-x 1 root root 1202 Dec 30  2021 docker-entrypoint.sh
drwxr-xr-x 1 root root 4096 Dec 30  2021 etc
drwxr-xr-x 2 root root    6 Dec 12  2021 home
drwxr-xr-x 1 root root   45 Dec 20  2021 lib
drwxr-xr-x 2 root root   34 Dec 20  2021 lib64
drwxr-xr-x 2 root root    6 Dec 20  2021 media
drwxr-xr-x 2 root root    6 Dec 20  2021 mnt
drwxr-xr-x 2 root root    6 Dec 20  2021 opt
drwxr-xr-x 2 root root    6 Dec 12  2021 proc
drwx------ 2 root root   37 Dec 20  2021 root
drwxr-xr-x 3 root root   30 Dec 20  2021 run
drwxr-xr-x 2 root root 4096 Dec 20  2021 sbin
drwxr-xr-x 2 root root    6 Dec 20  2021 srv
drwxr-xr-x 2 root root    6 Dec 12  2021 sys
drwxrwxrwt 1 root root    6 Dec 30  2021 tmp
drwxr-xr-x 1 root root   66 Dec 20  2021 usr
drwxr-xr-x 1 root root   41 Dec 20  2021 var
#卸载
[root@kube-master ~]# umount /mnt/nginx

镜像导出

[root@kube-master ~]# ctr i export --platform linux/amd64 nginx.img  ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest
[root@kube-master ~]# ll -h  nginx.img 
-rw-r--r-- 1 root root 43M Jun 14 13:54 nginx.img

镜像删除

删除指定容器镜像

[root@kube-master ~]# ctr i rm ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest 
registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
#再次查看容器镜像
[root@kube-master ~]# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS 

镜像导入

导入容器镜像

[root@kube-master ~]# ctr i import  --platform linux/amd64 nginx.img 
unpacking registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest (sha256:423210a5903e9683d2bc8436ed06343ad5955c1aec71a04e1d45bd70b0d68460)...done

注意:貌似指定 --platform 没啥特别的用处,大家可以自行测试。

修改镜像TAG

[root@kube-master ~]# ctr i tag  ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest  nginx:latest
nginx:latest
[root@kube-master ~]# ctr i ls 
REF                                                  TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                               LABELS 
nginx:latest                                         application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -      
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -    

#修改完成后对镜像做对比
[root@kube-master ~]# ctr i check
REF                                                  TYPE                                                      DIGEST                                                                  STATUS         SIZE              UNPACKED 
nginx:latest                                         application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 complete (7/7) 54.1 MiB/54.1 MiB true
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 complete (7/7) 54.1 MiB/54.1 MiB true

Containerd容器管理

在 containerd 中,容器分为两种:静态容器和动态容器

  • 静态容器:命令创建容器后,容器并没有处于运行状态,其只是一个静态容器,这个 container对象只是包含了一个容器所需的资源及配置的数据结构
  • 动态容器:处于运行当中,有用户进程的容器

注意:在 container中,无法在没有镜像的情况下直接启动一个容器,必须遵循:1. pull镜像;2.启动容器。

查看容器

container表示静态容器,可用 c 缩写代表container

[root@kube-master ~]# ctr c ls
CONTAINER    IMAGE    RUNTIME    
#或者
[root@kube-master ~]# ctr container ls
CONTAINER    IMAGE    RUNTIME  

查看任务

task表示容器里跑的进程,可用 t 缩写代表 task

[root@kube-master ~]# ctr t ls
TASK    PID    STATUS
或者
[root@kube-master ~]# ctr task  ls
TASK    PID    STATUS 

创建静态容器

[root@kube-master ~]# ctr c create nginx:latest nginx
[root@kube-master ~]# ctr c ls
CONTAINER    IMAGE           RUNTIME                  
nginx        nginx:latest    io.containerd.runc.v2    
#查看容器详细信息
[root@kube-master ~]# ctr c info nginx

静态容器启动为动态容器

启动task,即表示在容器中运行进程,即为动态容器

[root@kube-master ~]# ctr t ls
TASK    PID    STATUS    
#说明:-d 表示在后台运行,与docker一致
[root@kube-master ~]# ctr t 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/

#查看容器所在宿主机的进程,是宿主机进程的方式存在的
[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING

#查看容器的进程(都是物理机的进程)
[root@kube-master ~]# ctr t ps nginx
PID     INFO
8635    -
8671    -
8672    -
[root@kube-master ~]# ps aux|grep nginx
root      8613  0.0  0.1 1238700 10168 ?       Sl   17:29   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace default -id nginx -address /run/containerd/containerd.sock
root      8635  0.0  0.0   8840  3504 ?        Ss   17:29   0:00 nginx: master process nginx -g daemon off;
101       8671  0.0  0.0   9228  1528 ?        S    17:29   0:00 nginx: worker process
101       8672  0.0  0.0   9228  1528 ?        S    17:29   0:00 nginx: worker process
root      8790  0.0  0.0 112712   960 pts/2    S+   17:30   0:00 grep --color=auto nginx

进入容器操作

[root@kube-master ~]#  ctr t exec --exec-id 1 -t nginx sh
# ls
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# curl -Is 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Wed, 19 Jun 2024 09:34:27 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes

直接运行一个动态容器

[root@kube-master ~]# ctr run -d --net-host nginx:latest ngx1
/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/

说明:
-d 代表后台运行
–net-host 代表容器的IP就是宿主机的IP(相当于docker里面的 host 类型网络)

测试是否运行成功,由于使用的–net-host模式,直接宿主机就可以访问

[root@kube-master ~]# curl -Is localhost
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Wed, 19 Jun 2024 09:40:40 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes

查看静态容器

[root@kube-master ~]# ctr c ls
CONTAINER    IMAGE           RUNTIME                  
nginx        nginx:latest    io.containerd.runc.v2    
ngx1         nginx:latest    io.containerd.runc.v2 

查看动态容器

[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
ngx1     9658    RUNNING
nginx    8635    RUNNING  

进入容器内部添加一个测试文件

[root@kube-master ~]# ctr t exec --exec-id 1 -t ngx1 sh
# echo "nginx" > /usr/share/nginx/html/index.html
# exit

宿主机访问:

[root@kube-master ~]# curl localhost
nginx

暂停容器

如果只是希望容器暂停工作一段时间,比如要对容器的文件系统做个快照,host需要使用CPU,处于暂停的容器不占用CPU资源。

查看容器状态

[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING
ngx1     9658    RUNNING

暂停容器

[root@kube-master ~]# ctr t pause ngx1
[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING
ngx1     9658    PAUSED

宿主机无法访问网站

[root@kube-master ~]# curl localhost
^C1

恢复容器

使用repause命令恢复容器

[root@kube-master ~]# ctr t resume ngx1
[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING
ngx1     9658    RUNNING

停止容器

使用kill命令停止容器中运行的进程,即为停止容器

[root@kube-master ~]# ctr t kill ngx1
#状态从 RUNNING 变为 STOPPED
[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING
ngx1     9658    STOPPED

删除容器

删除容器之前必须停止容器。

[root@kube-master ~]# ctr t ls
TASK     PID     STATUS    
nginx    8635    RUNNING
ngx1     9658    STOPPED
[root@kube-master ~]# ctr t rm ngx1
[root@kube-master ~]# ctr t rm nginx
ERRO[0000] unable to delete nginx                        error="task must be stopped before deletion: running: failed precondition"
ctr: task must be stopped before deletion: running: failed precondition

查看静态容器还存在系统中

[root@kube-master ~]# ctr c ls
CONTAINER    IMAGE           RUNTIME                  
nginx        nginx:latest    io.containerd.runc.v2    
ngx1         nginx:latest    io.containerd.runc.v2    
[root@kube-master ~]# ctr c rm ngx1
[root@kube-master ~]# ctr c ls
CONTAINER    IMAGE           RUNTIME                  
nginx        nginx:latest    io.containerd.runc.v2    
[root@kube-master ~]# 

命名空间

containerd 中是支持命名空间的概念.

查看命名空间

[root@kube-master ~]# ctr ns ls
NAME    LABELS 
default        
k8s.io         
moby

或者
[root@kube-master ~]# ctr namespace ls
NAME    LABELS 
default        
k8s.io         
moby

创建名称空间

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

[root@kube-master ~]# ctr ns ls
NAME    LABELS 
default        
k8s.io         
moby           
test 

指定名称空间启动容器

验证问题:当default 空间中有镜像,能否启动容器在test空间?

[root@kube-master ~]# ctr -n default i ls
REF                                                  TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                               LABELS 
nginx:latest                                         application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -      
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -      
#在test空间中启动容器
[root@kube-master ~]# ctr -n test run -d nginx:latest ngx
ctr: image "nginx:latest": not found

上面报错信息为:找不到 镜像。看来名称空间将镜像也隔离使用。

第一步,pull 镜像到 test 空间
注意命令选项位置:

[root@kube-master ~]# ctr -n test i pull ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest
#查看镜像
[root@kube-master ~]# ctr -n test i ls
REF                                                  TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                               LABELS 
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 54.1 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x -

第二步,启动容器
启动容器前,请确认其他命名空间容器端口不存在冲突(在网络模式为–net-host模式下),否则容器状态为 STOPPED

[root@kube-master ~]# ctr -n test run -d --net-host ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest ngx
[root@kube-master ~]# ctr -n test t ls
TASK    PID      STATUS    
ngx     20564    RUNNING
#测试
[root@kube-master ~]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Wed, 19 Jun 2024 10:39:40 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes

删除命名空间

尝试删除有容器、有镜像的命名空间。

[root@kube-master ~]# ctr ns rm test
ERRO[0000] unable to delete test                         error="namespace \"test\" must be empty, but it still has images, blobs, containers, snapshots on \"overlayfs\" snapshotter: failed precondition"
ctr: unable to delete test: namespace "test" must be empty, but it still has images, blobs, containers, snapshots on "overlayfs" snapshotter: failed precondition

由上面可以看出, 如果某个命名空间由容器和镜像,就不能直接进行删除。

删除容器

[root@kube-master ~]# ctr -n test t kill ngx
[root@kube-master ~]# ctr -n test t rm ngx
[root@kube-master ~]# ctr -n test c  rm ngx

删除镜像

[root@kube-master ~]# ctr -n test i rm  ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest
ustc-edu-cn.mirror.aliyuncs.com/library/nginx:latest
#查看容器及镜像
[root@kube-master ~]# ctr -n test i ls 
REF TYPE DIGEST SIZE PLATFORMS LABELS 
[root@kube-master ~]# ctr -n test c ls 
CONTAINER    IMAGE    RUNTIME    
[root@kube-master ~]# ctr -n test t ls 
TASK    PID    STATUS 

删除命名空间

[root@kube-master ~]# ctr ns rm test
test
[root@kube-master ~]# ctr ns ls
NAME    LABELS 
default        
k8s.io         
moby

命名空间的异同

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

[root@kube-master ~]# ctr -n moby c ls
CONTAINER                                                           IMAGE    RUNTIME

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

[root@kube-master ~]# ctr -n k8s.io c ls
CONTAINER    IMAGE    RUNTIME 

注意:这三者之间的 ns 是不同的,需要区分开。

containerd -> namespace(隔离) -> (和k8s里面的命名空间要区分开) -> namespace + cgroup + rootfs

日常积累

后期使用 containerd 遇到问题解决方案总汇。

修改数据存储目录

containerd 数据存储目录主要是针对镜像文件的存储,考虑到空间问题,常常会修改这个目录。

containerd的配置文件中有如下两项配置:

root = "/var/lib/containerd"
state = "/run/containerd"

root配置的目录是用来保存持久化数据的目录,包括 content, snapshotter, metadata 和 runtime。如下:

[root@kube-master ~]# tree -L 2 /var/lib/containerd/
/var/lib/containerd/
├── io.containerd.content.v1.content
│   ├── blobs
│   └── 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
│   ├── default
│   ├── moby
│   └── test
├── io.containerd.snapshotter.v1.blockfile
├── io.containerd.snapshotter.v1.btrfs
├── io.containerd.snapshotter.v1.native
│   └── snapshots
├── io.containerd.snapshotter.v1.overlayfs
│   ├── metadata.db
│   └── snapshots
└── tmpmounts
11 directories, 1 file

/var/lib/containerd 的各个子目录很清晰的对应到了 content, snapshot, metadata 和 runtime,containerd 架构示意图中的子系统和组件如下:
在这里插入图片描述
因此,如果需要修改目录,修改 containerd 中的 root 目录即可。如下修改到data目录

[root@kube-master ~]# vim /etc/containerd/config.toml
...
root = "/data/containerd"
...

[root@kube-master ~]# systemctl restart containerd
[root@kube-master ~]# tree -L 2 /data/containerd/
/data/containerd/
├── io.containerd.content.v1.content
│   └── ingest
├── io.containerd.metadata.v1.bolt
│   └── meta.db
├── io.containerd.runtime.v1.linux
├── io.containerd.runtime.v2.task
├── io.containerd.snapshotter.v1.btrfs
├── io.containerd.snapshotter.v1.native
│   └── snapshots
├── io.containerd.snapshotter.v1.overlayfs
│   └── snapshots
└── tmpmounts

11 directories, 1 file

更多关于containerd的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

margu_168

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值