Containerd注册表配置避坑指南:从CRI弃用项到TLS证书的那些坑

📅 发布时间:2026/7/12 6:22:40 👁️ 浏览次数:
Containerd注册表配置避坑指南:从CRI弃用项到TLS证书的那些坑
Containerd注册表配置避坑指南从CRI弃用项到TLS证书的那些坑最近在帮几个团队升级容器运行时从Containerd 1.x迁移到2.x本以为是个平滑过渡结果在注册表配置这块踩了不少坑。尤其是那些历史遗留的CRI配置以及私有仓库的TLS证书验证问题稍不注意就会导致集群镜像拉取失败排查起来相当费劲。这篇文章我就结合自己趟过的雷系统性地梳理一下Containerd注册表配置的核心变化、常见陷阱以及具体的解决方案希望能帮你绕过这些暗礁。1. 理解Containerd注册表配置的演进与核心架构如果你还在沿用旧版的CRI配置方式那么在升级到Containerd 2.x时很可能会遇到第一个拦路虎。Containerd从1.5版本开始引入了一套全新的、基于主机命名空间的注册表配置模型旨在取代过去在config.toml中直接定义registry.mirrors和registry.configs的方式。这套新模型并非凭空而来它深度借鉴了OCI分发规范提供了更强的灵活性和一致性。为什么要有这个变化旧有的CRI配置方式将镜像仓库的配置如镜像加速器、认证信息与CRI插件本身深度耦合。当需要支持ctr命令行工具或其他非CRI客户端时配置无法复用管理起来也很分散。新的模型将配置外部化、标准化所有客户端ctr、CRI、镜像服务都能读取同一套配置实现了配置的“一处定义处处可用”。注意这个变化是渐进式的。在Containerd 1.x中旧的CRI配置方式已被标记为“弃用”但仍可工作。但在Containerd 2.x中强烈建议迁移到新模型因为旧方式未来可能会被完全移除且某些新功能可能仅在新模型下可用。新架构的核心是config_path这个配置项。它指向一个目录通常是/etc/containerd/certs.d/这个目录的结构决定了Containerd如何为不同的镜像仓库主机应用配置。其逻辑非常直观目录即命名空间在config_path指向的目录下每个子目录代表一个“注册表主机命名空间”通常是仓库的域名或IP和端口。文件即配置在每个命名空间目录下可以放置一个名为hosts.toml的TOML文件里面包含了针对该主机的详细配置如镜像加速地址、TLS设置、认证头等。回退机制如果找不到针对特定主机的配置Containerd会尝试寻找_default目录下的hosts.toml作为全局默认配置。如果连这个都没有则使用内置的默认行为。这种设计使得为docker.io、gcr.io或你公司的私有仓库registry.internal.com分别配置不同的镜像加速策略或安全策略变得轻而易举只需创建对应的目录和文件即可。2. 从旧版CRI配置到新版主机配置的迁移实战迁移的核心是将原来写在/etc/containerd/config.toml中[plugins.io.containerd.grpc.v1.cri.registry]节下的配置转移到/etc/containerd/certs.d/目录下的对应hosts.toml文件中。2.1 识别并停用旧配置首先打开你的config.toml文件找到CRI插件关于镜像仓库的配置部分。对于Containerd 1.x它看起来是这样的version 2 [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://your-mirror.aliyuncs.com] [plugins.io.containerd.grpc.v1.cri.registry.configs] [plugins.io.containerd.grpc.v1.cri.registry.configs.registry.internal.com.tls] insecure_skip_verify true对于Containerd 2.x配置路径发生了变化但结构类似version 3 [plugins.io.containerd.cri.v1.images.registry] [plugins.io.containerd.cri.v1.images.registry.mirrors] [plugins.io.containerd.cri.v1.images.registry.mirrors.docker.io] endpoint [https://your-mirror.aliyuncs.com]迁移第一步注释掉或删除上述整个[plugins...registry]及其所有子节。这是为了避免新旧配置冲突导致行为不可预测。2.2 启用并配置新的config_path在同一个config.toml文件中你需要确保或添加指向新配置目录的路径。对于Containerd 2.x配置如下version 3 [plugins.io.containerd.cri.v1.images.registry] config_path /etc/containerd/certs.d对于Containerd 1.x路径稍有不同version 2 [plugins.io.containerd.grpc.v1.cri.registry] config_path /etc/containerd/certs.d2.3 创建新的主机命名空间配置现在开始创建新的目录和hosts.toml文件。以上面的旧配置为例为docker.io配置镜像加速mkdir -p /etc/containerd/certs.d/docker.io创建/etc/containerd/certs.d/docker.io/hosts.toml内容如下server https://registry-1.docker.io [host.https://your-mirror.aliyuncs.com] capabilities [pull, resolve]这里server字段指定了默认的上游仓库Docker Hub官方。[host....]部分定义了一个镜像站点capabilities中的pull和resolve表示可以从该镜像拉取镜像并解析标签。为私有仓库registry.internal.com配置跳过TLS验证mkdir -p /etc/containerd/certs.d/registry.internal.com创建/etc/containerd/certs.d/registry.internal.com/hosts.toml内容如下[host.https://registry.internal.com] capabilities [pull, resolve, push] skip_verify trueskip_verify true就是用来跳过该仓库的TLS证书验证的常用于使用自签名证书的内部环境。完成上述步骤后重启Containerd服务sudo systemctl restart containerd你可以使用crictl pull或ctr images pull命令测试配置是否生效。一个常见的验证技巧是使用ctr并指定--hosts-dir来临时测试新配置而无需重启服务sudo ctr images pull --hosts-dir /etc/containerd/certs.d registry.internal.com/myapp:v13. TLS证书验证的深水区安全与便利的权衡TLS证书问题是导致镜像拉取失败的最常见原因之一尤其是在企业内部或测试环境中使用自签名证书时。Containerd提供了多种机制来处理证书理解它们的优先级和适用场景至关重要。3.1 证书查找链与优先级当Containerd尝试与一个HTTPS注册表通信时它会按以下顺序寻找和验证证书hosts.toml中的显式配置这是优先级最高的。你可以在hosts.toml中使用ca字段指定自定义的CA证书文件路径或者使用skip_verify true跳过验证。Docker兼容的证书文件模式如果在主机命名空间目录下没有hosts.toml文件Containerd会回退到检查以下文件主机名或IP[:端口]/证书文件例如对于registry.internal.com:5000它会查找registry.internal.com:5000/ca.crt作为CA证书。系统标准的证书存储位置如/etc/ssl/certs。系统根证书如果以上都未提供则使用操作系统信任的根证书库。3.2 配置自签名证书的正确姿势对于自签名证书最规范的做法是将你的私有CA证书提供给Containerd。假设你的CA证书是/etc/ssl/private/ca.pem。方法一在hosts.toml中指定CA推荐# /etc/containerd/certs.d/registry.internal.com/hosts.toml [host.https://registry.internal.com] capabilities [pull, resolve, push] ca /etc/ssl/private/ca.pem # 可以是绝对路径 # 或者 ca [/path/to/ca1.pem, /path/to/ca2.pem] 支持多个方法二使用Docker兼容模式# 创建对应目录 sudo mkdir -p /etc/containerd/certs.d/registry.internal.com\:5000 # 将CA证书复制为ca.crt sudo cp /etc/ssl/private/ca.pem /etc/containerd/certs.d/registry.internal.com:5000/ca.crt这种方式下目录名必须包含端口号如果有且证书文件必须命名为ca.crt。3.3 何时以及如何“跳过验证”skip_verify true是一个强大的选项但也是一把双刃剑。它完全禁用对目标服务器证书的验证包括证书是否由可信CA签发、主机名是否匹配、证书是否过期等。这意味着你面临着中间人攻击的风险。场景推荐做法风险等级生产环境私有仓库永远不要使用skip_verify。务必配置正确的CA证书。极高开发/测试环境隔离网络可临时使用但应尽快部署正式证书。中本地单机开发如localhost:5000可以使用需确保仅为该特定主机配置。低一个相对安全的跳过验证配置示例仅针对特定的IP和端口生效# /etc/containerd/certs.d/192.168.1.100_5000/hosts.toml [host.https://192.168.1.100:5000] capabilities [pull, resolve] skip_verify true注意目录名中端口号的处理用下划线_替换冒号:这是Unix系统的规则。提示如果你发现自己因为证书问题不得不大量使用skip_verify这通常是一个信号表明你的证书基础设施需要加强。考虑使用像Lets Encrypt这样的免费CA为内部服务签发证书或者搭建一个内部私有CA并确保所有节点都信任它。4. 高级配置场景与疑难排查掌握了基础迁移和TLS配置后我们来看几个更复杂但实用的场景以及当配置不生效时如何系统地排查。4.1 复杂镜像加速与镜像站策略有时你可能需要为同一个主机构建一个包含多个镜像站的列表或者设置一个纯粹的镜像不允许回退到上游。场景一多级镜像站按顺序尝试假设你有一个公司内部的镜像缓存站mirror.internal.com它缓存了docker.io和gcr.io的镜像。如果缓存中没有你希望它回退到公共互联网上的一个加速器最后再回退到官方仓库。# /etc/containerd/certs.d/docker.io/hosts.toml server https://registry-1.docker.io # 最终回退地址 [host.https://mirror.internal.com] capabilities [pull, resolve] # 可以在此处指定该镜像站独有的CA证书 # ca /certs/internal-mirror-ca.pem [host.https://public.accelerator.com] capabilities [pull, resolve]Containerd会按hosts.toml中[host]定义的顺序尝试拉取。场景二强制使用镜像禁止访问上游在某些严格隔离的网络中你可能希望完全阻断对公网仓库的直接访问所有流量必须经过指定的镜像。# /etc/containerd/certs.d/docker.io/hosts.toml server https://mirror.internal.com # 将镜像站设为“默认服务器” [host.https://mirror.internal.com] capabilities [pull, resolve]这里的关键是server字段指向了镜像站本身。这意味着如果mirror.internal.com不可用拉取就会失败而不会尝试连接registry-1.docker.io。4.2 认证信息的配置Containerd的新配置模型本身不直接在hosts.toml中存储用户名和密码。认证主要通过以下两种方式通过CRI插件Kubernetes这是最主要的方式。Kubernetes Pod可以通过imagePullSecrets来提供拉取私有镜像的凭证。Containerd的CRI插件会自动使用这些secret。通过ctr命令行使用ctr images pull时可以通过--user参数直接指定username:password。通过hosts.toml的[header]节可以注入静态的认证头例如用于Bearer Token认证。[host.https://private.registry.com] capabilities [pull, resolve] [host.https://private.registry.com.header] Authorization [Bearer your-static-token-here]注意这种方式将密钥明文存储在磁盘上安全性较低仅适用于令牌定期轮换或访问控制要求不高的场景。4.3 常见报错与排查清单当镜像拉取失败时可以按照以下步骤排查检查Containerd服务状态与日志sudo systemctl status containerd sudo journalctl -u containerd -f --since 5 minutes ago | grep -i pull\|registry\|auth日志中通常会包含连接失败、认证失败或证书错误的详细信息。验证配置目录和文件权限sudo ls -la /etc/containerd/certs.d/ sudo ls -la /etc/containerd/certs.d/docker.io/确保Containerd进程的用户通常是root有权限读取这些目录和hosts.toml文件。使用ctr命令进行独立测试# 测试不带任何自定义配置 sudo ctr images pull docker.io/library/nginx:alpine # 测试使用新配置目录 sudo ctr images pull --hosts-dir /etc/containerd/certs.d private.registry.com/app:latest # 测试跳过验证临时 sudo ctr images pull --skip-verify private.registry.com/app:latest通过对比不同参数下的结果可以快速定位是配置问题还是网络/证书问题。检查网络连通性与DNS解析sudo ctr images pull --plain-http private.registry.com/app:latest使用--plain-http可以排除TLS问题如果这样能成功那问题几乎肯定出在证书配置上。确认config.toml中的config_path 确保config_path指向的路径正确无误并且没有旧的registry.mirrors/configs配置干扰。理解端口号在目录名中的处理 这是最容易出错的地方之一。对于带端口的仓库地址myregistry.com:5000在Unix系统上配置目录名可以是myregistry.com:5000或myregistry.com_5000_。我个人的习惯是统一使用带下划线的格式如myregistry.com_5000_以避免任何潜在的shell或文件系统解析问题。最后记住Containerd的配置是动态加载的修改/etc/containerd/certs.d/下的文件不需要重启Containerd服务。但是修改/etc/containerd/config.toml文件后必须重启服务才能生效。每次进行重要配置变更后养成用ctr命令快速验证的习惯能节省大量故障排查时间。