容器引擎 Containerd&&Docker -- (Kubernetes 1.24 开始,删除了对 Docker(Dockershim)的容器运行时接口(CRI)的支持)

Containerd已成Kubernetes“新宠”

Docker 曾经是最早广泛使用的容器运行时,这也使用户对 Docker 非常熟悉。Kubernetes 最初支持 Docker 是通过在项目中内置了一个组件称为 "dockershim" 来实现的。随着容器生态系统的发展,Kubernetes 逐渐增加了对其他容器运行时的支持,以提供更多选择和灵活性。

Kubernetes 引入容器运行时接口(Container Runtime Interface,CRI),使 Kubernetes 的系统组件能够与不同容器运行时进行通信。这一变化使 Kubernetes 更加灵活,能够支持多个容器运行时,而不仅限于 Docker。随着对 Docker 和 dockershim 的依赖逐渐减弱, Kubernetes 的用户现在可以选择其他容器运行时,如Containerd、 CRI-O 等。减少了对 Docker 的硬编码依赖,降低了 Kubernetes 项目的复杂性,提升 Kubernetes 服务的运行速度。

从 Kubernetes 1.24 开始,删除了对 Docker(Dockershim)的容器运行时接口(CRI)的支持。同时Amazon EKS 官方也将 Containerd 作为唯一的运行时。

那么 Containerd 是什么,怎么用?接下来我们将一一揭晓

Containerd 诞生

概述

Containerd 是一个用于管理容器的开源项目,它起源于 Docker 项目,是 Docker 引擎的一部分。下面是 Containerd 的前世今生[1]。

- Containerd 的前世

Docker 最初是一个独立的开源项目,旨在提供容器化应用程序的解决方案。Docker 引擎是 Docker 项目的核心组件,负责容器的创建、运行和管理。然而,随着时间的推移,Docker 项目不断壮大,引入了许多新功能和组件,变得越来越复杂。这导致了 Docker 引擎的模块化需求,以便更容易维护和扩展。

- Containerd 的诞生

应对 Docker 引擎的复杂性问题,Docker 项目决定将引擎中的一部分核心功能抽象出来并开源,这就是 Containerd 项目的诞生。Containerd 专注于容器的基本操作,如镜像管理、容器运行时和容器生命周期管理等,它提供了一个统一的接口,供容器管理工具使用。

- Docker 和 Containerd 的关系

Docker 引擎与 Containerd 之间的关系可以被视为 “上游” 和 “下游” 的关系。Docker 引擎构建在 Containerd 之上,它使用 Containerd 来管理容器的基本功能。因此,Containerd 可以被认为是 Docker 引擎的核心部分之一。如下图所示:

- CNCF 和 OCI 的支持

Containerd 项目在 2017 年 3 月加入了云原生计算基金会(CNCF)[2],这是一个开源项目的管理组织,旨在促进云原生技术的发展。此外,Containerd 也符合开放容器倡议(Open Container Initiative,OCI)的规范,这是一个定义容器标准的组织。

Containerd 与 Docker 差异

Containerd 架构

逻辑架构

Containerd 是一种注重简单性、健壮性和可移植性的行业标准容器运行时。它可作为 Linux 和 Windows 的守护进程,可以管理其主机系统的完整容器生命周期,包括镜像传输和存储、容器执行和监督、底层存储和网络附加等功能[3]。

上图展示了 Containerd 的主要组件:

1. Runtime:Containerd 负责容器的生命周期管理,包括容器的创建、运行和事件管理等。

2. Storage:Containerd 提供镜像存储管理。它负责容器镜像的存储、检索和管理。

3. gRPC:Containerd 使用 gRPC 服务器来与上层应用程序通信,为上层提供容器管理服务的接口。gRPC 是一种远程过程调用协议,使容器管理操作可以通过网络进行。

4. Metrics:Containerd 提供了有关容器性能和资源使用的指标,主要涉及 cgroup(控制组)的性能指标。

5. Metadata:容器的元数据,如镜像和容器的信息,以及与其相关的元数据,存储在 bootfs 中。这些元数据用于容器的管理和操作。

