Containerd 深度解析与企业级落地

引言

🚀 随着云原生时代的到来,容器化技术已成为企业级应用部署与解耦的重要利器。在众多容器技术栈中,Containerd 作为一个轻量、稳定且高性能的容器运行时,正被 Kubernetes、云平台以及各大互联网公司所青睐。
📦 本文将从容器运行时的演进与需求出发,深度剖析 Containerd 的核心架构与关键模块,分享在企业级场景下的实战部署经验,并结合实际性能对比与调优思路,帮助中高级技术人员快速掌握 Containerd 在生产环境中的落地要点。

目标读者

  • Kubernetes 用户、容器平台搭建者
  • 企业 DevOps 工程师、架构师、云平台研发人员
  • 关注云原生与容器运行时机制的中高级技术研究员
  • 已具备一定工程实践背景的技术使用者(非小白)

背景与发展

Containerd 的前世今生

“在 Docker Engine 中,Containerd 曾经是 Docker 1.11 及之前版本的容器核心;如今,它已经独立成为 CNCF(Cloud Native Computing Foundation)下的顶级开源项目,为上层编排系统提供了更专注、更稳定的容器运行时基础设施。”

  1. 起源与演进

    • 2013 年:Docker 公司推出 Docker 引擎,其中包含了名为 libcontainer 的容器管理核心。
    • 2015 年libcontainer 捐献给 Open Container Initiative (OCI),并更名为 runc,作为标准化的 OCI 运行时。
    • 2016 年 3 月:Docker 1.11 发布,将 containerd 从 Docker Engine 中剥离,并将其作为独立守护进程(daemon),提供 gRPC 接口供上层系统调用。
    • 2017 年:Docker 官方将 Containerd 正式捐赠给 CNCF,成为独立的顶级项目,专注于容器生命周期管理、镜像拉取与存储、网络与存储插件等功能。
    • 2020 年:Kubernetes 1.20 宣布逐步移除对 Docker Shim 的支持,而推荐使用 containerd/runc 组合作为容器运行时。
  2. 社区与生态

    • CNCF 顶级项目:与 Kubernetes、Prometheus、Envoy 并列,拥有庞大的社区支持与活跃的版本迭代。
    • 厂商支持:Google、RedHat、IBM、阿里、华为等多家企业参与开发与贡献,保证了 Containerd 在云原生领域的主流地位。
    • 生态兼容:支持所有符合 OCI 标准的镜像与运行时,上层系统(如 Kubernetes、Mesos、Swarm 等)通过 CRI(Container Runtime Interface)或 gRPC 接口与 containerd 对接。

与 Docker、Kubernetes 的关系

  • Docker vs Containerd

    • Docker Engine 是一个完整的 PaaS 平台,集成了镜像构建、仓库管理、镜像分发、容器编排(Swarm)等功能,而 Containerd 仅聚焦于“容器运行时管理”。
    • 将 Containerd 从 Docker Engine 中独立出来,既保证了 Docker 引擎的上层用户体验,也让 Containerd 有了更专注的发展空间。
  • Kubernetes vs Containerd

    • 早期 Kubernetes 通过 “Docker Shim” 将 CRI 请求翻译为 Docker 的 API,进而借助 Docker Daemon 来管理容器。随着社区标准化需求日益增长,Docker Shim 的维护成本加大。
    • Containerd 原生支持 CRI,通过 cri-containerd 插件直接与 Kubelet 通信,实现镜像拉取、容器创建、日志收集等功能。2020 年后,Kubernetes 官方推荐将 Containerd 与 runc 作为主要运行时。

🎯 小结:Containerd 从 Docker Engine 中脱胎而出,继承了 Docker 对容器生命周期管理的设计思想,同时将重心放在“轻量化、稳定性、高性能”上,为云原生生态提供了理想的底层运行引擎。


架构设计

整体架构概览

Containerd 采用 C/S 架构,上层系统(如 Kubernetes、Docker Engine)通过 gRPC 接口调用 containerd 以实现对容器的管理。

  • Server(守护进程):以 containerd 进程形式运行,负责接收上层请求、管理镜像、存储、网络、容器生命周期等。
  • Client(CLI / SDK):通过 ctrcrictl、Docker Engine 等客户端进行交互,调用 gRPC 接口执行操作。
Containerd 服务端
上层系统
gRPC CRI
gRPC API
gRPC API
containerd Daemon
Content Plugin
Snapshot Plugin
Metadata Plugin
Runtime Plugin
CRI Plugin
Metrics Plugin
GC Plugin
Kubernetes Kubelet
Docker Engine
Mesos/Swarm 等
  • 🍃 Containerd 将不同职责划分为多个模块(插件),各插件之间通过核心框架协调运作。
  • 🌟 插件以 “插件名称 + 版本号” 的形式注册到 Containerd 中,启动时自动加载并初始化。

插件化设计与模块划分

