Containerd 概述

containerd 是一个容器运行时(Container Runtime),它负责管理容器的整个生命周期(镜像拉取、存储管理、容器执行、进程监控等),是 Docker 公司将其核心运行时组件剥离出来并捐献给 CNCF 的产物。

containerd 是 K8s 最推荐的 CRI 之一,它比完整的 Docker 引擎更轻量,占用的资源更少。

# 旧架构 (K8s → Docker):
K8s  (通过 CRI 接口)  ->  Docker  (通过 gRPC)  ->  containerd  (通过 OS 调用)  ->  runc

# 新架构 (K8s → containerd):
K8s  (通过 CRI 接口)  ->  containerd  (通过 OS 调用)  ->  runc
  • 在新架构中,K8s 可以直接通过 CRI 接口与 containerd 通信,省去了中间的 Docker daemon 层 (Dockershim)。这减少了 API 转换的开销、降低了复杂性,也排除了一个潜在的故障点。

Containerd 配置文件

# cat /etc/containerd/config.toml 
# ==============================================================================
# 核心配置部分 (General Settings)
# ==============================================================================
disabled_plugins = []
imports = []
oom_score = 0 # OOM分数调整,0表示不调整,避免containerd主进程被OOM killer轻易终止
plugin_dir = ""
required_plugins = []
root = "/var/lib/containerd" # containerd存储容器状态和镜像数据的根目录
state = "/run/containerd"    # containerd存储运行时状态、套接字等临时数据的目录
temp = ""
version = 2 # 配置文件版本

[cgroup]
  path = ""

[debug]
  address = ""
  format = ""
  gid = 0
  level = ""
  uid = 0

# ==============================================================================
# gRPC 接口配置 (API Communication)
# ==============================================================================
[grpc]
  address = "/run/containerd/containerd.sock" # containerd Unix域套接字地址,kubelet和crictl通过此通信
  gid = 0
  max_recv_message_size = 16777216
  max_send_message_size = 16777216
  tcp_address = "" # TCP监听地址(通常不启用)
  tcp_tls_ca = ""
  tcp_tls_cert = ""
  tcp_tls_key = ""
  uid = 0

[metrics]
  address = ""
  grpc_histogram = false

[plugins]

  [plugins."io.containerd.gc.v1.scheduler"] # 垃圾回收 (GC) 调度器配置
    deletion_threshold = 0
    mutation_threshold = 100
    pause_threshold = 0.02
    schedule_delay = "0s"
    startup_delay = "100ms"