6. Tasks:在 Containerd 中,容器结构被管理为任务(tasks)。这包括容器的运行状态、进程信息和其他相关数据。

7. Events:Containerd 生成事件以通知上层应用程序容器的状态变化。这使上层应用程序能够订阅这些事件,以获知容器的状态变化,以及采取相应的操作。

架构应用

Containerd 旨在嵌入到更大的系统中,而不是直接由开发人员或最终用户使用,在 kubernetes 中应用最为广泛。下图由 Containerd 官方提供,从图中可以看出,Containerd 为 C/S 架构,通过 gRPC 暴漏接口供不同的客户端进行集成调用。

Containerd 使用

安装

通过源安装

containerd.io 包在 DEB 和 RPM 格式中的分发由 Docker 而不是 Containerd 项目本

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install containerd.io 

也可通过二进制安装[4]。

# containerd.io 中包含的组件
# 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.19
/usr/share/doc/containerd.io-1.6.19/README.md
/usr/share/licenses/containerd.io-1.6.19
/usr/share/licenses/containerd.io-1.6.19/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

客户端工具

ctr是 Containerd 的官方命令行客户端工具。它提供了用于容器和镜像操作的命令行接口。您可以使用 ctr来创建、管理和监视容器,以及处理容器镜像。

# ctr
NAME:
   ctr -
        __
  _____/ /______
 / ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/

Containerd CLI


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

VERSION:
   1.6.19

DESCRIPTION:

ctr is an unsupported debug and administrative client for interacting
with the Containerd daemon. Because it is unsupported, the commands,
options, and operations are not guaranteed to be backward compatible or
stable from release to release of the Containerd project.

COMMANDS:
   plugins, plugin            provides information about Containerd plugins
   version                    print the client and server versions
   containers, c, container   manage containers
   content                    manage content
   events, event              display Containerd events
   images, image, i           manage images
   leases                     manage leases
   namespaces, namespace, ns  manage namespaces
   pprof                      provide golang pprof outputs for Containerd
   run                        run a container
   snapshots, snapshot        manage snapshots
   tasks, t, task             manage tasks
   install                    install a new package
   oci                        OCI tools
   shim                       interact with a shim directly
   help, h                    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug                      enable debug output in logs
   --address value, -a value    address for Containerd's 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]
   --help, -h                   show help
   --version, -v                print the version

命名空间

Containerd 提供完全隔离的 API,使多用户能够同时使用单个 containerd 实例而不会相互冲突。

命名空间允许在单个守护进程中实现多租户功能。用户可以拥有具有相同名称但具有不同功能或配置的容器。例如,系统或基础架构级容器可以隐藏在一个命名空间中,而用户级容器可以保留在另一个命名空间中。底层镜像内容仍然是通过内存地址共享的,但是image名称和metadata在每个命名空间中是单独的。

需要注意 Containerd 实现的命名空间是一种管理形式,不具有安全功能。客户端可以轻松切换命名空间,不能提供安全隔离。

- 查看命名空间

# ctr ns ls
NAME    LABELS
default
moby

- 创建命名空间

# ctr ns create test
# ctr ns ls
NAME    LABELS
default
moby
test

- 删除命名空间

# ctr ns rm test
test

镜像操作

- 下载镜像

# ctr image pull public.ecr.aws/nginx/nginx:1.25
public.ecr.aws/nginx/nginx:1.25:                                                  resolved       |++++++++++++++++++++++++++++++++++++++|
index-sha256:56fae3726ce208394da92a3ac447caacfccd59d8325f700b8542e6faf614cc4a:    done           |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:d2e65182b5fd330470eca9b8e23e8a1a0d87cc9b820eb1fb3f034bf8248d37ee: done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:c1dfc7e1671e8340003503af03d067bae6846c12c30cbc1af3e589cb124fd45d:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:c20060033e06f882b0fbe2db7d974d72e0887a3be5e554efdb0dcf8d53512647:   done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:578acb154839e9d0034432e8f53756d6f53ba62cf8c7ea5218a2476bf5b58fc9:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:e398db710407fbc310b4bc0b0db1c94161480ac9b44638c6655939f426529780:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:85c41ebe6d660b75d8e2e985314ebce75e602330cd325bc5cfbf9d9723c329a1:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:7170a263b582e6a7b5f650b7f1c146267f694961f837ffefc2505bb9148dd4b0:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:8f28d06e2e2ec58753e1acf21d96619aafeab87e63e06fb0590f56091db38014:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:6f837de2f88742f4e8083bff54bd1c64c1df04e6679c343d1a1c9a650078fd48:    done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 12.7s                                                                    total:  67.3 M (5.3 MiB/s)                                      
unpacking linux/amd64 sha256:56fae3726ce208394da92a3ac447caacfccd59d8325f700b8542e6faf614cc4a...
done: 1.889424578s

