3. 镜像仓库的安装与配置
在企业 OpenShift 环境中,镜像仓库通常不是“装一个 registry 容器”这么简单,而是要把高可用、持久化、外部访问和证书信任一起设计好。OpenShift 自带的 Image Registry Operator 负责把内部 registry 以集群组件的方式部署出来,它默认使用 openshift-image-registry 命名空间,并通过一个名为 cluster 的 configs.imageregistry.operator.openshift.io 自定义资源来声明期望状态。理解这个 Operator 的调谐逻辑,是后续存储、路由和 TLS 配置的基础。
Operator 部署:从 CR 到实际工作负载
安装镜像仓库的第一步不是手工创建 Deployment,而是确认 Image Registry Operator 处于可用状态,然后编辑 cluster 这个 CR。Operator 会监听该 CR,并据此创建或更新 registry 的 Deployment、Service、ConfigMap、Secret 以及可选的 Route。可以用下面的命令查看当前状态:
oc get clusteroperator image-registry
oc get configs.imageregistry.operator.openshift.io/cluster -o yaml
oc get pods -n openshift-image-registry
如果 managementState 为 Managed,说明 Operator 会持续管理 registry;若为 Removed,则相关组件会被清理。生产环境通常保持 Managed,并通过 replicas 控制副本数。默认情况下 registry 可能只运行 1 个副本,这在高可用要求下是不够的。将副本数设为 2 或 3,并配合反亲和性,可以避免单节点故障导致整个仓库不可用。需要注意的是,副本数增加后,所有副本必须共享同一份后端存储,否则会出现“同一镜像在不同 Pod 上看到的内容不一致”的问题。
存储后端选择:emptyDir、PVC 与对象存储
存储后端决定了镜像层数据放在哪里,也直接决定了仓库能否持久化和扩容。OpenShift Image Registry 支持多种后端,常见选择如下:
| 后端类型 | 典型配置 | 适用场景 | 主要限制 |
|---|---|---|---|
| emptyDir | 不声明 storage,默认使用节点临时目录 | 实验、临时验证 | Pod 重建后镜像丢失,不能用于生产 |
| PVC(块/文件) | storage.pvc.claim 指定 RWO 或 RWX 卷 | 中小规模、单副本或支持 RWX 的集群 | RWO 卷无法被多副本同时挂载 |
| 对象存储 | S3、Swift、Azure Blob、GCS 等 | 生产、多副本、大规模 | 需要额外维护 bucket、凭据和网络连通性 |
如果使用 PVC,配置片段大致如下:
spec:
storage:
pvc:
claim: registry-pvc
replicas: 2
这里有一个关键判断:若 replicas 大于 1,PVC 的访问模式必须是 ReadWriteMany,否则第二个副本会因卷被占用而无法启动。很多集群默认 StorageClass 只支持 ReadWriteOnce,这时要么改用对象存储,要么把副本数降为 1,并接受单点风险。对象存储则没有这个限制,多个 registry Pod 可以同时读写同一个 bucket,更适合生产。以 S3 兼容存储为例,通常需要创建一个 Secret 保存 REGISTRY_STORAGE_S3_ACCESSKEY 和 REGISTRY_STORAGE_S3_SECRETKEY,再在 CR 中引用:
spec:
storage:
s3:
bucket: ocp-registry-prod
region: cn-north-1
regionEndpoint: https://s3.example.com
encrypt: true
virtualHostedStyle: false
配置完成后,Operator 会重建 registry Pod。此时应观察 Pod 是否进入 Running,并检查日志中是否出现存储初始化失败、凭据错误或 bucket 不存在等信息。只有存储后端真正可用,后面的路由和证书才有意义。
路由暴露:内部访问与外部访问
默认情况下,registry 只在集群内部通过 Service 暴露,Pod 可以使用 image-registry.openshift-image-registry.svc:5000 推送和拉取镜像。如果集群外的构建机、CI 或开发人员需要访问,就必须创建 Route。配置项是 spec.defaultRoute:
spec:
defaultRoute: true
开启后,Operator 会创建一条名为 default-route 的 Route,主机名通常形如 default-route-openshift-image-registry.apps.example.com。外部客户端随后可以用这个域名登录:
podman login default-route-openshift-image-registry.apps.example.com -u kubeadmin -p $(oc whoami -t)
但要注意,Route 暴露的是 HTTPS 端点,而 registry 自身可能使用自签名证书。如果客户端不信任该证书,登录会失败。因此,路由暴露和 TLS 证书管理必须一起考虑。
TLS 证书管理:让客户端真正信任
OpenShift 内部组件之间的通信通常由集群 CA 签发证书,但外部客户端并不一定信任这个 CA。要让外部工具顺利访问,需要把 registry 的 CA 证书加入客户端的信任链。可以从集群中提取:
oc extract secret/router-ca -n openshift-ingress-operator --to=/tmp --confirm
# 或从 registry 相关 secret 中获取
oc get secret -n openshift-image-registry | grep tls
更规范的做法是使用企业 CA 或公共 CA 签发的证书,并通过 spec.tls 或 Route 的证书字段进行替换。若使用自定义证书,需要把证书和私钥放入 Secret,并确保 Route 的 termination 为 reencrypt 或 passthrough,具体取决于 registry 是否自行终止 TLS。配置完成后,用 openssl s_client 或 curl -v 验证证书链是否完整、主机名是否匹配、有效期是否正常。
下面这张图把 Operator、存储后端、Route 和 TLS 证书之间的关系集中呈现出来,便于在配置时快速定位每个对象的作用位置。
实际配置时,建议按“先存储、再副本、后路由、最后证书”的顺序推进。因为存储不可用会导致 Pod 反复重启,副本数设置错误会暴露访问模式冲突,而路由和证书只有在 registry 本身健康时才能验证成功。每一步都可以用 oc get pods -n openshift-image-registry、oc get route -n openshift-image-registry 和 oc describe configs.imageregistry.operator.openshift.io/cluster 观察状态变化。当 Pod 稳定运行、Route 可解析、证书链完整时,再执行一次真实的 podman push 和 podman pull,才能确认整条链路真正打通。