Containerd 主要分为以下三大子系统(层):

  1. Storage(存储层)

    • Content Plugin:管理镜像层二进制内容(如 tarball、OCI Layer)。
    • Snapshot Plugin:对镜像层进行解压、挂载、卸载操作,将镜像与容器文件系统进行绑定。
  2. Metadata(元数据层)

    • Metadata Plugin:基于 BoltDB 存储容器、镜像、快照、租约(Lease)、命名空间(Namespace)等元数据信息。
    • Garbage Collection (GC) Plugin:定期清理无用的快照、内容、租约,维护存储空间。
  3. Runtime(运行时层)

    • Runtime Plugin(v1/v2):负责调用 runc 或其他符合 OCI 规范的 runtime(如 kata-runtimegvisor)创建、启动、停止容器进程。
    • Service Plugin(tasks-service、containers-service、events-service 等):暴露 gRPC 服务供上层调用,实现容器创建、启动、监控等功能。
    • CRI Plugin:实现 Kubernetes CRI(Container Runtime Interface)规范,桥接 Kubelet 与 Containerd。
    • Metrics Plugin:暴露 Prometheus 格式的监控指标,用于上层集群监控系统。
Runtime 运行时层
Metadata 元数据层
Storage 存储层
Runtime Plugin v1
Runtime Plugin v2
CRI Plugin
Metrics Plugin
Tasks-Service
Containers-Service
Events-Service
Metadata Plugin
GC Plugin
Content Plugin
Snapshot Plugin

关键插件与组件

插件名称作用
Content Plugin存储与管理镜像层的二进制内容,如 OCI Layer,支持拉取、导入、导出。
Snapshot Plugin对镜像层进行解压、挂载、复制快照。支持多种存储后端(overlayfs、btrfs、zfs)。
Metadata Plugin使用 BoltDB 存储容器、镜像、快照等元数据信息。
Garbage Collection (GC) Plugin定期清理不再使用的镜像层、快照、租约,释放磁盘空间。
Runtime Plugin (v1/v2)负责调用 runc(或其他 OCI Runtime)创建、启动、停止容器。
CRI Plugin实现 Kubernetes CRI 接口,将 Kubelet 请求翻译为 Containerd 操作。
Tasks-Service、Containers-Service、Events-Service提供容器与任务的管理、查询、事件上报等服务。
Metrics Plugin暴露 Prometheus 风格的监控指标,如镜像拉取速率、容器启动耗时等。
Diff-Service处理增量文件系统差异(walking)。

关键模块深度解析

Content Plugin:镜像内容管理

  1. 功能定位

    • 管理镜像中所有不可变的二进制内容,如镜像层(layer)、配置(config)、清单(manifest)等。
    • 支持多种操作:Pull(拉取)、Push(推送)、Import(导入)、Export(导出)等。
  2. 核心概念:Content Store

    • Containerd 维护一个 Content Store,负责存储镜像各个层的数据。每份内容通过 Digest(sha256) 进行唯一标识,保证内容可寻址与一致性。
    • 物理存储路径默认在 /var/lib/containerd/io.containerd.content.v1.content 下,以子目录分片存放。
  3. 工作流程

    • ctr images pull:首先获取镜像清单(manifest),遍历所需的 layer Digest,依次下载到本地 Content Store;下载完毕后校验完整性,将 Digest 及尺寸信息写入元数据(Metadata Store)。
    • ctr images push:根据本地 Content Store 中已有的层,打包上传到远端 Registry。
    • 导入/导出:利用 ctr images import/export 命令,将镜像保存为 tar 归档文件,支持跨集群迁移。
  4. 示例:拉取镜像

    # 拉取 nginx:alpine(支持多平台)
    sudo ctr images pull --all-platforms docker.io/library/nginx:alpine
    
    # 指定平台拉取(仅 linux/amd64)
    sudo ctr images pull --platform linux/amd64 docker.io/library/nginx:alpine
    
    # 查看 Content Store 路径
    ls /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
    
  5. 内容校验与租约(Lease)

    • Containerd 引入 租约(Lease) 概念,用于在特定时间段内保护内容不被 GC 删除,例如在备份或导出过程中。
    • 通过 ctr lease 命令管理租约,保证内容在使用期间不会被回收。

Snapshot Plugin:文件系统快照与存储

  1. Snapshotter 概述

    • Snapshotter 负责将镜像层(layer)解压到本地文件系统,并在容器启动时将各层合并为一个联合文件系统,实现对容器 RootFS 的管理。

    • 支持多种后端 Snapshotter

      • overlayfs(默认,最常见,适用于大多数 Linux 发行版)
      • btrfs(支持写时复制,需要底层文件系统支持 btrfs)
      • zfs(写时复制,需要底层文件系统支持 zfs)
      • devmapperthindaufs 等(根据平台与场景选择)
  2. Union Mount(联合挂载)

    • 采用 联合挂载 技术,将多个只读层(immutable layer)和一个读写层(rw layer)合并到一起,为容器提供一个完整的根文件系统。
    • 读写分离:上层读写层位于 /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs(以 overlayfs 为例),只记录容器运行时的变更。
  3. Snapshot 生命期管理

    • Image Snapshot:当拉取镜像后,会将各个 layer 解压为只读快照(readonly snapshot),这些快照共享于多个容器。
    • Container Snapshot:在基于镜像创建容器时,会为该容器创建一个新的读写快照(rw snapshot),并将只读层以联合挂载形式置于上层。
    • 删除与 GC:容器停止并删除后,对应的读写层快照被删除,关联的只有当没有任何容器依赖时,只读层才会被 GC 清理。
  4. 示例:overlayfs Snapshot 操作

    # 列出所有 snapshot
    sudo ctr snapshots ls
    # 输出类似:
    # NAME                              KIND                PARENT
    # sha256:aeae...                    active              sha256:bbbb...
    # sha256:bbbe...                    view                sha256:cccc...
    # ...
    
    # 手动创建一个镜像快照(view)
    sudo ctr snapshots view sha256:aeae... /mnt/nginx-layer
    
    # 删除快照
    sudo ctr snapshots rm sha256:aeae...
    
  5. 存储优化与调优

    • 选择合适的 Snapshotter:大多数场景推荐使用 overlayfs,兼容性强、性能佳;对写时复制要求高、希望隔离的场景可考虑 btrfszfs
    • 底层文件系统参数调优:如 overlayfs 中可以通过 mount 选项设置 metacopy=onxor 等参数以提升性能。
    • 多级缓存:对于高并发场景,可结合分布式存储或缓存代理减少单机 I/O 压力。