- 查看镜像

# ctr images ls
REF                             TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                  LABELS
public.ecr.aws/nginx/nginx:1.25 application/vnd.docker.distribution.manifest.list.v2+json sha256:56fae3726ce208394da92a3ac447caacfccd59d8325f700b8542e6faf614cc4a 67.3 MiB linux/amd64,linux/arm64/v8 -

- 删除镜像

# ctr  images  delete public.ecr.aws/nginx/nginx:1.25
public.ecr.aws/nginx/nginx:1.25

- 将镜像挂载到主机目录

将容器镜像挂载到指定的目标路径。这个命令允许你在主机上查看容器镜像的文件系统,以便浏览、检查或修改容器中的文件。

# ctr  image  mount public.ecr.aws/nginx/nginx:1.25 /mnt/
sha256:32cf0b3c70998330104acfc1a02f6aae2f8a728bc6ad91c2415fda501593fa81
/mnt/

# cd /mnt
# ls
bin   dev                  docker-entrypoint.sh  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   lib64  media   opt  root  sbin  sys  usr

容器操作

- 创建容器

# ctr  c  create public.ecr.aws/nginx/nginx:1.25 nginx
# ctr  c  ls
CONTAINER    IMAGE                              RUNTIME
nginx        public.ecr.aws/nginx/nginx:1.25    io.Containerd.runc.v2

- 查看容器详情

# ctr c info nginx 

- 删除容器

# ctr c del nginx

任务操作

在 Containerd 中,容器对象可以看作是一个配置和资源的抽象,它包含容器的各种设置、rootfs(容器的文件系统)等。容器对象本身并不运行,只是一个配置状态。要实际运行容器,需要通过创建和启动任务(Task)来执行容器内的进程。

任务(Task)是 Containerd 中的实体,它代表容器内的运行时环境。一个容器可以包含一个或多个任务,每个任务对应容器内的一个进程或进程组。任务用于管理容器内的进程,包括创建、启动、停止和监控。

想要启动容器,需要使用 ctr task 命令创建一个任务,并将其关联到容器对象。任务会负责启动容器内的主要进程,例如应用程序。此过程确保容器的进程以正确的方式在容器内执行。

- 启动任务

# ctr c ls
CONTAINER    IMAGE                              RUNTIME
nginx        public.ecr.aws/nginx/nginx:1.25    io.containerd.runc.v2
# ctr task start -d  nginx
# ctr task ls
TASK     PID      STATUS
nginx    67132    RUNNING

- 进入容器

# ctr t exec -t --exec-id 0 nginx bash
# ls
bin   dev                  docker-entrypoint.sh  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   lib64  media   opt  root  sbin  sys  usr

- 停止任务

# ctr t ls
TASK     PID      STATUS
nginx    67132    RUNNING

# ctr t kill nginx
# ctr t ls
TASK     PID      STATUS
nginx    67132    STOPPED

- 删除任务

# ctr t rm nginx

通过编写podlspodenter命令, 简化操作

从Kubernetes 1.24开始,用户均须使用Containerd作为容器运行时。然而,由于Containerd与Docker在使用方式上有所差异,用户在排查Kubernetes Node上将会遇到很大的挑战。针对这个问题,聚云科技针对性给出简化排查方案,通过编写podlspodenter命令,用户可以使用 Containerd 自带ctr来快速列出容器和进入容器。这些自定义命令的输出与Docker的样式相似,使得用户可以更加快速地上手使用,找到需要的容器,从而大大简化了故障排除过程。

