3. 容器镜像获取与仓库管理
在容器交付链路中,镜像仓库是镜像的“中转站”和“分发中心”。RHEL 默认使用 Podman 管理容器,但 Podman 的强项是运行容器,而不是精细地操作远程镜像。要检查、复制、删除远程镜像,以及处理多仓库认证,红帽提供的 Skopeo 是更合适的工具。它不依赖本地容器存储,可以直接与远程 registry 的 Registry HTTP API 交互,因此非常适合做镜像搬运、仓库巡检和离线交付。
Skopeo:面向远程镜像的搬运工具
Skopeo 的核心价值在于“不落地即可操作”。它支持 docker://、dir:、oci:、containers-storage: 等多种传输格式。日常最常用的四个子命令是:
skopeo inspect:读取远程镜像的 manifest、标签、架构、层摘要和创建时间,不下载镜像层。skopeo copy:在 registry、本地目录、OCI 布局之间复制镜像,可跨仓库、跨认证域。skopeo delete:删除远程仓库中的指定标签或摘要,需要仓库开启删除权限。skopeo list-tags:列出某个仓库中所有可用标签,便于确认版本。
例如,检查红帽 UBI 镜像的元数据:
skopeo inspect docker://registry.access.redhat.com/ubi9/ubi:latest
skopeo list-tags docker://registry.access.redhat.com/ubi9/ubi
输出中会包含 Digest、Architecture、Labels 等字段。其中 Digest 是镜像内容的唯一指纹,比标签更可靠。生产环境建议用摘要固定版本,例如 ubi9/ubi@sha256:...,避免 latest 漂移导致不同节点拉取到不同内容。
registries.conf:定义仓库的信任与搜索顺序
RHEL 中容器仓库配置位于 /etc/containers/registries.conf,采用 TOML 格式。它决定三件事:未写全域名时去哪些仓库搜索、哪些仓库允许不安全连接、以及各仓库的镜像重写规则。典型配置如下:
unqualified-search-registries = ["registry.access.redhat.com", "quay.io", "registry.internal.example.com"]
[[registry]]
prefix = "registry.internal.example.com"
location = "registry.internal.example.com:5000"
insecure = true
[[registry.mirror]]
location = "mirror.internal.example.com"
insecure = false
这里 unqualified-search-registries 定义了短名称的搜索顺序;insecure = true 表示允许通过 HTTP 或跳过 TLS 校验访问内部仓库,仅建议在隔离内网使用;registry.mirror 则让 Podman/Skopeo 优先从镜像站拉取,失败后再回源,适合大规模节点加速。修改后无需重启服务,新发起的拉取即生效。
auth.json:多仓库认证的集中管理
当仓库需要登录时,凭据保存在 ${XDG_RUNTIME_DIR}/containers/auth.json(普通用户)或 /run/containers/0/auth.json(root)。推荐用 podman login 或 skopeo login 写入,而不是手工编辑:
podman login quay.io -u myuser --password-stdin
skopeo login registry.internal.example.com:5000 -u admin --password-stdin
auth.json 的结构是 auths 下按仓库域名分组,每组保存 base64 编码的 用户名:密码。同一文件可同时保存 quay.io、红帽 registry 和内部仓库的凭据,Skopeo 在复制时会自动按目标域名选取对应认证。需要注意:该文件是明文凭据,权限应保持 600,且不要提交到 Git。
实践:从 quay.io 拉取 UBI 并推送到内部 registry
下面以“把 quay.io 上的 UBI 镜像搬运到内部仓库”为例,串联本节知识点。假设内部仓库地址为 registry.internal.example.com:5000,已开启删除权限,且已通过 skopeo login 完成认证。
第一步,确认源镜像信息,记录摘要:
skopeo inspect docker://quay.io/ubi9/ubi:latest | grep -E 'Digest|Architecture'
# 示例输出(合理假设):
# "Digest": "sha256:9f3a...c1d2",
# "Architecture": "amd64"
第二步,直接跨仓库复制,不经过本地存储:
skopeo copy \
--src-creds myuser:myquaytoken \
--dest-creds admin:internalpass \
docker://quay.io/ubi9/ubi:latest \
docker://registry.internal.example.com:5000/ubi9/ubi:internal
如果内部仓库使用 HTTP,需要在 registries.conf 中把该仓库标记为 insecure = true,否则 Skopeo 会因 TLS 校验失败而报 x509: certificate signed by unknown authority。复制完成后,用 skopeo list-tags docker://registry.internal.example.com:5000/ubi9/ubi 确认 internal 标签已出现,再用 skopeo inspect 比对源与目标的 Digest 是否一致——一致即说明内容完整搬运。
--override-arch amd64;若要保留多架构 manifest list,则不要加该参数,Skopeo 会整体复制索引。删除远程镜像与常见排障
删除远程标签使用 skopeo delete docker://registry.internal.example.com:5000/ubi9/ubi:internal。注意:多数 registry 默认关闭删除接口,需要服务端启用 delete.enabled=true,否则会返回 405。删除标签不会立即回收存储,还需在仓库侧执行垃圾回收。
常见问题与判断依据:
- unauthorized:auth.json 中域名与目标地址不一致,或凭据过期。用
skopeo login重新写入。 - manifest unknown:标签不存在或拼写错误,先用
list-tags核对。 - connection refused:内部仓库端口未监听,或 registries.conf 中 location 端口写错。
- digest mismatch:复制中断或镜像被覆盖,重新执行 copy 并再次比对摘要。
把 Skopeo、registries.conf 与 auth.json 三者配合使用,就能在不启动容器、不占用本地存储的前提下完成镜像的检查、搬运、删除与认证管理,为后续在 RHEL 上部署容器应用准备好可靠的镜像来源。