Metadata Plugin:元数据存储与检索

  1. Metadata Store 概述

    • 使用 BoltDB(嵌入式 KV 数据库)存储所有元数据信息,包括:

      • 镜像清单(Manifest)与层(Layer)信息
      • 容器对象(Container)与任务(Task)信息
      • Snapshot(快照)与 Lease(租约)
      • Namespace(命名空间)概念
  2. Namespace 用法

    • Containerd 支持多命名空间(Namespace)隔离,不同 Namespace 之间的镜像、容器、快照等资源相互独立。

    • 通过 --namespace 参数或环境变量 $CONTAINERD_NAMESPACE 指定操作数据所归属的命名空间。

    • 示例:

      # 切换命名空间为 dev
      export CONTAINERD_NAMESPACE=dev
      # 拉取镜像到 dev 命名空间
      sudo ctr images pull docker.io/library/nginx:latest
      # 在 default 命名空间下看不到该镜像
      sudo ctr -n default images ls
      
  3. Metadata Schema 演进

    • Containerd v1.x 使用 BoltDB v1 版本,存储在 /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
    • v1.5+ 开始支持分离 Metadata 存储路径,配置文件中可通过 plugins."io.containerd.metadata.v1.bolt".directory = "/data/containerd/metadata" 自定义。
  4. 事务与并发

    • Containerd 的 Metadata 插件实现了读写分离与 MVCC(多版本并发控制),保证高并发场景下操作的可见性与一致性。
    • 所有元数据操作(如创建镜像记录、写入快照信息)均在事务(Transaction)中执行,保证回滚与原子性。

Runtime Plugin:容器运行时

  1. Runtime Plugin v2(io.containerd.runtime.v2)

    • Containerd v1.1+ 引入 Runtime v2 插件,采用新的任务(Task)模型,直接调用 runc 的 JSON Spec,性能与稳定性更优。
    • 核心二进制:containerd-shim-runc-v2,作为 shim 进程负责将容器进程置于独立命名空间内。
  2. Runtime Plugin v1(io.containerd.runtime.v1)

    • 兼容早期版本的 Runtime API,使用 containerd-shimrunc 结合,适用于老系统。
    • v1 与 v2 在命令行与 gRPC 接口上有部分差异,建议新项目优先选用 v2。
  3. Shim 机制

    • Shim 进程用于隔离 Containerd 守护进程与容器进程,保证容器进程不会因为 Containerd 重启而被回收。

    • 当执行 ctr runctr task start 时:

      • Containerd Daemon 通过 gRPC 调用 Runtime Plugin,创建 shim 进程(如 containerd-shim-runc-v2)。
      • Shim 进程再调用 runc 启动容器进程。
      • 容器进程的 StdIO(stdin/stdout/stderr)通过 FIFO 与 Client 进行通信,由 shim 进行转发。
  4. Runtime Config(OCI Spec)

    • Containerd 支持自定义 OCI 运行时配置,如 CPU、内存、挂载、Seccomp、AppArmor 等。

    • 可以通过 --config 参数指定自定义 JSON 文件:

      # 示例:自定义运行时 Spec
      cat <<EOF > myruntime.json
      {
        "ociVersion": "1.0.2",
        "process": {
          "terminal": true,
          "user": {
            "uid": 1000,
            "gid": 1000
          },
          "args": ["sh"],
          "env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"],
          "cwd": "/"
        },
        "root": {
          "path": "rootfs"
        },
        "hostname": "containerd-test",
        "mounts": [
          {
            "destination": "/proc",
            "type": "proc",
            "source": "proc"
          },
          {
            "destination": "/dev",
            "type": "tmpfs",
            "source": "tmpfs",
            "options": ["nosuid", "strictatime", "mode=755", "size=65536k"]
          }
        ]
      }
      EOF
      
      # 运行容器时指定
      sudo ctr run --runtime io.containerd.runc.v2 --config myruntime.json myimage:latest mycontainer
      
  5. 多 Runtime 支持

    • Containerd 支持为不同镜像或容器指定不同的 Runtime,例如 runckata-runtimegvisor 等。

    • 在配置文件(/etc/containerd/config.toml)中,定义多个 runtime:

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]
        runtime_type = "io.containerd.kata.v2"
        runtime_engine = "/usr/bin/kata-runtime"
        runtime_root = "/run/kata"
      

