Dockerless的概念,即不依赖Docker守护进程的容器管理方案。介绍了Containerd及其周边工具(如nerdctl和buildkit)在容器和镜像管理中的应用,旨在简化容器基础设施,减少系统资源开销,并提升性能和灵活性。文章还探讨了OCI标准、Containerd、CRI等技术背景,并对比了Docker、ctr、nerdctl和crictl这些容器管理工具。最后,文章提供了Containerd和crictl的使用指南,展示了如何在不使用Docker的情况下进行容器和镜像管理。

背景介绍

Docker作为广泛应用的容器运行时,用户对其操作和功能极为熟悉。Kubernetes初期通过dockershim与Docker适配,后推出CRI标准以增强对多种容器运行时的兼容性。CRI使Kubernetes系统组件能与各种容器运行时无缝交互,降低了对Docker的依赖,提升了灵活性,用户可选择如Containerd、CRI-O等运行时。自Kubernetes 1.24起,官方移除对Docker的支持,Amazon EKS也选择Containerd为唯一运行时,我们随之切换至Containerd并用nerdctl替换docker命令。

libcontainer、runc、Containerd、CRI、OCI等组件在容器生态系统中扮演关键角色。深入了解这些组件有助于掌握容器技术的运维手段。Docker 1.11起,除Docker Daemon外,还需containerd、runc等组件协作。Docker Daemon保持CS架构,管理镜像和容器。为应对复杂性,Docker项目开源了Containerd,专注于容器基本操作,为管理工具提供统一接口。在现代架构中,Containerd管理容器生命周期,通过gRPC接口支持Docker Daemon。

640 (7).webp

技术背景

OCI 标准 (Open Container Initiative)

OCI标准(Open Container Initiative)

OCI是由Docker、CoreOS(现已被RedHat收购)等重量级组织联手制定的,针对容器格式及其运行时的统一行业标准。

OCI主要涵盖了两大核心规范:

  • 镜像规范(image-spec):该规范详细定义了镜像的主要格式及其内在内容,为容器的镜像标准奠定了坚实基础。
  • 运行时规范(runtime-spec):这一规范则专注于镜像文件运行的管理机制。其中,runC作为目前最为广泛应用的Low-Level容器运行时,凭借其包含的libcontainer技术,实现了对namespace和cgroup等关键功能的调用操作。

接下来,让我们一同探讨市面上最为主流的三大High-Level容器运行时(High-Level容器运行时涵盖了镜像传输、镜像管理、镜像解包以及API等高级功能):

  • Containerd:这一开源项目源自CNCF孵化器,由Docker慷慨捐赠。
  • Podman:该项目由Redhat精心孵化,并在RHEL8中作为核心功能隆重发布,Podman工具以其强大的功能赢得了广泛赞誉。
  • CRI-O:同样作为CNCF孵化器的开源明星项目,CRI-O在容器运行时领域也占据着举足轻重的地位。

进一步深入容器运行关系,我们可以发现:

  • 当Docker以Containerd作为其核心容器运行时,它实际上已经升级为了“High-High-Level”容器运行时,展现了其在容器技术领域的深厚底蕴。

640 (8).webp

在探讨containerd与CRI的关系时,我们不得不关注以下几个关键时间点:

  • Containerd在2016年初正式从Docker中拆分出来,开始了其独立的发展历程。
  • CRI标准则在2016年末应运而生,为容器运行时的标准化提供了有力支撑(值得注意的是,CRI标准的出台时间早于Containerd的拆分)。
  • 直至2017年3月,Containerd在加入CNCF后,才正式添加了CRI支持,进一步丰富了其功能与应用场景。

Containerd

Containerd 项目于2017年3月荣耀加入云原生计算基金会(CNCF),它作为一款简单、强健且具备高度可移植性的行业标准容器运行时,广受业界赞誉。在Linux与Windows系统上,Containerd均以守护进程的身份存在,全面管理容器的生命周期,涵盖镜像的传输、存储、容器的日常管理、底层存储配置以及网络管理(借助CNI等技术)等多方面功能。

640 (9).webp

