ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

绕过Docker Daemon:使用ctr命令通过HTTP协议操作容器镜像

绕过Docker Daemon:使用ctr命令通过HTTP协议操作容器镜像 1. 项目概述为什么需要绕过Docker Daemon直接操作镜像在容器和云原生的日常运维里我们最熟悉的镜像操作命令莫过于docker pull和docker push。Docker CLI 就像一个友好的前台接收我们的指令然后交给后台的 Docker Daemon 去真正执行拉取、推送这些“体力活”。这个架构清晰但也带来了一个问题强依赖。你必须确保 Docker Daemon 服务正常运行并且你拥有调用它的权限通常是需要sudo或加入docker用户组。但有些场景下这个“前台-后台”的架构会显得笨重甚至不可用。比如在一个高度定制化或安全策略严格的环境中Docker Daemon 可能被禁用或者你需要在 CI/CD 流水线的某个无特权容器内直接操作镜像而不想或不能运行一个完整的 Docker Daemon。再比如当你需要对镜像的传输过程进行更底层的控制或调试时绕过 Daemon 直接与容器运行时或镜像仓库对话会给你带来前所未有的清晰视野。这时ctr命令就该登场了。它是 Containerd 这个行业标准容器运行时的命令行工具。Containerd 负责管理容器的完整生命周期而镜像管理正是其核心功能之一。ctr允许你直接与 Containerd 交互执行包括拉取、推送、导入、导出镜像在内的所有底层操作完全不需要 Docker Daemon 的参与。而今天我们要深入探讨的就是如何用ctr通过最基本的 HTTP 协议来完成镜像的推送push和拉取pull。这不仅是解决特定环境限制的钥匙更是深入理解容器镜像分发机制的一扇窗。2. 核心概念与前置准备2.1 ctr、Containerd 与 Docker 的关系辨析在开始实操前理清这几个概念至关重要否则很容易在后续步骤中混淆。Containerd是一个容器运行时。它的职责是执行容器管理容器的生命周期创建、启动、停止、删除、存储、网络等底层细节。它遵循 OCIOpen Container Initiative标准是 Kubernetes 默认的容器运行时也是 Docker 引擎的底层核心组件。ctr是 Containerd 自带的一个低级命令行客户端。你可以把它理解为 Containerd 的“瑞士军刀”功能强大且直接但用户界面相对不友好主要面向开发者和高级运维人员用于调试、测试或在不依赖 Docker 的情况下直接操作 Containerd。Docker是一个完整的容器化平台。它包含 Docker Daemon一个常驻后台进程、Docker CLI我们常用的docker命令以及一系列工具。Docker Daemon 在内部调用 Containerd 来运行容器但同时提供了镜像构建、网络管理、卷管理、用户友好的 API 等高层功能。简单来说ctr直接对话Containerddocker命令对话Docker Daemon后者再调用Containerd。因此使用ctr操作镜像是更接近底层、更轻量级的方式。2.2 理解镜像仓库与 HTTP 协议镜像仓库Registry是存储和分发容器镜像的地方比如 Docker Hub、Google Container Registry (GCR)、Amazon ECR以及私有的 Harbor、Nexus 等。默认情况下无论是docker还是ctr与镜像仓库通信都使用HTTPS协议。这是为了保障传输安全防止镜像被篡改。然而在内网测试、开发环境或者某些特定架构中我们可能会搭建或使用一个只支持HTTP的仓库例如一个简单的、未配置 TLS 证书的私有仓库。直接让ctr使用 HTTP 访问仓库它会出于安全考虑而拒绝。这就需要我们明确地告诉 Containerd“我知道这个仓库不安全但我接受风险请允许我使用 HTTP 连接它。”2.3 环境检查与 ctr 安装首先确保你的系统已经安装了 Containerd。在大多数现代 Linux 发行版上如果安装了 Docker通常也会安装 Containerd。# 检查 Containerd 服务状态 sudo systemctl status containerd # 检查 ctr 命令是否可用 ctr version如果ctr命令不存在你需要单独安装 Containerd。例如在 Ubuntu 上# 安装 Containerd sudo apt-get update sudo apt-get install -y containerd.io # 启动并启用服务 sudo systemctl enable --now containerd安装后Containerd 的主配置文件通常位于/etc/containerd/config.toml。我们后续的 HTTP 仓库配置将主要在这里进行。注意直接操作ctr和 Containerd 配置通常需要root权限。请确保你使用sudo或在 root 用户下操作。3. 配置 Containerd 以允许 HTTP 仓库这是最关键的一步。Containerd 通过配置文件中的registry.mirrors和registry.configs节点来定义如何与各个镜像仓库通信。3.1 生成默认配置文件如果/etc/containerd/config.toml文件不存在可以先让 Containerd 生成一个默认配置。sudo mkdir -p /etc/containerd sudo containerd config default | sudo tee /etc/containerd/config.toml3.2 修改配置文件以添加 HTTP 仓库假设我们有一个内网私有仓库地址是http://my-insecure-registry.local:5000。我们需要在配置文件中声明它。使用文本编辑器如vim或nano打开配置文件sudo vim /etc/containerd/config.toml找到[plugins.”io.containerd.grpc.v1.cri”.registry]这个部分。这是配置容器运行时接口CRI的 registry 设置ctr命令也会参考这里的配置。我们需要在configs下为我们仓库的 host 创建一个配置项并指定insecure_skip_verify true。同时也可以在mirrors中为其定义一个镜像加速地址这里就是它本身。在配置文件中添加或修改如下内容[plugins.io.containerd.grpc.v1.cri.registry] # 定义镜像仓库的镜像加速地址 [plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.my-insecure-registry.local:5000] endpoint [http://my-insecure-registry.local:5000] # 注意是 http # 定义针对特定仓库的配置 [plugins.io.containerd.grpc.v1.cri.registry.configs] [plugins.io.containerd.grpc.v1.cri.registry.configs.my-insecure-registry.local:5000] [plugins.io.containerd.grpc.v1.cri.registry.configs.my-insecure-registry.local:5000.tls] insecure_skip_verify true # 关键跳过 TLS 验证配置解析mirrors.”my-insecure-registry.local:5000″这为仓库主机名定义了一个端点列表。当拉取镜像时Containerd 会尝试这些端点。这里我们直接指向 HTTP 地址。configs.”my-insecure-registry.local:5000″.tls.insecure_skip_verify true这是允许 HTTP 连接的核心。它告诉 Containerd连接到这个主机时不要验证 TLS 证书。对于 HTTP 连接这个设置同样使其被允许。3.3 重启 Containerd 服务并验证配置修改保存配置文件后必须重启 Containerd 服务使配置生效。sudo systemctl restart containerd sudo systemctl status containerd # 确认服务重启成功没有报错验证配置是否被加载可以查看服务的详细状态或使用ctr命令列出已知的命名空间间接测试连接。# 查看 containerd 服务日志看是否有配置错误 sudo journalctl -u containerd --since “5 minutes ago” | tail -20 # 使用 ctr 查看镜像测试基础功能 sudo ctr images ls如果服务重启成功且无错误日志说明配置已生效。4. 使用 ctr 进行 HTTP 镜像拉取Pull配置好仓库后我们就可以开始实际操作了。ctr命令的基本格式是ctr [全局选项] 对象类型 子命令 [命令选项]。4.1 拉取镜像的命令格式拉取镜像到本地的命令是ctr images pull。sudo ctr images pull [选项] 镜像引用一个完整的镜像引用image reference通常格式为仓库地址/命名空间/镜像名:标签例如my-insecure-registry.local:5000/library/nginx:alpine4.2 从 HTTP 仓库拉取镜像实操假设我们的 HTTP 私有仓库里有一个nginx:alpine镜像。# 从我们配置的 HTTP 仓库拉取镜像 sudo ctr images pull my-insecure-registry.local:5000/library/nginx:alpine # 拉取成功后查看本地镜像列表 sudo ctr images ls执行过程解析ctr会解析镜像引用my-insecure-registry.local:5000/library/nginx:alpine。根据我们之前的配置它知道my-insecure-registry.local:5000对应的 endpoint 是http://my-insecure-registry.local:5000并且允许不安全连接。ctr会向http://my-insecure-registry.local:5000/v2/发起请求进行仓库 API 版本检查。然后请求http://my-insecure-registry.local:5000/v2/library/nginx/manifests/alpine获取镜像清单manifest。接着根据清单中的层layer摘要digest逐个拉取 blob 文件例如http://my-insecure-registry.local:5000/v2/library/nginx/blobs/sha256:xxx...。所有层拉取完毕后在本地构建出完整的镜像。常见问题与排查错误failed to resolve reference “my-insecure-registry.local:5000/...: http: server gave HTTP response to HTTPS client原因这是最典型的错误意味着 Containerd 仍然试图用 HTTPS 去连接仓库。99% 的原因是你的配置文件没有生效。排查确认配置文件/etc/containerd/config.toml修改正确特别是 host 名称my-insecure-registry.local:5000是否与镜像引用中的完全一致包括端口。确认重启了containerd服务 (sudo systemctl restart containerd)。检查是否有其他配置文件覆盖例如/etc/containerd/certs.d/目录下的配置。ctr也会参考这个目录。你可以尝试在这个目录下创建对应的 host 配置来允许 HTTP。例如sudo mkdir -p /etc/containerd/certs.d/my-insecure-registry.local:5000 echo ‘{“http”: true}’ | sudo tee /etc/containerd/certs.d/my-insecure-registry.local:5000/hosts.toml然后再次重启 containerd。/etc/containerd/certs.d/的优先级有时比config.toml中的 CRI 配置更高。错误failed to do request: Head “http://.../v2/...“: dial tcp: lookup my-insecure-registry.local on ...: no such host原因DNS 解析失败无法找到仓库主机。解决确保你的主机名可以被解析。对于内网地址最简单的方法是在/etc/hosts文件中添加一条记录echo “192.168.1.100 my-insecure-registry.local” | sudo tee -a /etc/hosts将192.168.1.100替换为你私有仓库的实际 IP 地址。错误unexpected status: 404 Not Found原因镜像在仓库中不存在或者镜像引用路径写错了例如命名空间或镜像名错误。解决使用curl或浏览器直接访问仓库的 API 来验证镜像是否存在curl -X GET http://my-insecure-registry.local:5000/v2/_catalog curl -X GET http://my-insecure-registry.local:5000/v2/library/nginx/tags/list4.3 拉取镜像的进阶选项ctr images pull提供了一些有用的选项--skip-verify跳过镜像内容的完整性验证不推荐在生产环境使用。--platform指定拉取特定平台的镜像如linux/amd64,linux/arm64。这在多架构仓库中非常有用。--all-platforms拉取所有可用平台的镜像。# 拉取特定平台的镜像 sudo ctr images pull --platform linux/arm64 my-insecure-registry.local:5000/library/nginx:alpine # 拉取时显示详细信息 sudo ctr -d images pull my-insecure-registry.local:5000/library/nginx:alpine5. 使用 ctr 进行 HTTP 镜像推送Push将本地镜像推送到仓库是ctr images push。但这里有一个关键前提你需要先为本地镜像打上符合目标仓库地址的标签。5.1 镜像标签管理与推送准备ctr无法像docker tag那样直接给镜像重命名。在ctr的世界观里镜像的名称严格说是镜像引用是其不可分割的身份标识。因此我们通常需要先通过其他方式比如从 Docker 导出再导入或者直接构建得到一个带有正确仓库标签的镜像。方法一利用 Docker 中转如果 Docker 可用这是最方便的方法。先用 Docker 拉取或构建镜像打上标签然后导出给ctr。# 1. 使用 Docker 拉取或构建一个基础镜像 docker pull nginx:alpine # 2. 给这个镜像打上目标 HTTP 仓库的标签 docker tag nginx:alpine my-insecure-registry.local:5000/myteam/nginx:my-version # 3. 将 Docker 镜像导出为 tar 包 docker save -o nginx-myversion.tar my-insecure-registry.local:5000/myteam/nginx:my-version # 4. 使用 ctr 导入这个 tar 包 sudo ctr images import nginx-myversion.tar # 5. 检查 ctr 中是否有这个镜像 sudo ctr images ls | grep my-insecure-registry方法二直接使用 ctr 从远程拉取如果源可用如果源镜像本身就在某个可访问的仓库包括这个 HTTP 仓库直接拉取即可。# 直接从目标 HTTP 仓库拉取一个镜像假设已存在 sudo ctr images pull my-insecure-registry.local:5000/myteam/nginx:base5.2 执行镜像推送操作确保本地ctr的镜像列表中已经有了一个标签为目标 HTTP 仓库地址的镜像后就可以执行推送了。# 推送镜像到 HTTP 仓库 sudo ctr images push my-insecure-registry.local:5000/myteam/nginx:my-version推送过程解析ctr会先检查本地是否存在该镜像。向仓库http://my-insecure-registry.local:5000/v2/发起请求确认 API 支持。检查目标仓库中是否已存在该镜像的清单Manifest以决定是否需要上传层Layer。对于仓库中不存在的镜像层Blobctr会逐个通过 HTTP PUT 请求上传到http://my-insecure-registry.local:5000/v2/myteam/nginx/blobs/upload/...。所有层上传完毕后最后上传镜像清单Manifest文件完成推送。5.3 推送过程中的常见问题与排查错误failed commit on ref “manifest”: unexpected status: 401 Unauthorized原因仓库需要认证但ctr没有提供有效的凭据。解决需要在 Containerd 的配置中为这个仓库配置认证信息。编辑/etc/containerd/config.toml在对应仓库的configs下添加auth部分。[plugins.io.containerd.grpc.v1.cri.registry.configs.my-insecure-registry.local:5000.auth] username myuser password mypassword或者更安全的方式是使用config.json文件。ctr会尝试从 Docker 的认证配置中读取凭据~/.docker/config.json。你可以先用docker login my-insecure-registry.local:5000登录然后ctr可能会自动使用这些凭据。但注意ctr对config.json的支持可能因版本而异最可靠的方法还是直接写在config.toml里。修改配置后别忘了重启containerd。错误unexpected status: 405 Method Not Allowed或unexpected status: 404 Not Found原因仓库的 API 路径可能不正确或者仓库不支持 v2 API。请确保你的私有仓库如 Harbor, Nexus正确部署并开启了 v2 API 支持。用curl测试curl -X GET http://my-insecure-registry.local:5000/v2/应该返回{}或一个空 JSON 对象。如果返回 404说明 v2 API 未启用。错误推送缓慢或超时原因镜像层太大HTTP 传输慢或网络不稳定。解决考虑优化镜像减少层数和大小。对于内网确保网络带宽和延迟正常。ctr本身推送大镜像的进度反馈不如 Docker 友好需要耐心等待。可以加上-d参数查看详细日志。6. 高级技巧与生产环境考量6.1 使用/etc/containerd/certs.d/目录进行更精细的配置我们之前修改了config.toml。实际上Containerd 推荐使用/etc/containerd/certs.d/目录来配置每个仓库的详细设置这个目录的配置优先级更高且更清晰。目录结构规则是/etc/containerd/certs.d/host:port/hosts.toml为我们的 HTTP 仓库创建配置# 创建对应仓库的配置目录 sudo mkdir -p /etc/containerd/certs.d/my-insecure-registry.local:5000 # 创建 hosts.toml 配置文件 sudo tee /etc/containerd/certs.d/my-insecure-registry.local:5000/hosts.toml EOF server “http://my-insecure-registry.local:5000” [host.”http://my-insecure-registry.local:5000″] capabilities [“pull”, “resolve”, “push”] skip_verify true # 如果需要认证 # [host.”http://my-insecure-registry.local:5000″.header] # authorization [“Basic base64-encoded-auth”] EOF这个配置明确指定了服务器地址、允许的操作并跳过了验证。使用这种方式后甚至可以简化或移除config.toml中的相关配置。修改此目录配置通常不需要重启 containerd但为了保险起见重启一下服务总是好的。6.2 处理多架构镜像Multi-Arch Images现代镜像仓库通常支持存储多个平台如 amd64, arm64的镜像并通过一个“清单列表”manifest list来统一引用。ctr对多架构镜像的支持是原生的。拉取多架构镜像的特定平台sudo ctr images pull --platform linux/amd64 my-insecure-registry.local:5000/library/nginx:latest sudo ctr images pull --platform linux/arm64 my-insecure-registry.local:5000/library/nginx:latest推送多架构镜像这通常不是直接用一个ctr push完成的。你需要先分别构建或拉取不同平台的镜像并使用像docker buildx或manifest-tool这样的工具创建并推送一个清单列表到仓库。ctr主要用于拉取和运行特定平台的单个镜像。6.3 镜像导入、导出与迁移ctr是进行镜像迁移的利器尤其是在无法运行 Docker Daemon 的环境中。从ctr导出镜像# 导出单个镜像为 tar 包 sudo ctr images export nginx.tar my-insecure-registry.local:5000/library/nginx:alpine # 导出时可以指定平台 sudo ctr images export --platform linux/arm64 nginx-arm64.tar my-insecure-registry.local:5000/library/nginx:alpine向ctr导入镜像sudo ctr images import nginx.tar # 或者指定镜像名如果 tar 包内元信息丢失 sudo ctr images import --base-name my-registry.com/nginx nginx.tar这个功能在离线环境部署、镜像备份和恢复时非常有用。6.4 安全警告与生产建议允许 HTTP 连接是极不安全的因为它使中间人攻击成为可能攻击者可以篡改你下载或上传的镜像。因此请务必遵守以下原则仅用于测试和开发HTTP 仓库只应在完全可控的内网测试环境中使用。使用 HTTPS对于任何生产环境或跨网络的仓库必须使用 HTTPS并配置有效的 TLS 证书。你可以使用 Let‘s Encrypt 获取免费证书或使用私有 CA 签发的证书。如果必须在内网使用 HTTP请确保网络边界安全避免该仓库暴露在公网。在 Containerd 配置中尽可能精确地指定insecure_skip_verify true的仓库 host而不是使用通配符以减少安全风险。7. 总结与故障排查速查表通过ctr使用 HTTP 协议操作镜像本质上是绕过了 Docker Daemon直接与容器运行时和镜像仓库进行底层对话。这提供了更大的灵活性和对流程的控制力特别适用于无 Docker 环境、CI/CD 流水线或深度调试。核心步骤永远有三步配置在/etc/containerd/config.toml或/etc/containerd/certs.d/host/hosts.toml中为目标 HTTP 仓库明确设置insecure_skip_verify true。重启修改配置后务必执行sudo systemctl restart containerd。操作使用sudo ctr images pull/push命令确保镜像引用中的仓库地址与配置中的 host 完全一致。故障排查速查表现象可能原因排查步骤http: server gave HTTP response to HTTPS client1. 配置未生效2. Host 地址不匹配3. 存在更高优先级配置冲突1. 确认配置修改正确并重启 containerd。2. 检查镜像引用地址与配置中的 host 是否一字不差。3. 检查/etc/containerd/certs.d/目录看是否有冲突配置。401 Unauthorized仓库需要认证1. 在config.toml或hosts.toml中添加auth配置。2. 尝试docker login后确认ctr是否能读取~/.docker/config.json。404 Not Found1. 镜像不存在2. 仓库 v2 API 未启用1. 用curl http://registry/v2/_catalog和.../v2/image/tags/list验证。2. 用curl http://registry/v2/验证 API 端点。no such hostDNS 解析失败1. 在/etc/hosts中添加 IP 和主机名的映射。2. 检查网络连通性ping registry-host。操作非常缓慢网络问题或镜像层过大1. 检查网络带宽和延迟。2. 优化镜像减少层大小。3. 使用-d参数查看详细传输日志。掌握ctr的 HTTP 镜像操作不仅仅是学会了一条命令更是理解了容器镜像分发协议的底层逻辑。下次当你面对复杂的容器环境或棘手的镜像问题时这份底层的掌控感或许能帮你更快地找到突破口。
返回列表