- 列出主机上容器

  • 命令执行详情
# podls 
TaskID                                                            Namespace                  PodName                                      ContainerName
884be98a85717f58eb348af1510dc0e83077f37bcc63a7f82980047c4d3a4b12  kubecost                   kubecost-network-costs-9ghdj                 kubecost-network-costs
0a92e5b7d9de06283d5de4fb96431b966dc3f23ec2604fdbf7ca9f37c015e29c  monitoring                 alertmanager-main-2                          config-reloader
a44029681a617d6721fdacf483e509bbf7bf0da0a006e4d768bc74338bfcc287  monitoring                 alertmanager-main-2                          alertmanager
4c8be9a3c3fa828e1d1287e7f54e56e75a1f8abceaba0d5b44c0b7b8ce45adfb  monitoring                 node-exporter-5hsr6                          kube-rbac-proxy
734b3cdec3990f5b4176c27cf6b147f049546b750253cc813ddcda3977853347  monitoring                 node-exporter-5hsr6                          node-exporter
e0971f27d8701a2099cdb22590b067f85b711f6b4e96acf7b9ee24624be77776  monitoring                 process-exporter-kxdxn                       process-exporter
4d6570e7cc7ede80eaf2ec7b23ea500def34b967b08a64653b2510328f37d448  monitoring                 prometheus-k8s-0                             config-reloader
8249f57e1938f284b65259d44cb93c82e31542f98b1138b5e3bb086487221690  monitoring                 prometheus-k8s-0                             prometheus
  • 命令源码
#!/bin/bash
# podls 列出主机上容器
# 屏蔽系统命名空间 kube-system
containerHeader=$(echo -e "TaskID\tNamespace\tPodName\tContainerName" )
# 获取 task 列表
taskInfo=$(ctr -n k8s.io task ls -q |tr "\n" "|" | sed 's#|$##g')
# 获取容器列表
taskData=$(
for i in `ctr -n k8s.io c ls -q`; do
    ctr  -n k8s.io c info $i |\
    jq '.ID,  .Labels."io.kubernetes.pod.namespace", .Labels."io.kubernetes.pod.name", .Labels."io.kubernetes.container.name" ' |\
    tr -d \" | \
    tr "\n" "\t";
    echo ;
done | \
    sort -t$'\t' -k2,2 -k3,3 |\
    grep -Ev "kube-system|null" | \
    grep -E  "${taskInfo}"
)
# 格式化输出
echo -e "${containerHeader}\n${taskData}" | column -t

- 进入容器

  • 命令执行详情
# 进入到某个容器中
# podenter 8249f57e1938f284b65259d44cb93c82e31542f98b1138b5e3bb086487221690 sh
/prometheus $ ps -ef
PID   USER     TIME  COMMAND
    1 1000      5d07 /bin/prometheus --web.console.templates=/etc/prometheus/consoles 
   23 1000      0:00 sh
   29 1000      0:00 ps -ef
  • 命令源码
#!/bin/bash
# podenter 登录 pod
# 需要先通过 podls 获取到 pod 列表
podid=$1
podcmd=$2
function display_help() {
cat << "EOF"
Usage:
    podenter TaskID CMD
EOF
}

if [ $# -ne 2 ]; then
    display_help
    exit 1
else
    ctr  -n k8s.io task  exec  -t  --exec-id 1  ${podid} ${podcmd}
fi

总结

作为一个开源的容器运行时项目,Containerd的发展和应用对于容器化技术的生态系统具有重要意义。虽然Containerd在多个方面具有明显的优势,但也存在一些限制,特别是在高级容器功能方面需要额外的注意。Containerd的定位是为容器生态系统提供一个通用的、标准化的容器运行时,以支持容器化应用程序的生命周期管理,而不是为最终用户提供一个完整的容器解决方案。

 
posted @ 2024-07-11 15:15  david_cloud  阅读(0)  评论(0编辑  收藏  举报