4. 镜像与ImageStream管理

在 OpenShift 中,容器镜像不只是“从某个 registry 拉下来的只读层”,它被抽象成了一套可追踪、可触发、可回滚的资源对象。理解这套抽象,是掌握持续交付流水线的关键一步。本节围绕 ImageStream、ImageStreamTag、ImageStreamImage 三个核心对象,讲清内部与外部镜像仓库的集成方式、镜像拉取策略,以及镜像流触发器如何驱动自动部署。

三个核心对象:从“仓库地址”到“可追踪指针”

最基础的是 ImageStream(镜像流)。它本身不存储镜像数据,而是一个逻辑命名空间,用来组织一组相关镜像。例如 myapp 这个 ImageStream 可以代表“我的应用的所有历史构建版本”。

ImageStreamTag(镜像流标签)是 ImageStream 下的具名指针,形如 myapp:latest 或 myapp:v1.2。它指向某个具体的镜像 ID(sha256 摘要)。关键点在于:这个指针是可移动的。当新构建完成时,myapp:latest 会自动指向新镜像,而 DeploymentConfig 或 Deployment 引用的是这个标签,于是“标签移动”就成了自动部署的触发源。

ImageStreamImage(镜像流镜像)则是通过“ImageStream 名 + 镜像摘要”精确定位到某一个不可变镜像,形如 myapp@sha256:abc123...。它用于需要绝对确定性的场景,比如回滚到某个确切版本,或审计“当时部署的到底是哪个镜像”。

记忆要点:ImageStream 是“目录”,ImageStreamTag 是“可移动书签”,ImageStreamImage 是“带页码的精确引用”。

内部镜像仓库与外部仓库集成

OpenShift 自带一个内部镜像仓库(Image Registry),通常以 image-registry.openshift-image-registry.svc:5000 形式暴露在集群内部。每个项目(Namespace)在其中拥有独立路径,例如 image-registry.../myproject/myapp:latest。构建(BuildConfig)产出的镜像默认推送到这里,ImageStream 也默认从这里拉取。

当需要引入外部镜像(如 Docker Hub、Quay、企业私有 Harbor)时,有两种典型做法:

  • 直接引用外部地址:在 Pod 或 Deployment 中直接写 docker.io/library/nginx:1.25。简单,但无法享受 ImageStream 的标签追踪与触发能力。
  • 导入为 ImageStream:使用 oc import-image 或带 --from 的 oc tag,把外部镜像“映射”成本地 ImageStreamTag。这样后续就能用触发器、回滚、标签移动等能力。
# 从外部仓库导入镜像到本地 ImageStream
oc import-image mynginx:1.25 \
  --from=docker.io/library/nginx:1.25 \
  --confirm

# 查看导入结果与镜像摘要
oc describe is/mynginx

若外部仓库需要认证,需创建 docker-registry 类型的 Secret,并关联到构建或 Pod 的 imagePullSecrets,否则拉取会因 401/403 失败。

镜像拉取策略:Always、IfNotPresent、Never

拉取策略决定了 kubelet 在启动容器时是否去 registry 取镜像,直接影响部署行为与离线可用性。

策略行为典型场景
Always每次启动都向 registry 校验并拉取使用 latest 等可变标签,需保证最新
IfNotPresent本地已有则不再拉取固定版本标签,节省带宽、加快启动
Never只使用本地镜像,绝不拉取离线环境、预置镜像节点

一个常见陷阱:当标签为 latest 时,默认策略是 Always;若改为 IfNotPresent,节点上旧镜像可能被复用,导致“明明推了新镜像却没生效”。因此生产环境更推荐使用不可变标签(如 git commit sha)配合 IfNotPresent。

镜像流触发器与自动部署机制

这是 ImageStream 最有价值的部分。DeploymentConfig 可以配置 ImageChange 触发器,监听某个 ImageStreamTag 的变化。当该标签指向的镜像摘要发生变化时,OpenShift 自动创建一个新的 ReplicationController 并滚动更新,无需人工干预。

triggers:
- type: ImageChange
  imageChangeParams:
    automatic: true
    containerNames:
    - myapp
    from:
      kind: ImageStreamTag
      name: myapp:latest

完整链路是:代码提交 → BuildConfig 构建 → 推送新镜像到内部仓库 → 更新 myapp:latest 指针 → ImageChange 触发器感知摘要变化 → 自动部署新版本。这条链路把“构建”和“发布”解耦又自动衔接,是 OpenShift 持续交付的核心机制。

需要注意:触发器比较的是镜像摘要而非标签名。即使标签名不变,只要摘要变了就会触发;反之若摘要相同,即使手动重新打标签也不会触发。排查“为什么没自动部署”时,应先确认 ImageStreamTag 的摘要是否真的更新了。

ImageStream 对象关系与自动部署链路 外部镜像仓库 Docker Hub / Quay / Harbor 内部镜像仓库 image-registry...svc:5000 oc import-image ImageStream myapp ImageStreamTag: latest → sha256:abc123 拉取/推送 ImageStreamImage myapp@sha256:abc123(不可变) 精确引用 ImageChange 触发器 监听标签摘要变化 automatic: true 摘要变化 DeploymentConfig 滚动更新新版本 新 RC → 替换旧 Pod 触发部署 BuildConfig 构建 产出新镜像并推送 推送

实操检查清单

在真实项目中,建议按以下顺序核对镜像与 ImageStream 配置,避免“构建成功但没部署”的常见问题:

  1. 确认 BuildConfig 的 output.to 指向正确的 ImageStreamTag,例如 myapp:latest。
  2. 确认 DeploymentConfig 的 triggers 中 ImageChange 的 from.name 与构建输出标签一致。
  3. 用 oc describe is/myapp 查看标签当前指向的摘要,与 oc get istag 交叉验证。
  4. 检查 imagePullPolicy:可变标签用 Always,不可变标签用 IfNotPresent。
  5. 若引用外部镜像,确认 imagePullSecrets 已配置且 Secret 有效。
  6. 观察 oc rollout status dc/myapp 与事件日志,确认触发器确实产生了新部署。