• 0x00 前言简述

    • 1.基础介绍

    • 2.专业术语

    • 3.架构简述

  • 0x01 安装配置

    • 1.Ubuntu安装Containerd.io流程

  • 0x02 简单使用

    • 1.镜像拉取与运行

    • 2.创建和使用网络

    • 3.与宿主机和其它容器共享文件

    • 4.Docker 与 Containerd 并用配置

  • 0x03 Containerd 与 Docker CLI 工具命令表

    • ctr 命令 - Containerd 管理命令详细

    • crictl 命令 - Kubernetes 管理命令详解

0x00 前言简述

描述: 目前Docker是Kubernetes默认的容器运行时(Container Runtime), 由于k8s在2020年宣布1.20版本之后将弃用 dockershim (其中也有kubernetes与Docker爱恨情仇)时,才把containerd拉回大众的视野之中,所以本章主要讲解containerd基础入门。

1.基础介绍

Q: 什么是Containerd?

答: Containerd是从Docker中分类出的容器运行时与runc一样被分解为Docke的高级运行时部分,它支持 OCI 的镜像标准、可以实现拉取和推送镜像、管理操作镜像负责容器的整个生命周期。
例如当它需要运行一个容器时,它会将映像解压到一个OCI运行时包中,并将其发送给runc来运行它,Containerd还提供了一个API和客户端应用程序可以用来与之交互,containerd命令行客户端是ctr命令。
官方介绍: An industry-standard container runtime with an emphasis on simplicity, robustness and portability - 业界标准的容器运行时,强调简单性、健壮性和可移植性。

Q: Containerd 有何特点?

  • OCI Image Spec support - OCI图像规范支持

  • OCI Runtime Spec support - OCI运行时规范支持

  • Image push and pull support - 图像推拉支持

  • Container runtime and lifecycle support - 容器运行时和生命周期支持

  • Network primitives for creation, modification, and deletion of interfaces - 用于创建、修改和删除接口的网络原语

  • Management of network namespaces containers to join existing namespaces - 管理连接现有名称空间的网络名称空间容器

  • Multi-tenant supported with CAS storage for global images - CAS存储支持用于全局映像的多租户

发展历史: ( Containerd 和 Docker 的前世今生以及爱恨情仇)
在几年之前 Docker 公司在容器技术领域强势崛起一家独大,Google、RedHat 这样的巨头们都产生了很大的危机感,因此他们想与 Docker 公司一起联合研发推进一个开源的容器运行时作为 Docker 技术的核心依赖。然鹅 Docker 公司很高冷的表示:我不干!巨头们听到这个反馈就很不爽啊,因此通过一些手段对 Docker 公司软硬兼施,使其将 libcontainer 捐给了开源社区,也就是现在的 runc,一个 low level 的容器运行时。此外巨头们又成立了 CNCF 去对抗 Docker 公司的一家独大,CNCF 成立的思路很明确:在容器领域干不过 Docker,那就搞容器上层的建设——容器编排,从此 K8s 诞生了。虽然 Docker 公司也尝试使用 Swarm 去对抗 K8s但最终也失败了。

自此K8s慢慢成为云原生领域的标配,其生态也越做越大、越做越完善。Docker 公司为了融入生态,开源了 Docker 的核心依赖 containerd 。2019年2月28日containerd正式成为云原生计算基金会(Cloud Native Computing Foundation -CNCF)的一个毕业项目,紧随Kubernetes、Prometheus、Envoy和CoreDNS之后,在从containerd1.5开始,Kubernetes容器运行时接口(CRI)的containerd插件已经合并到containerd中。。

此外 K8s 为了对接下一层的容器,也因为其中立性搞了一个运行时接口,也就是 CRI(Container Runtime Interface),runc、containerd 等运行时都去支持此接口。由于当时确实没有啥 high level 的 runtime,oci-o 虽然支持 CRI 接口,但其功能太弱;containerd 也尚未成熟,而且其当时的定位是嵌入到系统中,并非给终端用户使用;rkt 有自己的一套体系后来这个项目也失败了。只能暂时为了适配 Docker 搞了个 shim,将 CRI 转换为 Docker API。K8s 和 Docker 进入了冷静期,双方都在各自优化自己,互不干扰。然而平静之下仍是暗潮汹涌,CNCF 社区一直在不断完善 containerd,其定位也发生了改变,由原来的系统嵌入组件,变成了今天的"工业标准容器运行时",并提供给终端用户使用。直到2020年12月 K8s 宣布废弃使用 Docker,而改用 Containerd。

总结: 其实kubernetes宣布废弃dockershim,一方面是因为商业因素,而另一方面 K8s 已经提供了标准接口对接底层容器运行时,不再想单独维护一个类似于Dockershim的适配层去迎合不同的运行时。

Q: 那什么是dockershim?
描述: dockershim 是 Kubernetes 的一个组件,其作用是为了操作Docker。Docker是在2013年面世的而Kubernetes是在2016年,所以Docker刚开始并没有想到编排,也不会知道会出现Kubernetes这个庞然大物(它要是知道,也不会败的那么快)。但是Kubernetes在创建的时候就是以Docker作为容器运行时,很多操作逻辑都是针对的Docker,随着社区越来越健壮,为了兼容更多的容器运行时,才将Docker的相关逻辑独立出来组成了dockershim。

正因为这样,只要Kubernetes的任何变动或者Docker的任何变动,都必须维护dockershim,这样才能保证足够的支持,但是通过dockershim操作Docker,其本质还是操作Docker的底层运行时Containerd,而且Containerd自身也是支持CRI(Container Runtime Interface)交互,所以正如前面所说只是kubernetes不想单独维护一个类似于Dockershim的适配层去迎合不同的运行时。

相关参考
Containerd 官网: https://containerd.io/
Containerd 帮助文档: https://containerd.io/docs/
CNI 网络项目: https://github.com/containernetworking

Tips: 在github存储库中的 containerd 基本项目级信息:

  • containerd/containerd :containerd的主要项目repo,包括container运行时以及从containerd 1.5开始,用于Kubernetes容器运行时接口(CRI)已并入containerd。

  • containerd/containerd.io : 用于构建containerd网站和文档的资产(即您当前正在阅读的内容)

  • containerd/project : 跨containerd存储库使用的实用程序,如脚本、公共文件和核心文档

  • containerd/ttrpc : containerd使用的gRPC版本(为低内存环境设计)

2.专业术语

描述: 在介绍容器运行时相关概念及组件原理,梳理下我们常听到的 OCI、runc、containerd 等名词之间的关系。