CRI Plugin:与 Kubernetes 的对接

  1. Container Runtime Interface(CRI)概览

    • CRI 是 Kubernetes 提供的一套标准接口,用于与容器运行时(Container Runtime)通信。
    • 通过 CRI,Kubelet 可以执行镜像拉取、容器创建、启动、停止、删除、日志获取等操作。
  2. cri-containerd 插件

    • Containerd 官方提供了 cri 插件(plugins."io.containerd.grpc.v1.cri"),完全实现了 CRI v1.0 规范。
    • config.toml 中启用 cri 插件后,Containerd 会启动一个 CRI gRPC 服务,监听 unix:///run/containerd/containerd.sock,供 Kubelet 调用。
  3. 关键配置示例

    [plugins."io.containerd.grpc.v1.cri"]
      sandbox_image = "k8s.gcr.io/pause:3.6"
      systemd_cgroup = false
      stream_idle_timeout = "4h"
      max_container_log_line_size = 16384
    
      [plugins."io.containerd.grpc.v1.cri".containerd]
        snapshotter = "overlayfs"
        default_runtime_name = "runc"
    
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
          runtime_type = "io.containerd.runc.v2"
          runtime_engine = ""
          runtime_root = ""
          privileged_without_host_devices = false
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
            SystemdCgroup = true
    
      [plugins."io.containerd.grpc.v1.cri".cni]
        bin_dir = "/opt/cni/bin"
        conf_dir = "/etc/cni/net.d"
    
      [plugins."io.containerd.grpc.v1.cri".registry]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
          endpoint = ["https://registry.aliyuncs.com"]
    
  4. CRI 对接流程

    1. Kubelet 启动时,通过 --container-runtime=remote--container-runtime-endpoint=unix:///run/containerd/containerd.sock 指定 CRI Socket。
    2. Kubelet 调用 CRI.PullImage,Containerd 从指定 Registry 拉取镜像,并存储到 Content Store。
    3. Kubelet 调用 CRI.CreateContainer,Containerd 根据 Pod Sandbox(Pause 容器)创建 Namespace、网络、挂载,并在此基础上创建应用容器。
    4. Kubelet 调用 CRI.StartContainer,Containerd 通过 Runtime 插件启动 shim 与 runc,正式运行容器进程。
    5. 容器运行期间,Kubelet 可通过 CRI.UpdateContainerResourcesCRI.KillContainer 等接口对容器进行动态管理。

🚀 小结:通过 cri-containerd 插件,Containerd 完美对接 Kubernetes,省去了 Docker Shim 的额外开销,提高了性能与稳定性。


企业级落地实战

系统环境与前置依赖

  • 操作系统:CentOS 7.x、RHEL 7.x、Ubuntu 18.04+、Debian 10+ 均可支持。

  • 内核版本:建议 ≥ 4.14,以获得更好性能与兼容性,尤其是 OverlayFS、Seccomp、Cgroupv2 等。

  • 硬件资源:每台节点 ≥ 2 核 CPU、4GB 内存、100GB 磁盘空间(推荐 SSD)。

  • 网络环境:需要能够访问外部 Docker Registry(如 docker.iogcr.io 等)或本地私有镜像仓库(Harbor 等)。

  • 依赖工具

    • iptablesiproute2
    • runc(对于二进制方式安装需要额外安装)
    • CNI 插件包(如 Flannel、Calico、Weave 等)
    • crictl(可选,用于 CLI 方式管理 CRI 镜像与容器)

安装方式对比与实践

企业生产环境常见两种安装方式:YUM(APT)包管理安装二进制包离线安装

  • YUM/DEB 安装:优点是依赖自动解决、升级方便。缺点是版本可能滞后、对网络要求较高。
  • 二进制离线安装:优点是版本可控、适用于无网络或镜像需要严格一致的场景;缺点是需要手动管理依赖与配置。
YUM 安装(适用于 CentOS/RHEL)
  1. 添加 Docker 官方仓库或第三方镜像源

    # 添加阿里云 Docker CE 仓库(示例)
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
  2. 查看可用 containerd 版本

    sudo yum list containerd.io --showduplicates
    
  3. 安装 containerd.io

    sudo yum install -y containerd.io
    
  4. 启动并设置开机自启动

    sudo systemctl enable containerd
    sudo systemctl start containerd
    
  5. 验证安装

    # 查看版本
    sudo ctr version
    
    # 示例输出
    # Client:
    #   Version:  1.6.0
    #   Revision: 39259a8f35919a0d02c9ecc2871ddd6ccf6a7c6e
    # Server:
    #   Version:  1.6.0
    #   Revision: 39259a8f35919a0d02c9ecc2871ddd6ccf6a7c6e
    

Tip:YUM 安装方式会自动拉取并安装 runc、containerd、ctr、crictl 等相关二进制,对大多数常见场景足够。

二进制包安装(适用于离线环境与 Kubernetes 集群)
  1. 下载 containerd 二进制包

    • 访问 Containerd Releases,下载对应平台的 cri-containerd-cni-<version>-linux-amd64.tar.gz 包,该包已包含 runc 与 CNI 插件。
    • 也可仅下载 containerd-<version>-linux-amd64.tar.gz,此包需额外手动下载并安装 runc
  2. 解压并复制二进制文件

    # 假设包名为 cri-containerd-cni-1.6.0-linux-amd64.tar.gz
    tar zxvf cri-containerd-cni-1.6.0-linux-amd64.tar.gz -C /tmp
    
    # 复制 containerd 二进制文件
    sudo cp /tmp/usr/local/bin/containerd /usr/local/bin/
    sudo cp /tmp/usr/local/bin/ctr /usr/bin/
    sudo cp /tmp/usr/local/bin/containerd-shim* /usr/bin/
    sudo cp /tmp/usr/local/bin/runc /usr/sbin/    # 如果包中自带 runc,则复制到 /usr/sbin
    sudo chmod +x /usr/sbin/runc
    
  3. 部署 systemd 单元文件

    # 创建目录
    sudo mkdir -p /etc/systemd/system
    
    # 将容器包中的 systemd 服务文件复制过来
    sudo cp /tmp/etc/systemd/system/containerd.service /etc/systemd/system/
    
    # 重新加载 systemd 配置
    sudo systemctl daemon-reload
    
  4. 初始化默认配置文件

    # 创建配置目录
    sudo mkdir -p /etc/containerd
    
    # 生成默认配置信息到 /etc/containerd/config.toml
    sudo containerd config default > /etc/containerd/config.toml
    
  5. 替换或优化配置

    • 生产环境下,建议在默认配置基础上,调整镜像加速、CNI 插件路径、Snapshot 驱动、Runtime 配置等。
    sudo vim /etc/containerd/config.toml
    # 重点修改:snapshotter、runtime、registry mirrors、cni 配置等
    
  6. 启动 containerd

    sudo systemctl enable containerd
    sudo systemctl start containerd
    
    # 验证
    sudo systemctl status containerd
    sudo ctr version
    