# ==============================================================================
# CRI 插件配置 (Kubernetes Interface) - K8s交互的核心
# ==============================================================================
  [plugins."io.containerd.grpc.v1.cri"]
    cdi_spec_dirs = ["/etc/cdi", "/var/run/cdi"]
    device_ownership_from_security_context = false
    disable_apparmor = false
    disable_cgroup = false # 是否禁用cgroup,通常为false (启用资源限制)
    disable_hugetlb_controller = true
    disable_proc_mount = false
    disable_tcp_service = true
    drain_exec_sync_io_timeout = "0s"
    enable_cdi = false
    enable_selinux = false # 是否启用SELinux。在需要SELinux的环境中应设为true
    enable_tls_streaming = false
    enable_unprivileged_icmp = false
    enable_unprivileged_ports = false
    ignore_deprecation_warnings = []
    ignore_image_defined_volumes = false
    image_pull_progress_timeout = "5m0s"
    image_pull_with_sync_fs = false
    max_concurrent_downloads = 3 # 最大并发镜像层下载数
    max_container_log_line_size = 16384
    netns_mounts_under_state_dir = false
    restrict_oom_score_adj = false
    sandbox_image = "registry.k8s.io/pause:3.8" # K8s Pod 沙箱(pause容器)使用的镜像
    selinux_category_range = 1024
    stats_collect_period = 10
    stream_idle_timeout = "4h0m0s" # 流(如kubectl logs/exec)的空闲超时时间
    stream_server_address = "127.0.0.1"
    stream_server_port = "0"
    systemd_cgroup = false # K8s节点关键配置:是否使用systemd cgroup驱动。与kubelet保持一致很重要
    tolerate_missing_hugetlb_controller = true
    unset_seccomp_profile = ""

    [plugins."io.containerd.grpc.v1.cri".cni] # CNI 网络插件配置
      bin_dir = "/opt/cni/bin" # CNI插件可执行文件的目录
      conf_dir = "/etc/cni/net.d" # CNI配置文件目录
      conf_template = ""
      ip_pref = ""
      max_conf_num = 1
      setup_serially = false

    [plugins."io.containerd.grpc.v1.cri".containerd] # CRI 对接 containerd 的配置
      default_runtime_name = "runc" # 默认的容器运行时名称,对应下面的 [runc]
      disable_snapshot_annotations = true
      discard_unpacked_layers = false
      ignore_blockio_not_enabled_errors = false
      ignore_rdt_not_enabled_errors = false
      no_pivot = false
      snapshotter = "overlayfs" # 默认的快照存储驱动 (如 overlayfs, btrfs, zfs等)

      [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
        base_runtime_spec = ""
        cni_conf_dir = ""
        cni_max_conf_num = 0
        container_annotations = []
        pod_annotations = []
        privileged_without_host_devices = false
        privileged_without_host_devices_all_devices_allowed = false
        runtime_engine = ""
        runtime_path = ""
        runtime_root = ""
        runtime_type = ""
        sandbox_mode = ""
        snapshotter = ""

        [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options]

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] # 定义所有可用的容器运行时

        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] # runc 运行时配置
          base_runtime_spec = ""
          cni_conf_dir = ""
          cni_max_conf_num = 0
          container_annotations = []
          pod_annotations = []
          privileged_without_host_devices = false
          privileged_without_host_devices_all_devices_allowed = false
          runtime_engine = ""
          runtime_path = ""
          runtime_root = ""
          runtime_type = "io.containerd.runc.v2" # 使用 runc v2 shim
          sandbox_mode = "podsandbox"
          snapshotter = ""

          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] # runc 运行时选项
            BinaryName = ""
            CriuImagePath = ""
            CriuPath = ""
            CriuWorkPath = ""
            IoGid = 0
            IoUid = 0
            NoNewKeyring = false
            NoPivotRoot = false
            Root = ""
            ShimCgroup = ""
            SystemdCgroup = true # K8s节点关键配置:指示runc使用systemd cgroup驱动

      [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]
        base_runtime_spec = ""
        cni_conf_dir = ""
        cni_max_conf_num = 0
        container_annotations = []
        pod_annotations = []
        privileged_without_host_devices = false
        privileged_without_host_devices_all_devices_allowed = false
        runtime_engine = ""
        runtime_path = ""
        runtime_root = ""
        runtime_type = ""
        sandbox_mode = ""

        [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options]

    [plugins."io.containerd.grpc.v1.cri".image_decryption]
      key_model = "node"

    [plugins."io.containerd.grpc.v1.cri".registry] # 镜像注册表(Registry)配置
      config_path = ""

      [plugins."io.containerd.grpc.v1.cri".registry.auths] # 认证配置
      [plugins."io.containerd.grpc.v1.cri".registry.configs] # 镜像仓库特定配置
      [plugins."io.containerd.grpc.v1.cri".registry.headers]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors] # 镜像加速器/镜像源配置

    [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.internal.v1.tracing"]

  [plugins."io.containerd.metadata.v1.bolt"]
    content_sharing_policy = "shared"

  [plugins."io.containerd.monitor.v1.cgroups"]
    no_prometheus = false

  [plugins."io.containerd.nri.v1.nri"] # NRI 插件配置 (Node Resource Interface)
    disable = true
    disable_connections = false
    plugin_config_path = "/etc/nri/conf.d"
    plugin_path = "/opt/nri/plugins"
    plugin_registration_timeout = "5s"
    plugin_request_timeout = "2s"
    socket_path = "/var/run/nri/nri.sock"

  [plugins."io.containerd.runtime.v1.linux"]
    no_shim = false
    runtime = "runc"
    runtime_root = ""
    shim = "containerd-shim"
    shim_debug = false

  [plugins."io.containerd.runtime.v2.task"]
    platforms = ["linux/amd64"]
    sched_core = false

  [plugins."io.containerd.service.v1.diff-service"]
    default = ["walking"]
    sync_fs = false

  [plugins."io.containerd.service.v1.tasks-service"]
    blockio_config_file = ""
    rdt_config_file = ""

# ==============================================================================
# 快照插件配置 (Snapshotters) - 存储后端
# ==============================================================================
  [plugins."io.containerd.snapshotter.v1.aufs"]
    root_path = ""

  [plugins."io.containerd.snapshotter.v1.blockfile"]
    fs_type = ""
    mount_options = []
    root_path = ""
    scratch_file = ""

  [plugins."io.containerd.snapshotter.v1.btrfs"]
    root_path = ""

  [plugins."io.containerd.snapshotter.v1.devmapper"]
    async_remove = false
    base_image_size = ""
    discard_blocks = false
    fs_options = ""
    fs_type = ""
    pool_name = ""
    root_path = ""

  [plugins."io.containerd.snapshotter.v1.native"]
    root_path = ""

  [plugins."io.containerd.snapshotter.v1.overlayfs"] # 最常用的 Linux 存储驱动
    mount_options = []
    root_path = ""
    sync_remove = false
    upperdir_label = false

  [plugins."io.containerd.snapshotter.v1.zfs"]
    root_path = ""

  [plugins."io.containerd.tracing.processor.v1.otlp"]

  [plugins."io.containerd.transfer.v1.local"]
    config_path = ""
    max_concurrent_downloads = 3
    max_concurrent_uploaded_layers = 3

    [[plugins."io.containerd.transfer.v1.local".unpack_config]]
      differ = ""
      platform = "linux/amd64"
      snapshotter = "overlayfs"

[proxy_plugins]

[stream_processors] # 用于处理加密镜像等场景的流处理器

  [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
    accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
    args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
    env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
    path = "ctd-decoder"
    returns = "application/vnd.oci.image.layer.v1.tar"

  [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
    accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
    args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
    env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
    path = "ctd-decoder"
    returns = "application/vnd.oci.image.layer.v1.tar+gzip"

[timeouts] # 各种操作的超时配置
  "io.containerd.timeout.bolt.open" = "0s"
  "io.containerd.timeout.metrics.shimstats" = "2s"
  "io.containerd.timeout.shim.cleanup" = "5s"
  "io.containerd.timeout.shim.load" = "5s"
  "io.containerd.timeout.shim.shutdown" = "3s"
  "io.containerd.timeout.task.state" = "2s"

[ttrpc]
  address = ""
  gid = 0
  uid = 0