上图生动展示了Containerd的核心组件及其功能:

  • Runtime:Containerd肩负起容器生命周期管理的重任,从容器的创建、运行到事件处理,每一步都精心把控。
  • Storage:在镜像存储管理方面,Containerd展现出卓越的能力。它精准地负责容器镜像的存储、检索与整体管理,确保镜像数据的安全与高效。
  • gRPC:Containerd通过gRPC服务器与上层应用实现无缝通信,为上层提供了一站式的容器管理服务接口。gRPC作为一种高效的远程过程调用协议,让容器管理操作跨越网络,触手可及。
  • Metrics:Containerd贴心提供了关于容器性能与资源使用的详尽指标,特别是cgroup(控制组)的性能数据,让容器资源的监控与优化更加得心应手。
  • Metadata:容器的元数据,如镜像与容器的详细信息,以及与之紧密相关的各类元数据,均被精心存储在bootfs中。这些元数据为容器的日常管理与操作提供了坚实的支撑。
  • Tasks:在Containerd的精心管理下,容器结构被巧妙地组织为任务(tasks)。这涵盖了容器的运行状态、进程信息及其他关键数据,让容器的管理更加直观与高效。
  • Events:Containerd实时生成事件,及时通知上层应用容器的状态变化。这让上层应用能够轻松订阅这些事件,实时感知容器的状态动态,并据此采取相应的操作措施。

值得一提的是,Containerd项目于2017年3月正式成为云原生计算基金会(CNCF)的一员。而下图则直观地展示了Docker与Containerd之间的对照关系,帮助您更深入地理解两者之间的异同与联系。

640 (10).webp

CRI

Kubernetes 推出了名为 CRI 的容器运行时接口。那么,CRI 究竟是什么呢?这还得从 Docker 的发展说起。

640 (11).webp

在 Kubernetes 早期,Docker 凭借广泛的流行度,成为其首选的容器运行时。Kubernetes 通过硬编码直接调用 Docker API。然而,随着 Docker 的演进和 Google 的推动,更多精简灵活的容器运行时涌现。为了支持这些运行时并减少对 Docker 的依赖,Google 与红帽联合推出了 CRI 标准,旨在将 Kubernetes 与特定容器运行时解耦。

CRI,即容器运行时接口,是 Kubernetes 定义的一组用于与容器运行时交互的接口。任何实现这些接口的容器运行时都能无缝集成到 Kubernetes 中。然而,在 CRI 标准推出时,Kubernetes 尚未占据主导地位,因此一些容器运行时并未直接实现 CRI 接口。为了适配这些运行时,引入了 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 的命令行参数或配置文件进行配置。

由于 Docker 的主导地位,Kubernetes 将 dockershim 内置于 kubelet 中。因此,使用 Docker 作为容器运行时无需额外安装或配置适配器。然而,这种内置支持也让 Docker 公司在一定程度上忽视了后续发展。

在 Kubernetes 中使用 Docker 创建 Pod 的过程如下:kubelet 通过 CRI 接口调用 dockershim 请求创建容器。dockershim 接收请求后,将其转换为 Docker Daemon 可识别的请求,并发送给 Docker Daemon。随后,Docker Daemon 调用 Containerd,再由 Containerd 创建 containerd-shim 进程(注意,后续版本的 Containerd 已移除 containerd-shim),最终通过该进程调用 runc 创建容器。

显然,使用 Docker 的调用链较长,而真正与容器相关的操作,Containerd 已足够胜任。尽管 Docker 因其友好功能而备受欢迎,但其复杂性和笨重性也显而易见,一些功能对 Kubernetes 来说并不必要。因此,切换到 Containerd 作为容器运行时更为高效。

下图展示了插件的发展历程。在 Containerd 1.0 中,CRI 的适配通过独立的 CRI-Containerd 进程完成。这是因为最初的 Containerd 还需适配其他系统(如 Swarm),所以未直接实现 CRI,而是由 CRI-Containerd 承担适配任务。然而,在 Containerd 1.1 版本中,CRI-Containerd 被移除,适配逻辑作为插件直接集成到 Containerd 主进程中,使调用流程更加简洁高效。

640 (12).webp

随着 CRI 方案的成熟和其他容器运行时对 CRI 支持的完善,Kubernetes 社区在 2020 年 7 月启动了移除 dockershim 的计划。在 Kubernetes 1.20 版本中,kubelet 内置的 dockershim 代码被分离并标记为“维护模式”。尽管当时仍可使用 dockershim,但在 1.24 版本中已彻底移除。