OCI
Docker 公司与 CoreOS 和 Google 共同创建了 OCI (Open Container Initial) 并提供了两种规范:

  1. 镜像规范 (https://github.com/opencontainers/image-spec) 镜像规范定义了OCI镜像的标准,high level 运行时将会下载一个OCI 镜像,并把它解压成OCI 运行时文件系统包(filesystem bundle),例如 制定镜像格式、操作等

  1. 运行时规范 (https://github.com/opencontainers/runtime-spec): 描述了如何从OCI 运行时文件系统包运行容器程序,并且定义它的配置、运行环境和生命周期,如何为新容器设置命名空间(namepsaces)和控制组(cgroups),以及挂载根文件系统等等操作,都是在这里定义的。它的一个参考实现是runC(低层级运行时- Low-level Runtime)除它以外也有很多其他的运行时遵循OCI标准,例如kata-runtime。

Tips: 文件系统束(filesystem bundle): 定义了一种将容器编码为文件系统束的格式,即以某种方式组织的一组文件,并包含所有符合要求的运行时对其执行所有标准操作的必要数据和元数据,即 config.json 与 根文件系统。

Tips: CRI(Container Runtime Interface,容器运行时接口) : 它是为了解决这些容器运行时和Kubernetes的集成问题在Kubernetes 1.5版本中推出。

Docker、Google 等开源了用于运行容器的工具和库 runC 作为 OCI 的一种实现参考, 随后各种运行时和库也慢慢出现例如 rkt、containerd(今天的主角)、cri-o,然而这些工具所拥有的功能却不尽相同,有的只有运行容器(runc、lxc),而有的除此之外也可以对镜像进行管理(containerd、cri-o), 按照前面容器运行时进行分为两类, 其不同容器运行时工具分类关系图如下。

Runtime

  1. 容器运行时(Container Runtime): 运行于Docker或者Kubernetes集群的每个节点中, 负责容器的整个生命周期,包括构建、创建、运行、管理、删除等对容器的操作。其中Docker是目前应用最广的,随着容器云的发展,越来越多的容器运行时涌现。

  • (1) low-level : 指的是仅关注运行容器的容器运行时,调用操作系统,使用 namespace 和 cgroup 实现资源隔离和限制

  • (2) high-level :指包含了更多上层功能,例如 grpc调用,镜像存储管理等。

  1. 容器运行时分成了 low-level 和 high-level 两类。

(1) low-level runtime : 主要关注如何与操作系统资源交互和创建并运行容器。目前常见的 low-level runtime有:

  • lmctfy -- Google的一个项目它是Borg使用的容器运行时。

  • runc -- 目前使用最广泛的容器运行时。它最初是作为Docker的一部分开发的,后来被提取出来作为一个单独的工具和库, 其实现了 OCI 规范包含config.json文件和容器的根文件系统。

  • rkt -- CoreOS开发的Docker/runc的一个流行替代方案,提供了其他 low-level runtimes (如runc)所提供的所有特性。

(2) high-level runtime : 主要负责传输和管理容器镜像,解压镜像,并传递给low-level runtimes来运行容器。目前主流的 high-level runtime 有:

  • docker -- 老熟人完整的集装箱(Container)解决方案

  • containerd -- 本章主角

  • rkt -- 与Docker类似的容器引擎更加专注于解决安全、兼容、执行效率等方面的问题。

CRI
描述: CRI是Kubernetes定义的一组gRPC服务。Kubelet作为客户端,基于gRPC框架,通过Socket和容器运行时通信。它包括两类服务:镜像服务(Image Service)和运行时服务(Runtime Service)。镜像服务提供下载、检查和删除镜像的远程程序调用。运行时服务包含用于管理容器生命周期,以及与容器交互的调用 ( exec / attach / port-forward ) 的远程程序调用。

客户端工具

  • ctr: 是containerd本身的 CLI (https://github.com/containerd/containerd/tree/master/cmd/ctr)

  • crictl: 是Kubernetes社区定义的专门 CLI 工具 (https://github.com/kubernetes-sigs/cri-tools)

3.架构简述

描述: containerd是Linux和Windows的守护程序。它管理其主机系统的完整容器生命周期,从图像传输和存储到容器执行和监督,再到低级存储到网络附件等等。

Containerd 的设计是一个大的插件系统,下图中每一个虚线框其实就对应一个插件。

  1. 底层系统支持 Linux 、Windows操作系统 和 支持 arm 和 x86 架构

  • Backend 层: Runtime plugin 提供了容器运行时的具体操作,为了支持不同的容器运行时 containerd 也提供了一系列的 containerd-shim

  • Core 层: 则是核心部分,提供了各种功能的服务,其中比较常用的是 Content service ,提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里;Images Service 提供镜像相关的操作;Snapshot Plugin : 用来管理容器镜像的文件系统快照。镜像中的每一个 layer 都会被解压成文件系统快照,类似于 Docker 中的 graphdriver

  • API 层: 通过 GRPC 与客户端连接,例如提供了给 Prometheus 使用 API 来进行监控,给kubernetes提供了CRI接口,给containerd提供了服务处理程序。

  1. 中间 containerd 包含 Backend、core、API 三层

  1. 高层提供各种客户端,包括 K8s 的 kubelet,containerd 自己的命令行 ctr 等。

我们可以将上面的架构图简化如下, 简化后的Containerd 分为三大块Storage 管理镜像文件的存储;Metadata 管理镜像和容器的元数据;由 Task 触发运行时, 并对外提供 GRPC 方式的 API 以及 Metrics 接口。

containerd-shim
描述: 主要是用于剥离 containerd 守护进程与容器进程。目前已有 shim v1 和 shim v2 两个版本;它是containerd中的一个组件,其通过 shim 调用 runc 的包函数来启动容器。直白的说引入shim是允许runc在创建和运行容器之后退出, 并将shim作为容器的父进程, 而不是containerd作为父进程。

# - 当我们执行 pstree 命令时可以看到如下的进程关系containerd-shim是独立于containerd进程运行的。
pstree
systemd─┬─VGAuthService├─containerd───15*[{containerd}]├─containerd-shim─┬─sh│                 └─13*[{containerd-shim}]├─2*[containerd-shim─┬─sh]│                    └─12*[{containerd-shim}]]

此种方式的目的是当containerd进程挂掉时保证容器不受影响, 此外 shim 也可以收集和报告容器的退出状态,不需要 containerd 来 wait 容器进程。

Tips:我们有需求去替换 runc 运行时工具库时,例如 替换为安全容器 kata container 或 Google 研发的 gViser,则需要增加对应的 shim(kata-shim) 以上两者均有自己实现的 shim。

CRI & OCI
如下图所示 dockershim,containerd 和 cri-o 都是遵循CRI的容器运行时,我们称他们为高层级运行时(High-level Runtime)。

Containerd vs Cri-o
描述: 前面我们说到过kubernetes为啥会替换掉Docker呢?主要原因就是其复杂性,由于Docker的多层封装和调用,导致其在可维护性上略逊一筹,增加了线上问题的定位难度(貌似除了重启Docker,我们就毫无他法了);

  • 如下图所示,我们总结了Docker,containerd以及cri-o的详细调用层级, Containerd和cri-o的方案比起 Docker 简洁很多, 因此我们更偏向于选用更加简单和纯粹的 containerd 和 cri-o 作为我们的容器运行时,kubernetes 1.20.x 之上的版本建议使用containerd作为容器运行时。

  • 如下图所示,我们对containerd和cri-o进行了一组性能测试,包括创建、启动、停止和删除容器,得出它们所耗的时间。
    Tips : containerd在各个方面都表现良好,除了启动容器这项。从总用时来看 containerd的用时还是要比cri-o要短的。

  • 如下图所示, 从功能性来讲containerd和cri-o都符合CRI和OCI的标准。从稳定性来说,单独使用containerd和cri-o都没有足够的生产环境经验。但庆幸的是,containerd一直在Docker里使用,而Docker的生产环境经验可以说比较充足。可见在稳定性上containerd略胜一筹。所以我们最终选用了containerd。

- Containerd CRI-O 备注
性能 更优 -
功能 CRI与OCI兼容
稳定性 稳定 未知 -

Device Mapper vs. Overlayfs
描述: 容器运行时使用存储驱动程序(storage driver)来管理镜像和容器的数据。目前我们生产环境选用的是Device Mapper。然而目前Device Mapper在新版本的Docker中已经被弃用,containerd也放弃对Device Mapper的支持。

当初选用Device Mapper,也是有历史原因的。我们大概是在2014年开始Kubernetes这个项目的。那时候Overlayfs都还没合进kernel。当时我们评估了Docker支持的存储驱动程序,发现Device Mapper是最稳定的。所以我们选用了Device Mapper。但是实际使用下来,由Device Mapper引起的Docker问题也不少。所以我们也借这个契机把Device Mapper给换掉,换成现在containerd和Docker都默认的Overlayfs。

从下图的测试结果来看,Overlayfs的IO性能比 Device Mapper 好很多。Overlayfs的IOPS大体上能比Device Mapper高20%,和直接操作主机路径差不多。最终,我们选用了containerd,并以Overlayfs作为存储后端的文件系统,替换了原有的Docker加Device Mapper的搭配。

我们在同一个节点上同时起10,30,50和80的Pod,然后再同时删除,去比较迁移前后创建和删除的用时。从下图可知,containerd用时明显优于Docker。


0x01 安装配置

1.Ubuntu安装Containerd.io流程

安装环境: 已进行安全基线加固以及系统优化。

# - OS
$ lsb_release -a# Description:    Ubuntu 20.04.2 LTS focal
$ uname -a# Linux containerd 5.4.0-78-generic #87-Ubuntu SMP Fri Jun 18 16:29:09 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux# - Container : 1.4.6-1
apt-cache madison containerd.io | cut -d '|' -f 2 |  sed 's/^[ \t]*//g'# 1.4.6-1# 1.4.4-1# 1.4.3-2# 1.4.3-1# 1.3.9-1# 1.3.7-1# 1.2.13-2

安装流程

  • Step 1.参考Kubernetes容器运行时接口进行安装前的基础环境准备.

# 安装和配置先决条件:
# 模块加载
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter# Setup required sysctl params, these persist across reboots.
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF# Apply sysctl params without reboot
sudo sysctl --system
  • Step 2.在Ubuntu中安装containerd.io,它来自官方Docker存储库的软件包我们可以参考安装Install Docker Engine(https://docs.docker.com/engine/install/ubuntu/)中的安装命令。

# - 卸载原有Docker 以及 containerd
sudo apt-get remove docker docker-engine docker.io containerd runc
# - 更新apt程序包索引并安装程序包,以允许apt通过HTTPS使用存储库
sudo apt-get update
sudo apt-get install \apt-transport-https \ca-certificates \curl \gnupg \lsb-release# - 添加Docker的官方GPG密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg# - 使用以下命令设置稳定存储库。要添加nightly或test存储库,请在下面的命令中的单词stable后面添加单词nightly或test(或两者)。
echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null# - 更新apt包索引,安装最新版本的containerd或进入下一步安装特定版本:
sudo apt-get update
# 安装前可查看containerd.io可用的版本: apt-cache madison containerd.io && apt install containerd.io=1.4.6-1
apt install containerd.io# - 查看安装Containerd的版本
$ ctr --version# ctr containerd.io 1.4.6
  • Step 3.初始化Containerd.io基础配置

# - 初始化配置
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# - 替换默认的 sandbox_image = "k8s.gcr.io/pause:3.2" 镜像因为GFW的原因导致无法访问我们可以替换为阿里云镜像源。
sed -ir 's#sandbox_image = \S\w+.*$#sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"#g' /etc/containerd/config.toml
sed -ir "s#https://registry-1.docker.io#https://registry.cn-hangzhou.aliyuncs.com#g"  /etc/containerd/config.toml# - 应用配置并重新运行containerd服务并查看服务状态
systemctl daemon-reload && systemctl restart containerd
systemctl status containerd.service# ● containerd.service - containerd container runtime#     Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)#     Active: active (running) since Sun 2021-06-27 19:05:48 CST; 8s ago#       Docs: https://containerd.io#     Process: 3088 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)#   Main PID: 3097 (containerd)#       Tasks: 15#     Memory: 22.6M#     CGroup: /system.slice/containerd.service#             └─3097 /usr/bin/containerd

Tips : 查看默认的

$ cat /etc/containerd/config.toml
version = 2
root = "/var/lib/containerd"
state = "/run/containerd"
plugin_dir = ""
disabled_plugins = []
required_plugins = []
oom_score = 0[grpc]address = "/run/containerd/containerd.sock"tcp_address = ""tcp_tls_cert = ""tcp_tls_key = ""uid = 0gid = 0max_recv_message_size = 16777216max_send_message_size = 16777216[ttrpc]address = ""uid = 0gid = 0[debug]address = ""uid = 0gid = 0level = ""[metrics]address = ""grpc_histogram = false[cgroup]path = ""[timeouts]"io.containerd.timeout.shim.cleanup" = "5s""io.containerd.timeout.shim.load" = "5s""io.containerd.timeout.shim.shutdown" = "3s""io.containerd.timeout.task.state" = "2s"[plugins][plugins."io.containerd.gc.v1.scheduler"]pause_threshold = 0.02deletion_threshold = 0mutation_threshold = 100schedule_delay = "0s"startup_delay = "100ms"[plugins."io.containerd.grpc.v1.cri"]disable_tcp_service = truestream_server_address = "127.0.0.1"stream_server_port = "0"stream_idle_timeout = "4h0m0s"enable_selinux = falseselinux_category_range = 1024sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"stats_collect_period = 10systemd_cgroup = falseenable_tls_streaming = falsemax_container_log_line_size = 16384disable_cgroup = falsedisable_apparmor = falserestrict_oom_score_adj = falsemax_concurrent_downloads = 3disable_proc_mount = falseunset_seccomp_profile = ""tolerate_missing_hugetlb_controller = truedisable_hugetlb_controller = trueignore_image_defined_volumes = false[plugins."io.containerd.grpc.v1.cri".containerd]snapshotter = "overlayfs"default_runtime_name = "runc"no_pivot = falsedisable_snapshot_annotations = truediscard_unpacked_layers = false[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]runtime_type = ""runtime_engine = ""runtime_root = ""privileged_without_host_devices = falsebase_runtime_spec = ""[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]runtime_type = ""runtime_engine = ""runtime_root = ""privileged_without_host_devices = falsebase_runtime_spec = ""[plugins."io.containerd.grpc.v1.cri".containerd.runtimes][plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]runtime_type = "io.containerd.runc.v2"runtime_engine = ""runtime_root = ""privileged_without_host_devices = falsebase_runtime_spec = ""[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options][plugins."io.containerd.grpc.v1.cri".cni]bin_dir = "/opt/cni/bin"conf_dir = "/etc/cni/net.d"max_conf_num = 1conf_template = ""[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://registry-1.docker.io"][plugins."io.containerd.grpc.v1.cri".image_decryption]key_model = ""[plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]tls_cert_file = ""tls_key_file = ""[plugins."io.containerd.internal.v1.opt"]path = "/opt/containerd"[plugins."io.containerd.internal.v1.restart"]interval = "10s"[plugins."io.containerd.metadata.v1.bolt"]content_sharing_policy = "shared"[plugins."io.containerd.monitor.v1.cgroups"]no_prometheus = false[plugins."io.containerd.runtime.v1.linux"]shim = "containerd-shim"runtime = "runc"runtime_root = ""no_shim = falseshim_debug = false[plugins."io.containerd.runtime.v2.task"]platforms = ["linux/amd64"][plugins."io.containerd.service.v1.diff-service"]default = ["walking"][plugins."io.containerd.snapshotter.v1.devmapper"]root_path = ""pool_name = ""base_image_size = ""async_remove = false
  • Step 4.查看containerd Client与Server端的信息。

$ ctr version
Client:Version:  1.4.6Revision: d71fcd7d8303cbf684402823e425e9dd2e99285dGo version: go1.13.15Server:Version:  1.4.6Revision: d71fcd7d8303cbf684402823e425e9dd2e99285dUUID: 71a28bbb-6ed6-408d-a873-e394d48b35d8

0x02 简单使用

描述: 此处以上面Ubuntu的安装环境进行演示。

1.镜像拉取与运行

Tips : containerd 默认的三个名称空间(Namespace)是default,docker.io,k8s.io

# - 1.将 hello-world:latest 镜像拉取到默认的名称空间中,将busybox:latest镜像拉取到k8s.io名称空间中。
ctr image pull docker.io/library/hello-world:latest
ctr -n k8s.io image pull docker.io/library/busybox:latest
ctr -n k8s.io image pull registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0# - 2.分别查看拉取的镜像
ctr image ls && ctr -n k8s.io image ls# REF                                  TYPE                                                      DIGEST                                                                  SIZE    PLATFORMS                                                                                                             LABELS# docker.io/library/hello-world:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c 6.5 KiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x,windows/amd64 # docker.io/library/busybox:latest                                        application/vnd.docker.distribution.manifest.list.v2+json sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d 752.6 KiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x io.cri-containerd.image=managed# registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0     application/vnd.docker.distribution.manifest.v2+json      sha256:3b3a29e3c90ae7762bdf587d19302e62485b6bef46e114b741f7d75dba023bd3 306.4 KiB linux/amd64                                                                                                          io.cri-containerd.image=managed# - 3.运行hello-world:latest和分步运行busybox镜像
ctr run docker.io/library/hello-world:latest hello-world
# Hello from Docker!
# ......
# For more examples and ideas, visit:
#  https://docs.docker.com/get-started/# 创建一个container(此时还未运行)
ctr -n k8s.io container create docker.io/library/busybox:latest busybox
# 创建一个task并后台运行
ctr -n k8s.io task start -d busybox
# 一步到位: ctr -n k8s.io run -d docker.io/library/busybox:latest busybox# - 4.查看你创建的容器与Task
ctr container ls && ctr -n k8s.io container ls# CONTAINER      IMAGE                                   RUNTIME# hello-world    docker.io/library/hello-world:latest    io.containerd.runc.v2# CONTAINER    IMAGE                               RUNTIME# busybox      docker.io/library/busybox:latest    io.containerd.runc.v2
# 查看该容器在宿主机的PID
ctr -n k8s.io task ls# TASK       PID      STATUS# busybox    25856    RUNNING
ps ajxf|grep "containerd-shim-runc\|25856"|grep -v grep1   25828   25828    3097 ?             -1 Sl       0   0:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id busybox -address /run/containerd/containerd.sock25828   25856   25856   25856 ?             -1 Ss       0   0:00  \_ sh# - 5.进入到容器内部执行shell命令
ctr -n k8s.io t exec --exec-id $RANDOM -t busybox sh# / # uname -a# Linux containerd 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 GNU/Linux# ---  此处你会发现只有lo网络卡后续我们可以通过CNI插件的形式添加网卡实现外部网络通信 --- # / # ip a# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00#     inet 127.0.0.1/8 scope host lo#       valid_lft forever preferred_lft forever#     inet6 ::1/128 scope host #       valid_lft forever preferred_lft forever# - 6.删除创建的Task与容器
ctr -n k8s.io t kill -s SIGKILL busybox  # 发送SIGKILL信号量杀死该容器
ctr -n k8s.io task rm busybox
ctr -n k8s.io container rm busybox
ctr container rm hello-world

2.创建和使用网络

描述: 在前面我们进入busybox容器中会发现里面只有一张网卡而且无法连接到外部网络之中,所以我们需要借助于CNI(Container Network Interface一个云计算基础项目来实现Containerd容器具有网络功能。

项目说明:

  • 2.1) CNI 网络插件(Plugins) : https://github.com/containernetworking/plugins (PS : 当前版本 v0.9.1)

  • 2.2) CNI 容器网络接口-Linux容器网络 : https://github.com/containernetworking/cni

操作流程:

  • Step 1.CNI插件下载

# - 1.从containernetworking/plugins的release页面下载最新版本并解压到/usr/local/cni-plugins:
wget https://github.com/containernetworking/plugins/releases/download/v0.9.1/cni-plugins-linux-amd64-v0.9.1.tgz
mkdir -vp /usr/local/cni-plugins && tar xvf cni-plugins-linux-amd64-v0.9.1.tgz -C /usr/local/cni-plugins# - 2.从containernetworking/cni的release页面下载最新版本并解压到/usr/local/cni-{version}:
wget https://github.com/containernetworking/cni/archive/refs/tags/v0.8.1.tar.gz
tar -zxvf v0.8.1.tar.gz -C /usr/local/
  • Step 2.创建和使用CNI网络插件

# - 使用bridge插件创建一个网卡依赖于一下面的配置文件。mkdir -p /etc/cni/net.d
cat >/etc/cni/net.d/10-mynet.conf <<EOF
{"cniVersion": "0.2.0","name": "mynet","type": "bridge","bridge": "cni0","isGateway": true,"ipMasq": true,"ipam": {"type": "host-local","subnet": "10.22.0.0/16","routes": [{ "dst": "0.0.0.0/0" }]}
}
EOFcat >/etc/cni/net.d/99-loopback.conf <<EOF
{"cniVersion": "0.2.0","name": "lo","type": "loopback"
}
EOF# - 注意json字符串解析需要依赖jq命令所以我们需要安装(已安装可以跳过)
apt install jq -y# - 利用CNI网络插件进行激活cni0网卡
/usr/local/cni-0.8.1/scripts# CNI_PATH=/usr/local/cni-plugins ./priv-net-run.sh echo "Hello World! CNI Plugins."
Hello World! CNI Plugins.# - 宿主机执行ip a命令即可看到一个cni0的网卡
/usr/local/cni-0.8.1/scripts# ip addr show cni0
3: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000link/ether ea:3e:1b:23:66:3a brd ff:ff:ff:ff:ff:ffinet 10.22.0.1/16 brd 10.22.255.255 scope global cni0valid_lft forever preferred_lft forever
  • Step 3.使containerd容器具备网络功能(使其具备各容器互通、外部网络通信功能)

# - 将busybox容器实现网络通信
ctr -n k8s.io run -d docker.io/library/busybox:latest busybox
ctr -n k8s.io task ls# TASK       PID      STATUS# busybox    43908    RUNNING
pid=$(ctr -n k8s.io t ls|grep busybox|awk '{print $2}')
netnspath=/proc/$pid/ns/net
CNI_PATH=/usr/local/cni-plugins /usr/local/cni-0.8.1/scripts/exec-plugins.sh add $pid $netnspath# - 随后进入busybox容器我们将会发现其新增了一张网卡并可以实现外部网络访问:
ctr -n k8s.io task exec --exec-id $RANDOM -t busybox  sh -# / # ip addr# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00#     inet 127.0.0.1/8 scope host lo#       valid_lft forever preferred_lft forever#     inet6 ::1/128 scope host#       valid_lft forever preferred_lft forever# 3: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue#     link/ether d6:fd:92:9c:8a:a9 brd ff:ff:ff:ff:ff:ff#     inet 10.22.0.3/16 brd 10.22.255.255 scope global eth0#       valid_lft forever preferred_lft forever#     inet6 fe80::d4fd:92ff:fe9c:8aa9/64 scope link#       valid_lft forever preferred_lft forever# / # ping 223.6.6.6   # 外网没有问题。PING 223.6.6.6 (223.6.6.6): 56 data bytes64 bytes from 223.6.6.6: seq=0 ttl=113 time=7.902 ms64 bytes from 223.6.6.6: seq=1 ttl=113 time=7.102 ms# - 在创建一个busybox-1实现互通。
ctr -n k8s.io run -d docker.io/library/busybox:latest busybox-1
pid=$(ctr -n k8s.io t ls|grep busybox-1|awk '{print $2}')
netnspath=/proc/$pid/ns/net
CNI_PATH=/usr/local/cni-plugins /usr/local/cni-0.8.1/scripts/exec-plugins.sh add $pid $netnspath# - 查看你创建容器的pid进程相关信息
ps ajxf|egrep "containerd-shim-runc|43908|48850"|grep -v grep#     1   43883   43883   39042 ?             -1 Sl       0   0:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id busybox -address /run/containerd/containerd.sock# 43883   43908   43908   43908 ?             -1 Ss       0   0:00  \_ sh#     1   48825   48825   39042 ?             -1 Sl       0   0:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id busybox-1 -address /run/containerd/containerd.sock# 48825   48850   48850   48850 ?             -1 Ss       0   0:00  \_ sh# - 查看创建的busybox-1相关信息
ctr -n k8s.io task exec --exec-id $RANDOM -t busybox-1 sh -# 3: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue#     link/ether 9e:70:c6:cd:a5:7b brd ff:ff:ff:ff:ff:ff#     inet 10.22.0.4/16 brd 10.22.255.255 scope global eth0#       valid_lft forever preferred_lft forever#     inet6 fe80::9c70:c6ff:fecd:a57b/64 scope link#       valid_lft forever preferred_lft forever

Tips : 采用nc -l -v -p 8080监听在另外的一个容器里面进行通信链接。

3.与宿主机和其它容器共享文件

描述: 在Docker我们常常需要将配置文件或者各类数据映射进入到docker容器之中,便于容器内部程序使用或者数据的持久化。

下面分别简单演示与宿主机或者其它容器共享目录;

  • (1) 宿主机共享

ctr -n k8s.io c create docker.io/library/busybox:latest busybox-2 --mount type=bind,src=/tmp,dst=/host,options=rbind:rwctr -n k8s.io t start -d busybox-2 shctr -n k8s.io t exec -t --exec-id $RANDOM busybox-2 sh# / # echo "WeiyiGeek" > /host/name# / #
root@containerd:~# cat /tmp/name
WeiyiGeek
  • (2) 其它容器间共享
    描述: 本章节对于PID NS共享为例其它的NS共享与该方案类似,下面我们利用docker 与 container 对ns共享设置做一个对比。

首先我们对docker的ns共享进行实验:

[root@docker scripts]# docker run --rm -it -d busybox sh
687c80243ee15e0a2171027260e249400feeeee2607f88d1f029cc270402cdd1
[root@docker scripts]# docker run --rm -it -d --pid="container:687c80243ee15e0a2171027260e249400feeeee2607f88d1f029cc270402cdd1" busybox cat
fa2c09bd9c042128ebb2256685ce20e265f4c06da6d9406bc357d149af7b83d2
[root@docker scripts]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fa2c09bd9c04        busybox             "cat"               2 seconds ago       Up 1 second                             pedantic_goodall
687c80243ee1        busybox             "sh"                22 seconds ago      Up 21 seconds                           hopeful_franklin
[root@docker scripts]# docker exec -it 687c80243ee1 sh
/ # ps aux
PID   USER     TIME  COMMAND1 root      0:00 sh8 root      0:00 cat15 root      0:00 sh

然后基于containerd的方式实现pid ns共享:

$ ctr -n k8s.io t ls# TASK         PID      STATUS# busybox      43908    RUNNING # busybox-1    48850    RUNNING  # 这里的48850即为已有task运行时的pid号# busybox-2    50314    RUNNING$ ctr -n k8s.io c create --with-ns "pid:/proc/48850/ns/pid" v4ehxdz8.mirror.aliyuncs.com/library/python:3.6-slim python # 将 容器中运行 的进程共享注入到 48850 pid之中$ ctr -n k8s.io t start -d python python  # 启动了一个python的命令$ ctr -n k8s.io t exec -t --exec-id $RANDOM busybox-1 sh # 至此可以在busybox-1容器中看见刚执行的python命令
/ # ps aux
PID   USER     TIME  COMMAND1 root      0:00 sh34 root      0:00 python341 root      0:00 sh47 root      0:00 ps aux

4.Docker 与 Containerd 并用配置

描述: 为了更方便我们学习可以将 Docker 与 Containerd 联合使用。
Docker-CE安装参考链接:https://docs.docker.com/engine/reference/commandline/dockerd/

  • Step 1.在前面我们完成 containerd 的安装配置并启动后,我们可以在宿主机中安装docker客户端及服务。

echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-update
# - 查看可用版本
apt-cache madison docker-ce
# - 安装指定版本 (20.10.X 版本支持 Docker Scan 特性)
sudo apt-get install docker-ce=5:20.10.7~3-0~ubuntu-focal docker-ce-cli=5:20.10.7~3-0~ubuntu-focal
  • Step 2.编辑/etc/systemd/system/multi-user.target.wants/docker.service文件并为其新增 --containerd如下启动项:--containerd /run/containerd/containerd.sock

vim /etc/systemd/system/multi-user.target.wants/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --debug# - 重新加载配置
systemctl daemon-reload
  • Step 3.添加低权限用户到docker组里并自启Docker。

sudo gpasswd -a ${USER} docker
systemctl enable docker && systemctl status docker# ● docker.service - Docker Application Container Engine#     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)#     Active: active (running) since Mon 2021-07-05 12:47:10 CST; 5min ago# TriggeredBy: ● docker.socket#       Docs: https://docs.docker.com#   Main PID: 129606 (dockerd)#       Tasks: 12#     Memory: 45.0M#     CGroup: /system.slice/docker.service#             └─129606 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --debug# 或者查看 Dockerd 服务端执行的命令
ps aux|grep docker# root      129606  0.0  4.4 1021016 89792 ?       Ssl  12:47   0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --debug# 新增docker0网卡信息
# 7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
#   link/ether 02:42:23:41:2c:db brd ff:ff:ff:ff:ff:ff
#   inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
#       valid_lft forever preferred_lft forever
  • Step 4.打开两个Shell终端一个采用 docker 运行一个 busybox 容器,另外一个查看对比。

$ docker run --rm -it busybox sh# / # ip addr# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00#     inet 127.0.0.1/8 scope host lo#       valid_lft forever preferred_lft forever# 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue#     link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff#     inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0   # 关键点#       valid_lft forever preferred_lft forever# / # cat /etc/hosts# 127.0.0.1       localhost# 172.17.0.2      51dcdf68d3b8# 采用 ctr 在 moby 名称空间下查看docker创建的容器以及Task PID
$ ctr -n moby c ls# CONTAINER                                                           IMAGE    RUNTIME# 51dcdf68d3b8bf4c9707c9059e33f9570cb83725355595e77cf433dd3e25b64b    -        io.containerd.runc.v2
$ ctr -n moby t ls# TASK                                                                PID       STATUS# 51dcdf68d3b8bf4c9707c9059e33f9570cb83725355595e77cf433dd3e25b64b    131926    RUNNING# 验证获取到的 Task PID 下其 net 相关信息
$ grep "172.17.0.2" /proc/131926/net/fib_trie|-- 172.17.0.2|-- 172.17.0.2# 采用 ctr 进入 Docker 创建的容器
$ ctr -n moby t exec -t --exec-id $RANDOM  51dcdf68d3b8bf4c9707c9059e33f9570cb83725355595e77cf433dd3e25b64b sh# / # ip addr | grep "172.17.0.2"#   inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0# / # hostname#   51dcdf68d3b8

0x03 Containerd 与 Docker CLI 工具命令表

描述: Containerd 和 Docker 在命令使用上的一些区别主要如下:

功能 Containerd CLI Docker CLI Crictl CLI
镜像列举 ctr image [ls/list] docker images [ls] crictl images [ls]
导出镜像 ctr image export app.tar weiyigeek.top/app:1.2.0 docker save -o app.tar app:1.2.0
导入镜像 ctr image import app.tar docker load -i app.tar
拉取镜像 ctr -n k8s.io images pull docker.io/library/redis:latest docker pull redis:latest crictl pull redis:latest
上传镜像 ctr -n k8s.io images push docker.io/library/redis:latest docker push crictl push
更改标记 ctr -n k8s.io images tag docker.io/library/redis:latest weiyigeek.top/redis:latest docker tag redis:latest weiyigeek.top/redis:latest
删除镜像 ctr -n k8s.io images rm docker.io/library/redis:latest docker rmi crictl rmi
创建容器 ctr -n k8s.io container create docker.io/library/redis:latest redis docker create crictl create
创建并运行容器 ctr run -d --env name=WeiyiGeek application weiyigeek.top/app:1.2.0 docker run
查看容器 ctr -n k8s.io container list docker ps crictl ps
启动容器 ctr -n k8s.io task start docker start crictl start
停止容器 ctr -n k8s.io task pause docker stop crictl stop
删除容器 ctr -n k8s.io container rm docker rm crictl rm
容器详情 ctr -n k8s.io c info 39d36ef08456 docker inspect 39d36ef08456 crictl inspect 39d36ef08456
容器连接 ctr -n k8s.io task attach docker attach crictl attach
进入容器 ctr -n k8s.io task exec docker exec crictl exec
stats(状态) ctr -n k8s.io task metric 39d36ef08456 docker top crictl stats
日志查看 ctr -n k8s.io event docker logs --tail 50 8db74c2bf7595 crictl logs --tail 50 8db74c2bf7595

Tips : 当导入本地镜像时ctr不支持压缩。

ctr 命令 - Containerd 管理命令详细

描述: 它是一个不受支持的调试和管理客户端,用于与容器守护进程进行交互。因为它不受支持,所以命令、选项和操作不能保证向后兼容或稳定从集装箱项目的发布到发布。

语法参数:

#USAGE:ctr [global options] command [command options] [arguments...]# GLOBAL OPTIONS:--debug                      enable debug output in logs--address value, -a value    address for containerds GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]--timeout value              total timeout for ctr commands (default: 0s)--connect-timeout value      timeout for connecting to containerd (default: 0s)--namespace value, -n value  namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]--version, -v                print the version# COMMANDS:plugins, plugin            provides information about containerd pluginsversion                    print the client and server versionscontainers, c, container   manage containerscontent                    manage contentevents, event              display containerd eventsimages, image, i           manage imagesleases                     manage leasesnamespaces, namespace, ns  manage namespacespprof                      provide golang pprof outputs for containerdrun                        run a containersnapshots, snapshot        manage snapshotstasks, t, task             manage tasksinstall                    install a new packageoci                        OCI toolsshim                       interact with a shim directly (直接与shim交互)help, h                    Shows a list of commands or help for one command# 子命令 #
# Images COMMANDS:check       check that an image has all content available locally(找到发生故障的容器后,可以使用以下工具检查其日志)export      export imagesimport      import imageslist, ls    list images known to containerdmount       mount an image to a target pathunmount     unmount the image from the targetpull        pull an image from a remotepush        push an image to a remoteremove, rm  remove one or more images by referencetag         tag an imagelabel       set and clear labels for an image# Container COMMANDS:create           create containerdelete, del, rm  delete one or more existing containersinfo             get info about a containerlist, ls         list containerslabel            set and clear labels for a containercheckpoint       checkpoint a container (检查点容器)restore          restore a container from checkpoint(从检查点还原容器)# run OPTIONS:--rm                                    remove the container after running--null-io                               send all IO to /dev/null (将容器内标准输出重定向到/dev/null)--log-uri value                         log uri--detach, -d                            detach from the task after it has started execution(在任务开始执行后从中分离,如没有选项则会等待用户输入并定向到容器内)--fifo-dir value                        directory used for storing IO FIFOs--cgroup value                          cgroup path (To disable use of cgroup, set to "" explicitly)--platform value                        run image for specific platform--runc-binary value                     specify runc-compatible binary--runc-systemd-cgroup                   start runc with systemd cgroup manager--uidmap container-uid:host-uid:length  run inside a user namespace with the specified UID mapping range; specified with the format container-uid:host-uid:length--gidmap container-gid:host-gid:length  run inside a user namespace with the specified GID mapping range; specified with the format container-gid:host-gid:length--remap-labels                          provide the user namespace ID remapping to the snapshotter via label options; requires snapshotter support--cpus value                            set the CFS cpu qouta (default: 0)--snapshotter value                     snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER]--config value, -c value                path to the runtime-specific spec config file--cwd value                             specify the working directory of the process--env value                             specify additional container environment variables (i.e. FOO=bar)--env-file value                        specify additional container environment variables in a file(i.e. FOO=bar, one per line)--label value                           specify additional labels (i.e. foo=bar)--mount value                           specify additional container mount (ex: type=bind,src=/tmp,dst=/host,options=rbind:ro)--net-host                              enable host networking for the container--privileged                            run privileged container--read-only                             set the containers filesystem as readonly--runtime value                         runtime name (default: "io.containerd.runc.v2")--tty, -t                               allocate a TTY for the container--with-ns value                         specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')--pid-file value                        file path to write the task's pid--gpus value                            add gpus to the container (default: 0)--allow-new-privs                       turn off OCI spec's NoNewPrivileges feature flag--memory-limit value                    memory limit (in bytes) for the container (default: 0)--device value                          add a device to a container--seccomp                               enable the default seccomp profile--rootfs                                use custom rootfs that is not managed by containerd snapshotter--no-pivot                              disable use of pivot-root (linux only)--cpu-quota value                       Limit CPU CFS quota (default: -1)--cpu-period value                      Limit CPU CFS period (default: 0)# Tasks COMMANDS:attach           attach to the IO of a running containercheckpoint       checkpoint a containerdelete, rm       delete one or more tasksexec             execute additional processes in an existing containerlist, ls         list taskskill             signal a container (default: SIGTERM)pause            pause an existing containerps               list processes for containerresume           resume a paused containerstart            start a container that has been createdmetrics, metric  get a single data point of metrics for a task with the built-in Linux runtime

Tips: containerd 引入了 namespace 概念, 每个image和container都会在各自的namespace下可见, 目前k8s会使用 k8s.io 以及 default 作为命名空间。

实际案例:

# 1) 名称空间查看创建或删除
ctr namespace create devops
ctr namespace ls -q# devops# k8s.io
ctr namespace remove devops# 2) 镜像查看及其操作
ctr -n k8s.io images ls | grep "busybox"# docker.io/library/busybox:1.33.1 application/vnd.docker.distribution.manifest.list.v2+json sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d 752.6 KiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x io.cri-containerd.image=managed
ctr -n k8s.io i rm k8s.gcr.io/pause:3.2       # 删除镜像
ctr -n k8s.io i pull -k k8s.gcr.io/pause:3.2  # 拉取镜像
ctr -n k8s.io i push -k k8s.gcr.io/pause:3.2  # 推送镜像
ctr -n k8s.io i export pause.tar k8s.gcr.io/pause:3.2 # 导出镜像
ctr -n k8s.io i import pause.tar              # 导入镜像
ctr -n k8s.io images check  | grep "busybox"  # 镜像检查# docker.io/library/busybox:1.33.1  application/vnd.docker.distribution.manifest.list.v2+json sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d complete (2/2) 750.1 KiB/750.1 KiB true
ctr -n k8s.io i tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2         # 镜像标记 Tag 更改
ctr -n k8s.io i tag --force registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2 # 若新镜像 reference 已存在需要先删除新 reference 或者如下方式强制替换
ctr -n k8s.io i label docker.io/library/busybox:1.33.1 name=weiyigeek-test  # 设置镜像标签# io.cri-containerd.image=managed,name=weiyigeek-test
ctr -n k8s.io i label docker.io/library/busybox:1.33.1 name=""              # 清除镜像标签# io.cri-containerd.image=managed# 3) 容器查看及其操作
ctr -n k8s.io container ls# CONTAINER                                                           IMAGE                                                            RUNTIME# 3d840c5cf157c322c1c0839d0166d80550fe49ca53544e1d589bd44f422b1f81    registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2    io.containerd.runc.v2
ctr -n k8s.io container create docker.io/library/busybox:latest busybox                       # 创建容器
ctr -n k8s.io container info 39d36ef08456bed24a52bf1c845facbd9f93c35cbd65b16739b4746ab1811cb5 # 查看创建的容器详情(注意这个必须是完整的容器ID)
ctr -n k8s.io container rm 39d36ef08456bed24a52bf1c845facbd9f93c35cbd65b16739b4746ab1811cb5   # 删除容器
ctr -n k8s.io container label busybox name=weiyigeek-test     # 设置容器标签# io.containerd.image.config.stop-signal=SIGTERM,name=weiyigeek-test# 4) 容器运行参数演示
ctr -n k8s.io run --null-io --net-host -d
–env PASSWORD=$drone_password
–mount type=bind,src=/etc,dst=/host-etc,options=rbind:rw
–mount type=bind,src=/root/.kube,dst=/root/.kube,options=rbind:rw
-log-uri file:///var/log/xx.log
WeiyiGeek:Test sysreport bash /sysreport/run.sh# 5) 容器Task查看以及相关操作
ctr -n k8s.io tasks ls# TASK                                                                PID      STATUS# 4cdf74e5b2afad420523bd681d97ed8a3cd322a730946566bad4d6dcc2a66c81    12708    RUNNING
ctr -n k8s.io tasks kill -a -s 9 {id}  # 停止容器内的Task
ctr -n k8s.io task metric 37d0ff9d8df20d34c652ee286c17e0626d8838d6d546a28e8246151fffd99b98 # - 使用内置的Linux运行时获取任务的单个度量数据点# ID                                                                  TIMESTAMP# 37d0ff9d8df20d34c652ee286c17e0626d8838d6d546a28e8246151fffd99b98    2021-07-11 03:33:18.421996083 +0000 UTC# METRIC                   VALUE                                                                                                            # memory.usage_in_bytes    65269760            # memory.limit_in_byte     9223372036854771712 # memory.stat.cache        4157440 # cpuacct.usage            44769155237                                                                                              # cpuacct.usage_percpu     [22375115908 22394039329 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]# pids.current             43          # pids.limit               4582

Tips: 注意容器默认使用fifo创建日志文件, 有可能因为fifo容量导致业务运行阻塞。
Tips: 注意需要停止容器时需要先停止容器内的Task再删除容器。

crictl 命令 - Kubernetes 管理命令详解

描述:crictl 是 CRI 兼容的容器运行时命令行对接客户端, 你可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序。由于该命令是为k8s通过CRI使用containerd而开发的(主要是调试工具), 其他非k8s的创建的 crictl 是无法看到和调试的, 简单的说用 ctr run 运行的容器无法使用 crictl 看到。

Tips: crictl 命令工具 和 它的源代码在 cri-tools 代码库。
Tips: crictl 默认使用命名空间 k8s.io.
Tips: cri plugin区别对待pod和container

官方参考: https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md

基础配置
描述: 在 k8s 1.19.x 之前 crictl 默认连接到 unix:///var/run/dockershim.sock,而在1.20.x起默认采用 /run/containerd/containerd.sock 运行时,当然除此之外还是支持cri-o运行时。

# crictl by default connects on Unix to:
unix:///var/run/dockershim.sock or
unix:///run/containerd/containerd.sock or
unix:///run/crio/crio.sock# or on Windows to:
npipe:./pipe/dockershim or
npipe:./pipe/containerd or
npipe:./pipe/crio# For other runtimes, use:
frakti: unix:///var/run/frakti.sock

查看或编辑 /etc/crictl.yaml 的内容

$ cat /etc/crictl.yaml
runtime-endpoint: /run/containerd/containerd.sock
image-endpoint: "/run/containerd/containerd.sock"
timeout: 0
debug: false
pull-image-on-create: false

Tips: 除了上面的设置端点外,我们还可以利用其它方式进行临时设置或者指定配置文件。

# 1.通过在配置文件中设置端点并通过 --config 参数指定配置文件
crictl --config=/etc/crictl-demo.yaml# 2.通过设置参数 --runtime-endpoint 和 --image-endpoint
crictl --runtime-endpoint="/run/containerd/containerd.sock" --image-endpoint="/run/containerd/containerd.sock"

基础语法:

# USAGE:crictl [global options] command [command options] [arguments...]# COMMANDS:attach        Attach to a running containercreate        Create a new containerexec          Run a command in a running containerversion       Display runtime version informationimages        List imagesinspect       Display the status of one or more containers (显示一个或多个容器的状态)inspecti      Return the status of one or more images (返回一个或者多个镜像的状态)inspectp      Display the status of one or more pods (返回一个或者多个Pod的状态)imagefsinfo: Return image filesystem infologs          Fetch the logs of a containerport-forward  Forward local port to a podps            List containerspull          Pull an image from a registryrunp          Run a new podrm            Remove one or more containersrmi           Remove one or more imagesrmp           Remove one or more podspods          List podsstart         Start one or more created containersinfo          Display information of the container runtimestop          Stop one or more running containersstopp         Stop one or more running podsupdate        Update one or more running containersconfig        Get and set crictl optionsstats         List container(s) resource usage statisticscompletion    Output bash shell completion codehelp, h       Shows a list of commands or help for one command# GLOBAL OPTIONS:--config value, -c value            Location of the client config file (default: "/etc/crictl.yaml") [$CRI_CONFIG_FILE]--debug, -D                         Enable debug mode--image-endpoint value, -i value    Endpoint of CRI image manager service [$IMAGE_SERVICE_ENDPOINT]--runtime-endpoint value, -r value  Endpoint of CRI container runtime service (default: "unix:///var/run/dockershim.sock") [$CONTAINER_RUNTIME_ENDPOINT]--timeout value, -t value           Timeout of connecting to the server (default: 10s)

ps: 列出在k8s.io 命名空间下的业务容器
pods: 列出在k8s.io 命名空间下的sandbox容器,在k8s里,通常是pause容器
create: 创建容器,这里需要先创建sandbox, 获取sandbox容器的id后,再用此id创建业务容器
inspect: 列出业务容器状态
inspectp: 列出sandbox容器状态

实践案例:

# 0) 镜像查看及其操作
crictl images --digests# IMAGE                                                                         TAG                 DIGEST              IMAGE ID            SIZE# docker.io/calico/cni                                                          v3.18.4             278fd825d089e       021ecb3cb5348       44.7MB
crictl images nginx   # - 打印某个镜像
crictl images -q      # - 只打印镜像ID# sha256:8c811b4aec35f259572d0f79207bc0678df4c736eeec50bc9fec37ed936a472a
crictl images -o [json|yaml|table]   # - 镜像详细信息
crictl pull busybox                  # - 拉取 busybox 镜像
crictl push weiyigeek.top/busybox    # - 推送 busybox 镜像
crictl rmi docker.io/library/busybox # - 容器删除# Deleted: docker.io/library/busybox:1.33.1# Deleted: docker.io/library/busybox:latest# 1) 容器查看及其操作
crictl ps -a  # - 打印在 k8s.io 命名空间下的业务容器
crictl --runtime-endpoint /run/containerd/containerd.sock ps -a | grep kube | grep -v pause # - 查看过滤指定的容器相关信息# CONTAINER ID        IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID# 8db74c2bf7595       ebc659140e762       3 days ago          Running             calico-node               0                   5af3d484b32c0
crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f[创建的 Pod 的 ID] container-config.json pod-config.json # - 创建容器
crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60  # - 启动容器
crictl stop 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60   # - 删除容器
crictl exec -i -t 1f73f2d81bf98 ls # - 容器上执行命令# 2) Pod查看与操作
$ crictl pods# POD ID              CREATED             STATE               NAME                                   NAMESPACE           ATTEMPT# 5af3d484b32c0       4 days ago          Ready               calico-node-zvst7                      kube-system         0
$ crictl pods --name nginx-65899c769f-wv2gp  # - 打印某个固定pod.
$ crictl pods --label run=nginx              # - 根据标签筛选pod.
$ crictl runp pod-config.json                # - 使用 crictl runp 命令应用 JSON 文件并运行沙盒。
$  crictl inspectp --output table $POD_ID # - 用crictl查看pod的信息# 3) 日志查看
crictl --runtime-endpoint /run/containerd/containerd.sock logs --tail 50 8db74c2bf7595# 4) 容器占用资源状态查看
crictl stats# CONTAINER           CPU %               MEM                 DISK                INODES# 8db74c2bf7595       0.69                53.37MB             274.4kB             81

Tips: 用 crictl 创建容器对容器运行时排错很有帮助。在运行的 Kubernetes 集群中,沙盒会随机的被 kubelet 停止和删除, 下面通过实例进行演示crictl使用。

  • Step 1.编写运行 Pod 沙盒的 JSON 文件,使用 crictl runp 命令应用 JSON 文件并运行沙盒。

$ cat pod-config.json
{"metadata": {"name": "nginx-sandbox","namespace": "default","attempt": 1,"uid": "hdishd83djaidwnduwk28bcsb"},"log_directory": "/tmp","linux": {}
}$ crictl runp pod-config.json
f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f
  • Step 2.检查沙盒是否处于就绪状态:

$ crictl pods
POD ID              CREATED             STATE               NAME                NAMESPACE           ATTEMPT
f84dd361f8dc5       17 seconds ago      Ready               busybox-sandbox     default             1
  • Step 3.使用运行时处理程序运行pod沙盒,运行时处理程序需要运行时支持。下面的示例显示如何在containerd运行时上使用runsc处理程序运行pod沙盒。

$ cat pod-config.json
{"metadata": {"name": "nginx-runsc-sandbox","namespace": "default","attempt": 1,"uid": "hdishd83djaidwnduwk28bcsb"},"log_directory": "/tmp","linux": {}
}$ crictl runp --runtime=runsc pod-config.json
c112976cb6caa43a967293e2c62a2e0d9d8191d5109afef230f403411147548c$ crictl inspectp c112976cb6caa43a967293e2c62a2e0d9d8191d5109afef230f403411147548c
..."runtime": {"runtimeType": "io.containerd.runtime.v1.linux","runtimeEngine": "/usr/local/sbin/runsc","runtimeRoot": "/run/containerd/runsc"},
...
  • Step 4.拉取 busybox 镜像然后在pod沙盒中使用config文件创建容器

crictl pull busybox:1.33.1# Image is up to date for sha256:69593048aa3acfee0f75f20b77acb549de2472063053f6730c4091b53f2dfb02$ cat pod-config.json
{"metadata": {"name": "nginx-sandbox","namespace": "default","attempt": 1,"uid": "hdishd83djaidwnduwk28bcsb"},"log_directory": "/tmp","linux": {}
}$ cat container-config.json
{"metadata": {"name": "busybox"},"image":{"image": "busybox:1.33.1"},"command": ["top"],"log_path":"busybox.log","linux": {}
}$ crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.json
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
  • Step 5.列出容器并检查容器是否处于已创建状并启动容器

$ crictl ps -a
CONTAINER ID        IMAGE               CREATED             STATE               NAME                ATTEMPT
3e025dd50a72d       busybox             32 seconds ago      Created             busybox             0$ crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60$ crictl ps
CONTAINER ID        IMAGE               CREATED              STATE               NAME                ATTEMPT
3e025dd50a72d       busybox             About a minute ago   Running             busybox             0
  • Step 6.在容器中执行命令

crictl exec -i -t 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60 ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少。
Tips : 本文章来源 Blog 站点或者 WeiyiGeek 公众账号 (技术交流、友链交换请邮我哟),

  • 公众号-WeiyiGeek # 精华文章发布地址(及时发布)

  • 首页-https://weiyigeek.top # 国内有时访问较慢(及时更新)

  • 博客-https://blog.weiyigeek.top # 国内访问快但(更新不及时)

历史文章:

1.Prometheus监控入门之基础架构介绍

2.Prometheus监控入门之环境安装配置

3.Prometheus监控入门之组件介绍和安装配置解析

1.Containerd容器运行时初识与尝试相关推荐

  1. 3.Containerd容器运行时的配置浅析与知识扩充实践

    公众号关注「WeiyiGeek」 设为「特别关注」,每天带你玩转网络安全运维.应用开发.物联网IOT学习! 本章目录: 0x00 Containerd 容器运行时配置指南 如何配置 Container ...

  2. 部署一个 Containerd 容器运行时的 Kubernetes 集群

    前面我们介绍了 containerd 的基本使用,也了解了如何将现有 docker 容器运行时的 Kubernetes 集群切换成 containerd,接下来我们使用 kubeadm 从头搭建一个使 ...

  3. Docker的容器运行时组件Containerd

    不久前,Docker宣布开源他们的容器运行时组件Containerd(发音是container-D).目前的Containerd版本是0.2.4,Docker计划在2017年第二季度基于Open Co ...

  4. 【容器运行时】一文理解 OCI、runc、containerd、docker、shim进程、cri、kubelet 之间的关系

    参考 docker,containerd,runc,docker-shim 之间的关系 Containerd shim 进程 PPID 之谜 内核大神教你从 Linux 进程的角度看 Docker R ...

  5. 课时 28:理解容器运行时接口 CRI(知谨)

    CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分.本文将主要分享以下三方面的内容: CRI 介绍 CRI 实现 相关工具 CRI 介绍 在 CRI 出现之前(也就是 Kuber ...

  6. 从零开始入门 K8s | 理解容器运行时接口 CRI

    作者 | 知谨 阿里云工程师 本文整理自<CNCF x Alibaba 云原生技术公开课>第 28 讲,点击直达课程页面. 关注"阿里巴巴云原生"公众号,回复关键词** ...

  7. Colima:MacOS 上的极简容器运行时和 Kubernetes

    作者 | Addo Zhang 来源 | 云原生指北 Colima 是一个以最小化设置来在MacOS上运行容器运行时和 Kubernetes 的工具.支持 m1,同样也支持 Linux. Colima ...

  8. 课时 30:理解 RuntimeClass 与使用多容器运行时(贾之光)

    本文将主要分享以下三方面的内容: RuntimeClass 需求来源 RuntimeClass 功能介绍 多容器运行时示例 RuntimeClass 需求来源 容器运行时的演进过程 我们首先了解一下容 ...

  9. 关于容器和容器运行时的那些事

    转载本文需注明出处:微信公众号EAWorld,违者必究. 前言: 容器,容器编排,微服务,云原生,这些无疑都是当下软件开发领域里面最热门的术语.容器技术的出现并迅速的广泛应用于软件开发的各个领域里,主 ...

最新文章

  1. mysql在线上建索引,mysql 5.6在线DDL建索引测试
  2. win nvcc warning : The 'compute_20', 'sm_20', and 'sm_21' architectures are depr
  3. Nginx502,504和499错误解决方案
  4. 【最简代码】1076 Wifi密码 (15分)_8行代码AC
  5. outlook反应慢的原因_环氧漆不固化是什么原因?固化剂的使用有关系!
  6. 对应node版本_安装Node.js教程
  7. 量子计算机 真假,复原乳到底有没有营养?量子计算机是否已拍死“前浪”?“科学”流言榜告诉你真假...
  8. 马云卸任阿里巴巴集团董事:传承计划执行完毕,换个江湖见!
  9. bash复杂脚本解释
  10. 嵌入式系统开发笔记100:使用FlyMcu下载程序到STM32单片机
  11. Leetcode力扣 MySQL数据库 1384 按年度列出销售总额
  12. Word 技术篇-文档中不同级别标题自动重新编号设置方法,论文多级编号演示
  13. 图解Navicat连接、操作数据库
  14. SPSS软件做配对t检验
  15. 软考高级 真题 2011年上半年 信息系统项目管理师 案例分析
  16. 深入理解Plasma(四):Plasma Cash
  17. 被互联网租房套路割韭菜的年轻人
  18. 惠普打印机只打印一半_打印机打出来的字只有一半是什么原因
  19. Matlab论文插图绘制模板第50期—分簇散点图(Swarmchart)
  20. pycharm中出现pytest_pytest文档3-pycharm运行pytest

热门文章

  1. shell数组目录遍寻循环输出
  2. Java知识之Git
  3. node.js 安装详细步骤如下(win 版)
  4. python+百度AI 文字转换成语音
  5. ORB-SLAM笔记———ORB-SLAM3概述
  6. MySQL数据库增删改查SQL语句
  7. MFC+Halcon 真正实现图像缩放、平移
  8. 支气管分割并3D展示效果
  9. LED驱动IC TM1616,TM1650,TM1651替代兼容型号(VK,AIP)
  10. JMeter - REST API测试 - 完整的数据驱动方法(翻译)