Tip:若仅需单机测试,可下载 containerd-<version>-linux-amd64.tar.gz,手动安装 runc;若打算部署在 Kubernetes 集群,推荐使用 cri-containerd-cni 包,一次性获取所有组件。

配置与调优

在企业级场景下,除了基础安装外,我们要关注以下几个方面的优化与定制:

基础配置文件解读
root = "/var/lib/containerd"
state = "/run/containerd"
oom_score = -999

[grpc]
  address = "/run/containerd/containerd.sock"
  uid = 0
  gid = 0

[debug]
  level = "info"

[metrics]
  address = "127.0.0.1:1338"
  grpc_histogram = true

[cgroup]
  path = ""

[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    sandbox_image = "k8s.gcr.io/pause:3.6"
    systemd_cgroup = true
    stream_server_address = "127.0.0.1"
    stream_server_port = "0"
    max_container_log_line_size = 16384

    [plugins."io.containerd.grpc.v1.cri".containerd]
      snapshotter = "overlayfs"
      default_runtime_name = "runc"

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
        runtime_type = "io.containerd.runc.v2"
        # 可选择配置 runtime_engine、runtime_root、privileged_without_host_devices 等

    [plugins."io.containerd.grpc.v1.cri".cni]
      bin_dir = "/opt/cni/bin"
      conf_dir = "/etc/cni/net.d"
      conf_template = ""

    [plugins."io.containerd.grpc.v1.cri".registry]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
        endpoint = ["https://docker.mirrors.ustc.edu.cn", "http://hub-mirror.c.163.com"]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
        endpoint = ["https://gcr.mirrors.ustc.edu.cn/google-containers/"]
      # 若使用企业内私有仓库(如 Harbor),直接添加:
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.mycompany.com"]
        endpoint = ["https://harbor.mycompany.com"]

  [plugins."io.containerd.snapshotter.v1.overlayfs"]
    root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs"
    upperdir_label = false
  • rootstate:分别指定 containerd 数据存储根目录与运行时临时目录。
  • oom_score:调整 containerd 进程在 OOM 情况下的优先级,-999 意味着最低可能被 OOM 杀死。
  • metrics.address:用于 Prometheus 抓取监控数据,可根据实际部署网络开放端口。
  • sandbox_image:Kubernetes Pod 的沙盒 Pause 镜像(负责网络 namespace)地址,若网络不通国际仓库,需改为国内镜像或私有镜像。
  • systemd_cgroup:若集群使用 systemd cgroup driver,需设为 true
  • snapshotter:根据环境选择 overlayfs(大多数推荐),也可配置 btrfszfs
  • registry.mirrors:为不同 Registry 配置镜像加速或私有仓库地址,显著提升镜像拉取速度。
针对企业场景的镜像加速与私有仓库配置
  1. 添加公共镜像加速器

    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
      endpoint = ["https://registry-aliyun.example.com"]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
      endpoint = ["https://gcr.mirrors.ustc.edu.cn"]
    
  2. 配置私有仓库(Harbor)

    • 步骤 1:主机名解析

      # 在所有 containerd 节点 /etc/hosts 添加:
      10.0.0.10    harbor.mycompany.com
      
    • 步骤 2:修改 config.toml

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.mycompany.com"]
        endpoint = ["https://harbor.mycompany.com"]
      
    • 步骤 3:重启 containerd

      sudo systemctl restart containerd
      
    • 步骤 4:验证拉取

      # 登录 Harbor
      sudo ctr images pull docker.io/library/nginx:latest
      sudo ctr images tag docker.io/library/nginx:latest harbor.mycompany.com/project/nginx:latest
      sudo ctr images push harbor.mycompany.com/project/nginx:latest
      

📈 Tip:对于私有仓库,如果启用了 TLS 证书,请确保证书链正确配置在系统信任列表中;对于 HTTP 协议,还需在 config.toml 中添加 insecure_skip_verify = trueplain_http = true(视版本而定)。

安全性与权限控制
  1. Seccomp 与 AppArmor

    • 默认启用了 Seccomp,若有特殊需求可自定义 seccomp.json 配置。
    • 对于 Ubuntu 系列,可结合 AppArmor 进行白名单控制。
  2. Cgroup 权限隔离

    • 建议启用 systemd_cgroup = true,将容器进程以 systemd 单元的方式管理,便于监控与限速。
    • 可通过 ctr run --cgroup 指定容器的 cgroup 路径,进行资源限制。
  3. TLS 与认证

    • Containerd 的 gRPC 接口支持 TLS 验证,可在 --address 配置中添加 --tls-cert--tls-key
    • 在受限网络环境,可将 gRPC Socket 设为私有 Unix Domain Socket,并设置文件权限。

与 Kubernetes 集成:CRI-Overshadow

Kubelet 配置示例

在 Kubernetes 节点上,需修改 Kubelet 的启动参数,使其使用 containerd 作为运行时。

编辑 /var/lib/kubelet/kubeadm-flags.env(或 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf):

KUBELET_KUBEADM_ARGS="--container-runtime=remote \
  --container-runtime-endpoint=unix:///run/containerd/containerd.sock \
  --runtime-request-timeout=15m \
  --image-service-endpoint=unix:///run/containerd/containerd.sock \
  --pod-infra-container-image=registry.aliyun.com/google_containers/pause:3.6"
  • --container-runtime-endpoint:指定 CRI Socket 地址,默认为 /run/containerd/containerd.sock
  • --pod-infra-container-image:Pause 镜像地址,需要与 config.toml 中的 sandbox_image 一致。

重载并重启 kubelet:

sudo systemctl daemon-reload
sudo systemctl restart kubelet
CNI 与网络插件对接
  1. 安装 CNI 插件

    # 假设放在 /opt/cni/bin
    sudo mkdir -p /opt/cni/bin
    # 下载安装 Flannel/Calico CNI
    tar zxvf calico-amd64-v3.19.1.tgz -C /opt/cni/bin
    
  2. 配置 CNI 网络

    • 将 CNI 配置文件放在 /etc/cni/net.d/ 下,例如 /etc/cni/net.d/10-calico.conflist

      {
        "name": "k8s-pod-network",
        "cniVersion": "0.3.1",
        "plugins": [
          {
            "type": "calico",
            "log_level": "info",
            "datastore_type": "kubernetes",
            "k8s_auth_token": "__SERVICEACCOUNT_TOKEN",
            "k8s_auth_authority": "https://10.96.0.1:443",
            "k8s_client_certificate": "/etc/cni/net.d/calico-kubeconfig",
            "ipam": {
              "type": "calico-ipam"
            },
            "policy": {
              "type": "k8s"
            },
            "kubernetes": {
              "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
            }
          },
          {
            "type": "portmap",
            "snat": true,
            "capabilities": {"portMappings": true}
          }
        ]
      }
      
    • 确保 config.toml 中的 CNI 路径一致:

      [plugins."io.containerd.grpc.v1.cri".cni]
        bin_dir = "/opt/cni/bin"
        conf_dir = "/etc/cni/net.d"
      
  3. 验证网络插件生效

    # 查看节点上是否创建了 cni0、flannel.1 等网络接口
    ip a show cni0
    ip a show flannel.1
    
    # 在 Kubernetes 中创建一个测试 Pod,验证 Pod 间通信
    kubectl run test-pod --rm -it --restart=Never --image=busybox -- sh
    # 在容器内部 ping 另一个 Pod IP
    
示例:在 K8s 中使用 Containerd 部署应用
  1. 部署 nginx 应用

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-demo
    spec:
      containers:
      - name: nginx
        image: nginx:1.21-alpine
        ports:
        - containerPort: 80
    
    kubectl apply -f nginx-pod.yaml
    
  2. 查看容器创建过程

    • Kubelet 调用 CRI.PullImage

      sudo ctr -n k8s.io images ls | grep nginx
      
    • Kubelet 调用 CRI.CreateContainerCRI.StartContainer

      # 查看 containerd 运行的容器
      sudo ctr containers ls | grep nginx-demo
      # 查看 containerd 运行的任务
      sudo ctr tasks ls | grep nginx-demo
      
  3. 调试与排障

    • 查看 Pod 事件:

      kubectl describe pod nginx-demo
      
    • 查看 Kubelet 日志:

      sudo journalctl -u kubelet -f
      
    • 查看 Containerd 日志:

      sudo journalctl -u containerd -f
      

🚀 Tip:在高并发场景下,建议使用更轻量的镜像(如 distroless、Alpine)以加速镜像拉取与启动,同时在集群内部署 Registry Cache 节点,减少跨网络拉取延迟。


日志与监控

Prometheus 监控指标

Containerd 自带 Metrics 插件,将监控数据以 Prometheus 格式暴露在指定端口,便于采集与可视化。

  1. config.toml 中启用 Metrics

    [metrics]
      address = "0.0.0.0:1338"
      grpc_histogram = true
    
  2. 常见 Metrics 列表

    • containerd_runtime_operations_seconds_count{operation="pull"}:拉取镜像耗时统计。
    • containerd_tasks_create_duration_seconds:创建容器任务耗时。
    • containerd_snapshotter_usage_bytes{snapshotter="overlayfs"}:Snapshot 驱动存储使用量。
    • containerd_content_store_blob_total:Content Store 中 Blob 总数。
  3. Prometheus 配置示例

    scrape_configs:
      - job_name: 'containerd'
        metrics_path: /metrics
        static_configs:
          - targets: ['node1:1338', 'node2:1338']
    
  4. Grafana 可视化

    • 官方提供了 Containerd 监控 Dashboard,可直接导入到 Grafana 中。
    • 通过监控 Snapshot 使用量、镜像拉取速率、容器启动延迟等指标,快速定位存储、网络或调度瓶颈。
常见日志路径与排障方法
  • Containerd 日志

    • 默认使用 systemd 进行管理,查看命令:

      sudo journalctl -u containerd -f
      
    • 日志等级可通过 config.toml 中的 [debug] level = "debug" 调整。

  • Shim 与 runc 日志

    • containerd-shim-runc-v2 启动时,会将 Stdout/Stderr 重定向到 systemd 日志中,可通过 journalctl -u containerd 一并查看。

    • 若调试运行时失败,可设置 --log-level debug 参数启动 shim:

      sudo containerd --log-level debug
      
  • Kubelet 日志

    sudo journalctl -u kubelet -f
    
    • 报错如 Failed to create containerd clientImagePullBackOff 等,可查看 Kubelet 与 Containerd 交互的细节。
  • CNI 插件日志

    • 一般打印在 /var/log/calico//var/log/flannel/ 目录下,需根据具体插件查询相应日志。
    • 如 Pod 启动后无网络,可查看 CNI 是否正常加载配置与二进制。

性能分析与优化

Benchmarks 对比(Bucketbench、Microbench)

  1. Bucketbench 简介

    • Bucketbench 是 CNCF 推出的容器运行时基准测试工具,对启动、停止、删除容器等操作进行对比。
    • 常见对比对象:Docker(内置 containerd)、containerd(runc)、CRI-O、CRI-Dockerd、gVisor 等。
  2. 示例 Benchmark 结果对比

    操作项Docker (containerd v1.4)Containerd (v1.4 + runc)CRI-O (v1.20)
    创建容器80ms65ms70ms
    启动容器120ms95ms110ms
    停止容器35ms25ms30ms
    删除容器40ms30ms32ms
    拉取镜像800ms750ms770ms
    镜像解压时长1.2s1.0s1.1s

    结论

    • Containerd 直接使用 runc,省去了 Docker Engine 的额外封装层,在容器启动与删除等场景下表现更优。
    • CRI-O 与 Containerd 性能相近,但在镜像管理与插件生态上,Containerd 更为丰富。
  3. Microbench:微基准测试

    • 通过对单个操作(如 ctr runctr pullctr delete)进行细粒度测量,分析不同 Snapshot 驱动、网络插件、存储后端对性能的影响。

    • 示例命令:

      # 基于 overlayfs 测试启动 100 次 nginx 容器
      for i in $(seq 1 100); do
        sudo time ctr run --rm --snapshotter overlayfs docker.io/library/nginx:alpine bench.$$ sh -c "echo hello"
      done
      

调优思路与最佳实践

快照驱动与存储后端调优
  1. OverlayFS 优化

    • 设置 mount 参数:

      • metacopy=on:减少 copy-up 时元数据操作,提高写性能。
      • upperdir_label:与 SELinux 配合时可开启标签。
    • 如果底层文件系统为 XFS,可使用 ftype=1 格式化,有助于 Overlay 性能。

  2. Btrfs / ZFS 场景

    • Btrfs/ZFS 原生支持写时复制(COW),可在多容器场景下减少层复制开销,提升快照创建速度。
    • 代价是需要额外学习与调优,如设置 ZFS recordsize、Btrfs compress 等参数。
  3. 分布式存储与共享

    • 对于多节点场景,可结合 Ceph/Rook、GlusterFS、NFS 等分布式存储,统一 Content Store 与 Snapshot Store,减少跨节点拉取延迟。
    • 需注意挂载性能、并发访问瓶颈与网络带宽限制。
网络层与 CNI 调优
  1. CNI Plugin 选择

    • Flannel:易于部署,支持 VXLAN 与 Host-GW 模式,适用于中小规模集群。
    • Calico:支持 BGP 路由,网段灵活,可与 Istio 等服务网格无缝集成。
    • Weave:支持 mesh 网络,拓扑自愈能力强。
  2. IPAM 与 MTU 调整

    • 根据集群物理网络 MTU 来调整 CNI 网络 MTU,避免分片带来的性能下降。
    • 如物理网络 MTU = 1500,则设置 CNI MTU = 1450(VXLAN 头部开销)或更合适的数值。
  3. Host Networking vs Bridge 模式

    • Host Networking:容器直接使用宿主机网络,性能最好,但缺少隔离;适用于高性能网络应用(如 DPDK)。
    • Bridge 模式:通过 Linux bridge 或虚拟交换机隔离网络,安全与隔离性好,性能略低于 Host。
收敛时间与资源隔离
  1. 容器启动收敛时间

    • 优化镜像体积:尽可能使用精简镜像(如 multistage 编译、distroless),减少拉取与解压时间。
    • 本地镜像缓存:部署 Registry Cache 节点或使用 CDN 缓存,以降低跨网络拉取耗时。
  2. 资源隔离与 QoS

    • 使用 cgroup v2 或 systemd cgroup driver,实现对容器 CPU、内存、IO 的精细限制。
    • 结合 Kubernetes QoS(Guaranteed/Burstable/BestEffort)策略,保证关键业务容器资源优先级。

常见问题与故障排查

服务无法启动

  1. 检查 systemd 状态

    sudo systemctl status containerd
    
    • 若出现 Failed to start containerd,查看具体错误日志:

      sudo journalctl -u containerd -xe
      
  2. 配置文件语法错误

    • 修改 /etc/containerd/config.toml 后,可能出现 TOML 语法错误:

      • 使用 containerd --config /etc/containerd/config.toml config check 验证(部分版本支持)。
      • 也可将配置文件输出到临时文件,尝试用 toml lint 工具进行校验。
  3. 端口或 Socket 冲突

    • 默认 gRPC 监听 unix:///run/containerd/containerd.sock,若 Socket 已被占用,可尝试删除旧文件:

      sudo rm /run/containerd/containerd.sock
      sudo systemctl restart containerd
      
    • metrics.address 绑定端口与其他服务冲突,需修改或关闭 Metrics。


容器无法拉取镜像

  1. 网络连通性问题

    • 验证节点能否访问外部 Registry:

      curl -v https://registry-1.docker.io/v2/
      
    • 若走私有仓库,检查 /etc/hosts 或 DNS 是否正确解析。

  2. TLS 证书验证失败

    • 私有仓库若使用自签名证书,需将根证书添加到节点的系统信任列表:

      sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
      sudo update-ca-trust
      sudo systemctl restart containerd
      
    • 或在 config.toml 中启用 insecure_skip_verify(不推荐,仅测试时使用)。

  3. 镜像名称或标签错误

    • Containerd 的 ctr 命令需要指定完整路径,如 docker.io/library/nginx:latest,否则可能拉取失败:

      sudo ctr images pull docker.io/library/nginx:latest
      
    • 若镜像是私有镜像,需要先登录:

      sudo ctr images pull --user=username:password harbor.mycompany.com/project/nginx:latest
      

容器启动失败

  1. Runtime 错误

    • 查看 shim 与 runc 报错:

      sudo journalctl -u containerd -n 50
      
    • 常见原因:Seccomp 或 AppArmor 限制,缺少特权权限或 Capabilities。

      • 可在运行时加上 --security-opt seccomp=unconfined--privileged 测试。
  2. 挂载或 Volume 问题

    • 检查挂载点是否存在、权限是否正确:

      ls -ld /data/myvolume
      sudo chown 1000:1000 /data/myvolume
      
    • CNI 网络未准备好,导致容器创建时网络 namespace 创建失败,可通过 ctr network ls(部分版本)或查看 cni 日志定位。

  3. 资源不足

    • 查看系统资源:

      free -h
      df -h
      
    • 检查 cgroup 限制:

      sudo cgget -r cpu.cfs_quota_us /kubepods.slice
      sudo cgget -r memory.limit_in_bytes /kubepods.slice
      

性能瓶颈与高内存占用

  1. Content Store 与 Metadata Store 数据量过大

    • 定期清理无用镜像与快照:

      sudo ctr images rm $(sudo ctr images ls -q | grep "<none>")
      sudo ctr snapshots cleanup
      
    • 确保 GC 插件正常运行,可在 config.toml 中调整 deletion_thresholdmutation_threshold 触发频率。

  2. 过多的 Shim 进程

    • 每个容器对应一个 containerd-shim-runc-v2 进程,容器数量过多可能占用大量内存。
    • 可通过 ctr tasks ls 压测容器并发承载能力,并合理规划节点规模。
  3. CNI 插件内存泄漏

    • 某些版本的 CNI 插件可能存在内存泄漏,升级到最新稳定版本,或切换到更轻量插件如 Flannel VXLAN。
    • 定期重启 containerdkubelet,清理可能残留的网络 namespace 与进程。

总结与展望

Containerd 作为 CNCF 顶级项目,已成为当前云原生生态中不可或缺的容器运行时。通过其轻量、插件化、性能优越的特点,成功取代了早期的 Docker Shim,成为 Kubernetes、云平台与企业内部容器平台的首选底层引擎。

核心优势

  • 高性能:直接调用 runc,无需额外封装层,启动、停止、删除容器效率高。
  • 插件化设计:灵活接入不同存储、网络、运行时插件,满足多种场景需求。
  • 社区活跃:CNCF 资助、厂商支持,版本迭代迅速,生态兼容性强。
  • 企业实战:已在阿里、腾讯、华为、百度等大规模生产环境中广泛应用,支撑千万级容器规模。

未来展望

  • 多样化运行时:与 WebAssembly(WASM)、gVisor、Kata Containers 等运行时深度集成,以满足更高安全隔离需求。
  • CNI 与 Service Mesh 深度融合:网络与服务网格(如 Istio、Linkerd)更加紧密结合,为复杂微服务场景提供更高效的流量管理与监控。
  • 更丰富的可观察性:通过 eBPF、OpenTelemetry 等技术,提升对容器网络、系统调用、性能指标的可视化与告警能力。
  • 边缘与 IoT 场景:针对边缘计算节点资源受限特性,推出更轻量化、自动化的 Containerd 发行版,适配 IoT 与边缘场景。

🎯 技术沉淀:本文从 Containerd 的演进背景切入,深入剖析其架构与关键模块,并结合丰富的企业级实战经验与性能对比,帮助读者全面理解 Containerd 在生产环境中的落地实践。
🚀 社区贡献:欢迎各位技术同仁在 GitHub 上为 Containerd 社区贡献代码、提交 Issue、参与讨论,共同推动云原生生态的繁荣。


参考链接

  1. Containerd 官方文档
  2. GitHub: containerd/containerd
  3. Kubernetes CRI 文档
  4. CNCF Containerd 监控 Dashboard (Grafana)
  5. Docker vs Containerd vs CRI-O 对比分析
  6. OverlayFS 调优最佳实践
  7. Flannel CNI 插件使用手册
  8. Calico CNI 插件官方文档
  9. Kata Containers 官方文档
  10. gVisor 用户指南

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值