同时,社区还提供了 crictl 命令行工具,用于与 CRI 进行交互。

命令行盘点

容器管理工具对比

Docker、ctr、nerdctl 和 crictl 均为强大的容器管理工具,但各自的设计初衷与应用场景却大相径庭。以下是它们的详尽对比:

Docker

简介:Docker 是一款广受欢迎的容器管理工具,它为用户提供了从容器构建、运行至管理的全方位生态系统。
功能:全面支持容器镜像的构建与分发(通过 Docker Hub 集成),以及容器的生命周期管理(如启动、停止、删除等)。
接口:Docker 配备了强大且易于上手的 CLI 和 API 接口,无论是开发人员还是运维人员,都能迅速掌握。

特点

  • 生态系统丰富(例如 Docker Compose)。
  • 支持复杂的容器编排(如 Swarm)。
  • 包含 dockerd 守护进程,需与容器运行时协同工作。

ctr

简介:ctr 是 containerd 的原生 CLI 工具,它允许用户直接与 containerd 进行交互。
功能:ctr 提供镜像拉取、容器运行、容器及镜像存储管理等基础功能,但其设计更为简洁,更适合低级操作与调试。
接口:与 Docker 相比,ctr 更专注于 containerd 用户,未提供 Docker 那样的高级 API 和生态支持。

特点

  • 适用于需直接操作 containerd 的开发者和系统集成商。
  • 不支持镜像构建等高级功能(containerd 专注于容器运行时管理)。

nerdctl

简介:nerdctl 是一个基于 containerd 的命令行工具,它支持 Docker 风格的 CLI 命令。
功能:提供与 Docker 相似的用户体验,支持容器运行、镜像构建、CNI 网络插件和卷等功能。
接口:nerdctl 的 CLI 与 Docker 高度相似,使得从 Docker 迁移至 nerdctl 变得异常简单。

特点

  • 无需 Docker 守护进程,仅依赖 containerd。
  • 与 Kubernetes(使用 containerd 作为运行时)完美集成,支持类似 Docker Compose 的功能。

crictl

简介:crictl 是一个专为 Kubernetes 容器管理设计的命令行工具,它基于容器运行时接口(CRI)。
功能:主要用于与 CRI 兼容的容器运行时(如 containerd 和 CRI-O)进行交互,管理 Pod、镜像和容器。
接口:crictl 的命令集更侧重于 Kubernetes 集群的调试与管理,与 Docker 和 nerdctl 相比,它更专注于 Kubernetes 场景。

特点

  • 与 Kubernetes 高度集成与兼容,常用于调试或管理容器和 Pod 的运行状态。
  • 不支持镜像构建,专注于容器和 Pod 的生命周期管理。

场景对比

以下是针对镜像管理、容器管理和 Pod 管理的场景对比图:

  1. 镜像管理

    640 (12).webp

  2. 容器管理

    640 (13).webp

  3. Pod 管理

    640 (14).webp

总结

  • Docker:用户友好,功能全面,是独立容器管理和开发环境的理想选择。
  • ctr:轻量级且低级,适合直接与 containerd 交互,主要用于调试和底层管理。
  • nerdctl:兼容 Docker CLI,适合希望使用 Docker 命令但希望直接使用 containerd 的用户。
  • crictl:Kubernetes 环境下的调试利器,专注于 CRI 兼容的运行时,不适合一般开发场景。其中,nerdctl 是 containerd 的轻量化替代方案,而 crictl 则是基于 Kubernetes CRI 交互的 Pod 管理工具。

Containerd使用指南

nerdctl 是一个与 Docker CLI 高度兼容的 Containerd 客户端工具,更值得一提的是,它直接支持 Docker Compose 语法,这一特性显著提升了将 Containerd 应用于本地开发、测试或单机容器部署的效率和便捷性。

1. 安装

安装过程简洁明了,只需前往 GitHub Release 页面下载对应系统的压缩包,解压至 PATH 路径下即可。

# 如果没有安装 containerd,则可以下载 nerdctl-full-<VERSION>-linux-amd64.tar.gz 包进行安装
➜ ~ wget https://github.com/containerd/nerdctl/releases/download/v1.7.5/nerdctl-1.7.5-linux-amd64.tar.gz

➜ ~ mkdir -p /usr/local/containerd/bin/ && tar -zxvf nerdctl-1.7.5-linux-amd64.tar.gz nerdctl && mv nerdctl /usr/local/containerd/bin/
➜ ~ ln -s /usr/local/containerd/bin/nerdctl /usr/local/bin/nerdctl
➜ ~ nerdctl version
WARN[0000] unable to determine buildctl version: exec: "buildctl": executable file not found in $PATH
Client:
Version: v1.7.5
OS/Arch: linux/amd64
Git commit: cffed372371dcbea3dc9a646ce5a913fc1c09513
buildctl:
Version:

Server:
containerd:
Version: v2.0.0-beta.2-33-g96bf529cb
GitCommit: 96bf529cbf55940ddb96bb8adc8be51b11922ebb
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d

安装完成后,接下来让我们深入了解一下 nerdctl 命令行工具的使用方法。

2. 命令简介

a. 容器管理

  • run

    docker run 类似,nerdctl run 命令可用于运行容器。例如:

➜ ~ nerdctl run -d -p 80:80 --name=nginx --restart=always nginx:alpine
docker.io/library/nginx:alpine: resolved |++++++++++++++++++++++++++++++++++++++|
index-sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce: done |++++++++++++++++++++++++++++++++++++++| manifest-sha256:ce6ca11a3fa7e0e6b44813901e3289212fc2f327ee8b1366176666e8fb470f24: done |++++++++++++++++++++++++++++++++++++++| config-sha256:7ce0143dee376bfd2937b499a46fb110bda3c629c195b84b1cf6e19be1a9e23b: done |++++++++++++++++++++++++++++++++++++++| elapsed: 5.3 s total: 3.1 Ki (606.0 B/s) 6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eff1806bcf8

可选参数的使用与 docker run 基本一致,如 -i-t--cpus--memory 等选项。使用 nerdctl run --help 可获取所有可用的命令选项。

  • exec

    同样,exec 命令可用于在容器内执行相关命令。例如:

[root@192 containerd]# nerdctl run --help
Run a command in a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.

Usage: nerdctl run [flags] IMAGE [COMMAND] [ARG...]

Flags:
--add-host strings Add a custom host-to-IP mapping (host:ip)
--blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
--cap-add strings Add Linux capabilities
--cap-drop strings Drop Linux capabilities
--cgroup-conf strings Configure cgroup v2 (key=value)
--cgroup-parent string Optional parent cgroup for the container
--cgroupns string Cgroup namespace to use, the default depends on the cgroup version ("host"|"private") (default "private")
--cidfile string Write the container ID to the file
--cosign-certificate-identity string The identity expected in a valid Fulcio certificate for --verify=cosign. Valid values include email address, DNS names, IP addresses, and URIs. Either --cosign-certificate-identity or --cosign-certificate-identity-regexp must be set for keyless flows
--cosign-certificate-identity-regexp string A regular expression alternative to --cosign-certificate-identity for --verify=cosign. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --cosign-certificate-identity or --cosign-certificate-identity-regexp must be set for keyless flows
--cosign-certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate for --verify=cosign, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --cosign-certificate-oidc-issuer or --cosign-certificate-oidc-issuer-regexp must be set for keyless flows
--cosign-certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer for --verify=cosign. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --cosign-certificate-oidc-issuer or --cosign-certificate-oidc-issuer-regexp must be set for keyless flows
--cosign-key string Path to the public key file, KMS, URI or Kubernetes Secret for --verify=cosign
--cpu-period uint Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota (default -1)
--cpu-shares uint CPU shares (relative weight)
--cpus float Number of CPUs
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
-d, --detach Run container in background and print container ID
--detach-keys string Override the default detach keys (default "ctrl-p,ctrl-q")
--device strings Add a host device to the container
--dns strings Set custom DNS servers
--dns-opt strings Set DNS options
--dns-option strings Set DNS options
--dns-search strings Set custom DNS search domains
--entrypoint stringArray Overwrite the default ENTRYPOINT of the image
-e, --env stringArray Set environment variables
--env-file strings Set environment variables from file
--gpus stringArray GPU devices to add to the container ('all' to pass all GPUs)
--group-add strings Add additional groups to join
--help show help
-h, --hostname string Container host name
--init Run an init process inside the container, Default to use tini
--init-binary string The custom binary to use as the init process (default "tini")
-i, --interactive Keep STDIN open even if not attached
--ip string IPv4 address to assign to the container
--ip6 string IPv6 address to assign to the container
--ipc string IPC namespace to use ("host"|"private")
--ipfs-address string multiaddr of IPFS API (default uses $IPFS_PATH env variable if defined or local directory ~/.ipfs)
--isolation string Specify isolation technology for container. On Linux the only valid value is default. Windows options are host, process and hyperv with process isolation as the default (default "default")
--kernel-memory string Kernel memory limit (deprecated)
-l, --label stringArray Set metadata on container
--label-file strings Set metadata on container from file
--log-driver string Logging driver for the container. Default is json-file. It also supports logURI (eg: --log-driver binary://<path>) (default "json-file")
--log-opt stringArray Log driver options
--mac-address string MAC address to assign to the container
-m, --memory string Memory limit
--memory-reservation string Memory soft limit
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) (default -1)
--mount stringArray Attach a filesystem mount to the container
--name string Assign a name to the container
--net strings Connect a container to a network ("bridge"|"host"|"none"|<CNI>) (default [bridge])
--network strings Connect a container to a network ("bridge"|"host"|"none"|"container:<container>"|<CNI>) (default [bridge])
--oom-kill-disable Disable OOM Killer
--oom-score-adj int Tune container’s OOM preferences (-1000 to 1000, rootless: 100 to 1000)
--pid string PID namespace to use
--pidfile string file path to write the task's pid
--pids-limit int Tune container pids limit (set -1 for unlimited) (default -1)
--platform string Set platform (e.g. "amd64", "arm64")
--privileged Give extended privileges to this container
-p, --publish strings Publish a container's port(s) to the host
--pull string Pull image before running ("always"|"missing"|"never") (default "missing")
--rdt-class string Name of the RDT class (or CLOS) to associate the container with
--read-only Mount the container's root filesystem as read only
--restart string Restart policy to apply when a container exits (implemented values: "no"|"always|on-failure:n|unless-stopped") (default "no")
--rm Automatically remove the container when it exits
--rootfs The first argument is not an image but the rootfs to the exploded container
--runtime string Runtime to use for this container, e.g. "crun", or "io.containerd.runsc.v1" (default "io.containerd.runc.v2")
--security-opt stringArray Security options
--shm-size string Size of /dev/shm
--stop-signal string Signal to stop a container (default "SIGTERM")
--stop-timeout int Timeout (in seconds) to stop a container
--sysctl stringArray Sysctl options
--tmpfs stringArray Mount a tmpfs directory
-t, --tty Allocate a pseudo-TTY
--ulimit strings Ulimit options
--umask string Set the umask inside the container. Defaults to 0022
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
--uts string UTS namespace to use
--verify string Verify the image (none|cosign|notation) (default "none")
-v, --volume stringArray Bind mount a volume
--volumes-from stringArray Mount volumes from the specified container(s)
-w, --workdir string Working directory inside the container

See also 'nerdctl --help' for the global flags such as '--namespace', '--snapshotter', and '--cgroup-manager'.
  • ps

    nerdctl ps 命令可列出所有容器。与 Docker 不同的是,nerdctl 提供了基于 namespace 的隔离。如需查看 Kubernetes 的容器,需增加 -n k8s.io 参数。

➜ ~ nerdctl -n k8s.io ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e7f156d31942 docker.io/prom/node-exporter:v1.4.0 "/bin/node_exporter …" 2 days ago Up k8s://node-exporter/node-exporter-5zhjt/main
bf1704937991 hub.cloud.ctripcorp.com/k8s-mirror/pause-amd64:3.1 "/pause" 2 days ago Up k8s://node-exporter/node-exporter-5zhjt

使用 -a 选项可显示所有容器列表,默认仅显示正在运行的容器。但需要注意的是,nerdctl ps 命令暂未实现 docker ps 中的 --filter--format--last--size 等选项。

  • inspect
➜ ~ nerdctl -n k8s.io inspect e7f156d31942
[
{
"Id": "e7f156d31942ffec027b48d50d787e18c59e24ae8134f06ee25dab6c74220d83",
"Created": "2024-11-15T08:37:07.845392486Z",
"Path": "/bin/node_exporter",
"Args": [
...
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"Pid": 22800,
"ExitCode": 0,
"Error": "",
"StartedAt": "",
"FinishedAt": ""
},
"Image": "docker.io/prom/node-exporter:v1.4.0",
...

显示结果与 docker inspect 基本一致。

  • logs

    查看容器日志是日常操作中的常用功能,nerdctl logs 命令可用于获取日志数据。

➜ ~ nerdctl -n k8s.io logs e7f156d31942 |more
ts=2024-11-15T08:37:07.980Z caller=node_exporter.go:182 level=info msg="Starting node_exporter" version="(version=1.4.0, branch=HEAD, revision=7da1321761b3b8dfc9e496e1a60e6a476fec6018)"
ts=2024-11-15T08:37:07.980Z caller=node_exporter.go:183 level=info msg="Build context" build_context="(go=go1.19.1, user=root@83d90983e89c, date=20220926-12:32:56)"
...

同样支持 -f-t-n--since--until 等选项。

  • stop
➜ ~ nerdctl -n k8s.io stop e7f156d31942
FATA[0000] 1 errors:
unable to cleanup network for container: e7f156d31942
  • rm
➜ ~ nerdctl -n k8s.io rm e7f156d31942
FATA[0000] 1 errors:
container e7f156d31942ffec027b48d50d787e18c59e24ae8134f06ee25dab6c74220d83 is in running status. unpause/stop container first or force removal
➜ ~ nerdctl -n k8s.io rm -f e7f156d31942
ERRO[0000] 1 errors:
failed to load container networking options from specs: unexpected end of JSON input

如需强制删除,可使用 -f--force 选项。

b. 镜像管理

  • images
➜ ~ nerdctl -n k8s.io images|grep 4a2c72aa0e18
prom/node-exporter <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
<none> <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
prom/node-exporter v1.4.0 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB

通过 CRI 方式获取的镜像,containerd 会生成三个镜像,分别为 tag、sha256 以及 digest。另外,需要注意的是,docker images 的一些选项在 nerdctl 中暂未实现,如 --filter--format

[root@192 containerd]# nerdctl image --help
Manage images

Usage: nerdctl image [flags]

Commands:
build Build an image from a Dockerfile. Needs buildkitd to be running.
convert convert an image
decrypt decrypt an image
encrypt encrypt image layers
history Show the history of an image
inspect Display detailed information on one or more images.
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image from a registry. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.
push Push an image or a repository to a registry. Optionally specify "ipfs://" or "ipns://" scheme to push image to IPFS.
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

Flags:
-h, --help help for image
  • pull
➜ ~ nerdctl -n k8s.io pull prom/node-exporter:v1.4.0
docker.io/prom/node-exporter:v1.4.0: resolved |++++++++++++++++++++++++++++++++++++++|
index-sha256:4a2c72aa0e18fcedfa86e4a2ca5cf8e33010246e3125449015b586f4fcde7f01: exists |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:2d9dcdf0b2226f0c3d550a64d2667710265462350a3ba9ebe37d0302bc64af0f: exists |++++++++++++++++++++++++++++++++++++++|
config-sha256:d3e443c987ef405e1be101647873d86b5729c9c47bb1dd1ab59ccb24bc9e322c: exists |++++++++++++++++++++++++++++++++++++++|
elapsed: 0.5 s total: 0.0 B (0.0 B/s)
  • push

    在推送镜像之前,可使用 nerdctl login 命令登录到镜像仓库,然后再执行 push 操作。使用 nerdctl logout 可注销退出登录。

  • tag

    tag 命令可用于为镜像创建别名。

➜ ~ nerdctl -n k8s.io images
REPOSITORY TAG IMAGE ID CREATED SIZE
prom/node-exporter <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
<none> <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
prom/node-exporter v1.4.0 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
➜ ~ nerdctl -n k8s.io tag prom/node-exporter:v1.4.0 prom/node-exporter:v1.4.1
➜ ~ nerdctl -n k8s.io images|grep 4a2c72aa0e18
prom/node-exporter v1.4.1 4a2c72aa0e18 4 seconds ago linux/amd64 24.56MB 11.47MB
prom/node-exporter <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
<none> <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
prom/node-exporter v1.4.0 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
  • save

    save 命令可将镜像导出为 tar 压缩包。

➜ ~ nerdctl save -o busybox.tar.gz busybox:latest
➜ ~ ls -lh busybox.tar.gz
-rw-r--r-- 1 root root 761K Aug 19 15:19 busybox.tar.gz
  • rmi
➜ ~ nerdctl -n k8s.io rmi prom/node-exporter:v1.4.1
Untagged: docker.io/prom/node-exporter:v1.4.1@sha256:4a2c72aa0e18fcedfa86e4a2ca5cf8e33010246e3125449015b586f4fcde7f01
Deleted: sha256:084326605ab6715ca698453e530e4d0319d4e402b468894a06affef944b4ef04
Deleted: sha256:5295faa045209ff9800d03fe1ccc94431dac6a54dac2edc7f6d06ee1e58bb0be
Deleted: sha256:bebdf9d4bf7bd2bd40a7e73e5f09a86a87e34578b622328d5a58bf01353f9def
  • load

    load 命令可将导出的镜像再次导入。

➜ ~ nerdctl load -i busybox.tar.gz
unpacking docker.io/library/busybox:latest (sha256:0f354ec1728d9ff32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60)...done

使用 -i--input 选项指定需要导入的压缩包。

  • build

    nerdctl build 依赖于 buildkit 工具。buildkit 是 Docker 公司开源的构建工具包,支持 OCI 标准的镜像构建。它包含服务端 buildkitd(支持 runc 和 containerd 作为 worker,默认是 runc,此处我们使用 containerd)和客户端 buildctl(负责解析 Dockerfile,并向服务端 buildkitd 发出构建请求)。

    构建完成后,可查看镜像是否构建成功。

➜ ~ nerdctl -n k8s.io images
REPOSITORY TAG IMAGE ID CREATED SIZE
prom/node-exporter <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
<none> <none> 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB
prom/node-exporter v1.4.0 4a2c72aa0e18 2 days ago linux/amd64 24.56MB 11.47MB

如此,我们便使用 nerdctl + buildkitd 轻松完成了容器镜像的构建。

c. compose

当然,如果你希望在单机环境下使用 Docker Compose 但想使用 containerd,nerdctl 提供了对 Compose 功能的兼容支持。以下命令可用于管理 Compose 服务:

  • 启动 Compose 服务:nerdctl compose up
  • 查看服务日志:nerdctl compose logs
  • 构建:nerdctl compose build
  • 停止并删除服务:nerdctl compose down

通过结合 Containerd、nerdctl 和 buildkit,你可完全替代 Docker,在镜像构建和容器管理方面享受高效且轻量的容器管理体验。

CRICTL使用指南

crictl 源自 Kubernetes 的容器运行时接口(CRI)。自 Kubernetes 1.5 版本引入 CRI 以来,它便作为 Kubernetes 与多种容器运行时(例如 Docker、containerd、CRI-O 等)之间的标准化桥梁,满足了日益增长的运行时特性和性能需求。同时,CRI 的标准化接口也极大地便利了容器运行时的开发工作。

在此背景下,crictl 应运而生,作为一个命令行工具,它与符合 CRI 标准的容器运行时无缝对接。用户可通过 crictl 轻松管理容器和镜像,查询容器状态与元数据,甚至查看容器日志。这一工具不仅简化了容器运行时的管理和调试流程,还推动了 CRI 标准的广泛应用。

crictl 的核心功能包括:

  • 容器管理:启动、停止、删除及查询容器状态。
  • 镜像管理:拉取、推送、删除及查询镜像。
  • 日志查看:访问容器的标准输出与标准错误日志。
  • 信息查询:获取容器的详细信息,涵盖 ID、名称、状态、IP 等。
  • 元数据操作:管理容器的注解与标签。

作为容器管理的得力助手,crictl 常用于调试与管理容器化应用,并与 Kubernetes 等容器编排系统紧密集成。

安装指南

首先,需从 cri-tools 的 release 页面下载 crictl 的二进制包,解压后将其置于 PATH 路径下,即可完成安装。

➜ ~ VERSION="v1.22.0"
➜ ~ wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
# 如果有限制,也可以替换成下面的 URL 加速下载
# wget https://download.fastgit.org/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
➜ ~ tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
➜ ~ rm -f crictl-$VERSION-linux-amd64.tar.gz
➜ ~ crictl -v
crictl version v1.22.0

命令概览

安装完成后,需修改默认配置文件(/etc/crictl.yaml),指定容器运行时与镜像的 endpoint 地址。

runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
debug: false
pull-image-on-create: false
disable-pull-on-run: false

配置就绪后,即可探索 crictl 的强大功能。

Pod 管理

通过 crictl pods 命令,轻松获取当前节点上的 Pods 列表。使用 --name 参数或标签筛选特定 Pods。

➜ ~ crictl pods
POD ID             CREATED             STATE               NAME                       NAMESPACE           ATTEMPT             RUNTIME
1f617ebf0524c       8 weeks ago         Ready               node-exporter-ggjwf               node-exporter       0                   (default)
4b93e3d6e8d1f       2 months ago       Ready               node-problem-detector-r6ps6       kube-system         0                   (default)
➜ ~ crictl pods --label app=node-exporter
POD ID             CREATED             STATE               NAME                 NAMESPACE           ATTEMPT             RUNTIME
1f617ebf0524c       8 weeks ago         Ready               node-exporter-ggjwf   node-exporter       0                   (default)

镜像管理

crictl images 命令展示所有镜像,添加 -v 参数可查看详细信息。

➜ ~ crictl images
IMAGE                                     TAG                 IMAGE ID           SIZE
hub.cloud.ctripcorp.com/prom/node-exporter                                           v1.4.0                                                                                   d3e443c987ef4       11.5MB
➜ ~ crictl images -v
ID: sha256:d3e443c987ef405e1be101647873d86b5729c9c47bb1dd1ab59ccb24bc9e322c
RepoTags: docker.io/prom/node-exporter:v1.4.0
RepoDigests: docker.io/prom/node-exporter@sha256:4a2c72aa0e18fcedfa86e4a2ca5cf8e33010246e3125449015b586f4fcde7f01
Size: 11474514
Username: nobody
......

容器管理

crictl ps 命令列出正在运行的容器,

➜ ~ crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME               ATTEMPT             POD ID
e7f156d31942f       d3e443c987ef4       2 days ago         Running             main                   2                   bf1704937991a       node-exporter-5zhjt

使用 -s 选项按状态过滤。

➜ ~ crictl ps -s Exited
CONTAINER           IMAGE               CREATED             STATE               NAME                   ATTEMPT             POD ID             POD
22a0adacf702f       d3e443c987ef4       2 days ago         Exited             main                   1                   bf1704937991a       node-exporter-5zhjt

此外,crictl 还支持在容器中执行命令(类似 exec)、

➜ ~ crictl exec -it e7f156d31942f whoami
root

查看日志(支持 -f 实时跟踪与 --tail N 指定行数)

➜ ~ crictl logs e7f156d31942f
ts=2024-11-15T08:37:07.980Z caller=node_exporter.go:182 level=info msg="Starting node_exporter" version="(version=1.4.0, branch=HEAD, revision=7da1321761b3b8dfc9e496e1a60e6a476fec6018)"
ts=2024-11-15T08:37:07.980Z caller=node_exporter.go:183 level=info msg="Build context" build_context="(go=go1.19.1, user=root@83d90983e89c, date=20220926-12:32:56)"
ts=2024-11-15T08:37:07.980Z caller=node_exporter.go:185 level=warn msg="Node Exporter is running as root user. This exporter is designed to run as unprivileged user, root is not required."
...

及监控资源使用情况(crictl stats)。

➜ ~ crictl stats e7f156d31942f

CONTAINER           NAME               CPU %               MEM                 DISK               INODES
e7f156d31942f       main               0.00               37.13MB             0B                 18

更多关于镜像与容器的操作,请参考 kubernetes-sigs/cri-tools。

由于笔者时间、视野、认知有限,本文难免出现错误、疏漏等问题,期待各位读者朋友、业界专家指正交流。

参考文献

  1. https://ziglang.org/documentation/master/.
  2. https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/
  3. https://zhuanlan.zhihu.com/p/666200234
  4. https://www.qikqiak.com/k8strain2/containerd/runtime/
  5. https://github.com/kubernetes/cri-api/tree/master/pkg/apis
    6.http://www.opennaru.com/kubernetes/containerd/
  6. https://www.slideshare.net/AkihiroSuda/container-plumbing-days-2023-why-was-nerdctl-made
  7. https://www.alibabacloud.com/blog/a-discussion-on-container-runtime---starting-with-dockershim-being-deleted-by-kubernetes_600118

标签: 云原生, Docker, 容器, Kubernetes

添加新评论