- 测试
- 云原生
- 质量保障
【免费下载链接】origin
Conformance test suite for OpenShift
本文基于 OpenShift Origin 仓库中的镜像设计文档 docs/images.md,系统梳理 OpenShift 将容器镜像、镜像仓库、标签与元数据作为一等资源进行建模的设计动因、十大核心应用场景,以及"注册表 Webhook 推送 + 定时轮询"两条镜像仓库同步路径。读完本文,你将理解 ImageStream(镜像流)资源为何是 OpenShift 应用交付体系的基石,掌握镜像元数据作为"部署契约"的用法、仓库同步的两种实现方案及其取舍,并能结合仓库内的真实配置与测试代码理解其落地形态。
问题缘起:为什么 Kubernetes 需要 OpenShift 补齐镜像信息管理
文档开篇即点明核心问题:Kubernetes 从容器镜像仓库拉取镜像来创建容器,但它本身不追踪、不存储任何关于镜像的信息——它只是在 Pod 创建过程中把镜像拉取并缓存在工作节点(minion)上。这意味着"某个镜像长什么样、暴露了哪些端口、环境变量是什么、哪个版本正在被哪些部署使用"这类关键信息,在纯 Kubernetes 体系里是缺失的。
OpenShift 的设计思路是:把与镜像相关的信息——镜像仓库(image repository)、镜像本身(image)、标签(tag)以及元数据(metadata)——提升为平台中的一等资源(first-class resource),由独立的镜像组件(image component)统一管理。这一抽象为后续诸多上层能力提供了地基,也正是 OpenShift 的 ImageStream(镜像流)资源在设计文档中最早的雏形动机。这一设计在后来的实现中演化为image.openshift.io/v1下的ImageStream、Image、ImageStreamTag、ImageStreamImage、ImageStreamMapping等 API 资源,仓库中 examples/image-streams/image-streams-centos7.json 即为以ImageStreamList形式预置的官方镜像流清单。
十大核心应用场景:镜像成为平台资源的价值所在
1. 上游镜像仓库变更时自动重建下游镜像
将镜像仓库抽象为可监视(watchable)的资源后,平台可以在上游镜像发生变更时通知下游消费者,另一个组件(如构建系统)据此自动重建你的下游镜像。这里的价值在于:你无需在远端系统上手工配置变更通知,就能识别出需要监视的关键资源——这是一种有价值的抽象能力。
典型例子:你基于SomeUser/AwesomeImage:latest创建了一个新镜像。当上游的latest标签被更新指向一个新的镜像 ID 时,你既希望收到上游变更的通知,也希望下游镜像能被自动重建以响应这次更新。
这一场景在 OpenShift 中由 ImageChangeTrigger(镜像变更触发器)与 BuildConfig 的自动构建机制承载。仓库中 test/extended/images/imagechange_buildtrigger.go 正是对"镜像变更触发构建"行为的端到端验证;而 examples/image-streams/image-streams-centos7.json 中latest标签的描述也明确写着:"选择此标签后,你的应用将自动更新到 OpenShift 上可用的最新版本",这是该场景在生产镜像流配置中的直接体现。
2. 在不构建新镜像的前提下修改镜像元数据
镜像的元数据包括环境变量、暴露的端口、内存与 CPU 限制等。这些元数据是 Pod 模板生成的输入之一,因此平台需要能够存储和访问它们,并支持把"镜像及其默认元数据"与"使用者的覆盖值(overrides)"进行合并。
典型例子:你发现了一个别人制作的优秀 MySQL 镜像,但想调整其中一些环境变量的取值。你并不想基于这些设置重新构建一份镜像副本,因为你还想订阅"上游"镜像,并在新镜像到来时重新部署你的容器。
文档同时提出了一个需要警惕的设计问题:
- 如何应对大量用户对上游镜像做小改动的情况?每个人是否要把改动存储在自己的镜像仓库(IR)中?
- 这种灵活性带来一种风险:同一个镜像在一组环境变量下可以正常运行,换一组变量就可能启动失败——而如果变量在构建时被绑定(build time),这种不一致的情况就不会存在。这是"运行时覆盖元数据"与"构建期固化配置"两种哲学之间的经典权衡。
3. 随时间保持镜像视图的一致性(审计与历史追溯)
将镜像元数据纳入管理后,平台可以捕获某个特定版本的镜像在某次部署中实际使用的元数据,供审计与历史回顾使用。这要求镜像信息不能是"一次性拉取后就消失"的临时数据,而是可被反复查询、可回溯的状态。
4. 追踪镜像随时间的变化:"部署契约"(Deployment Contract)
镜像的元数据可以被视为一份部署契约——它声明了镜像将使用哪些环境变量、暴露哪些端口等。一个部署组件可以在镜像仓库发生变更时,基于新元数据生成新的 Pod 模板,并与当前运行的 Pod 对比,从而判断"仅因元数据变化"是否会导致现有部署被破坏。
典型例子:你部署了一个基于上游 Redis 镜像的 Pod。镜像仓库更新后,部署组件发现新 Pod 模板与当前模板不兼容——因为新版 Redis 镜像改变了暴露的端口。
这正是 OpenShift DeploymentConfig 中 ImageChangeTrigger 所要解决的核心问题:只有兼容的变更才会触发滚动,破坏性的变更可以被拦截。仓库中 test/extended/images/trigger/annotation.go 等触发器测试,以及 docs/proposals/image-promotion.md 中对 ImageChangeTrigger 的完整使用说明,都在验证这一"契约"语义。
5. 从镜像元数据生成新的 Pod 模板
配置生成系统可以利用镜像最新版本的元数据来生成 Pod 模板。这一场景把镜像元数据从"描述性信息"升级为"可消费的输入",支撑平台基于镜像自动生成部署配置(如oc new-app根据镜像流的元数据推断端口、环境变量并生成 DeploymentConfig)。
6. 跨多个注册表的统一视图:镜像仓库与镜像的统一虚拟视图
平台可以提供一个统一的虚拟视图,把分散在多个容器镜像仓库中的镜像仓库(repository)与镜像统一呈现。PaaS 运维人员可以预先配置来自各个注册表的镜像仓库集合,供所有用户共享;用户只需到一个地方选择镜像,而不必到互联网上四处搜寻"注册表 + 镜像仓库"的组合。
这正是 OpenShift 预置镜像流(installed image streams)的设计初衷:仓库中 examples/image-streams/image-streams-centos7.json 预置了.NET、httpd、jenkins、mariadb、mysql、nginx、nodejs、perl等镜像流,每个镜像流的每个 tag 都通过from字段指向外部真实仓库(如registry.access.redhat.com/ubi8/nodejs-16:latest、quay.io/centos7/mysql-80-centos7:centos7),实现了"一个入口、多个注册表"的统一视图。
7. 追踪被引用与"在用"的镜像,清理不再使用的镜像
镜像会随时间不断累积,其中很多已不再被任何活跃或最近的部署引用。平台需要追踪哪些镜像可能已不再相关,以便将其移除。这一场景最终落地为 OpenShift 的镜像清理(prune)能力。仓库中 test/extended/images/prune.go 就是[sig-imageregistry][Feature:ImagePrune]套件,其中为测试用户授予system:image-pruner集群角色,验证镜像 prune 对旧镜像的清理行为,测试覆盖 schema 1 与 schema 2 两种镜像清单格式。
8. 防止用户占用不合理的镜像层存储空间
这更多属于注册表(registry)的职责,但实现方式可能使它与镜像组件相关。关键约束:
- 只统计用户镜像独有的层(unique layers);
- "合理用量"应大到足以满足绝大多数用户;
- 目标是防止恶意行为者用海量垃圾镜像填满系统(拒绝服务攻击,DoS)。
这一场景提示镜像组件的配额与用量统计能力需要与注册表协作实现,是平台安全治理的一部分。
9. 指定并控制应保留的镜像历史版本数量(支撑回滚)
为了支持回滚(rollbacks),平台应能控制保留多少个旧版本。文档讨论了两类实现归属:
- 部署与镜像追踪层面:DeploymentConfig 本身支持回滚;如果系统能追踪哪些镜像近期未被使用,就可以清理旧镜像;
- 注册表层:例如为每个容器镜像仓库保留 tag 历史;限制每个仓库的 tag 数量;自动清理"之前被标记过、但现在已落后于当前版本 n 减去保留数 j"的镜像。
两种路径各有取舍:前者更贴近应用生命周期,后者更贴近存储与注册表治理。
10. 降低含安全漏洞镜像的影响面
平台管理员需要以下能力来治理存在漏洞的镜像:
- 将某个镜像标记为存在安全问题(同时需要考虑:是否允许用户标记自己拥有的镜像?);
- 阻止带安全问题的镜像被部署;
- 让用户查看自己是否正在运行基于问题镜像的负载;
- 可能的情况下,允许管理员终止所有使用镜像 x 的容器(当 x 存在严重漏洞时)。
这一场景在 OpenShift 的镜像签名(signatures)与准入控制机制中得以体现——仓库中 test/extended/images/signatures.go 验证镜像签名的处理,test/extended/images/imagestream_admission.go 则验证 ImageStream 准入校验,两者共同构成了"镜像可信度治理"的测试保障。
补充场景:限制镜像仓库的访问范围
此外文档还提到:应把镜像仓库的访问权限限制在拥有该仓库所属项目(project)的用户范围内。这一需求可能需要修改注册表规范,且并非所有注册表都支持,属于平台安全模型的延伸诉求。
镜像仓库与 ImageRepository 的同步机制
要让上述场景成立,平台必须持续掌握"外部容器镜像仓库里发生了什么"。文档给出了两条同步路径:
方案一:注册表 Webhook(registry hook)——首选方案
对于支持在镜像/tag 被推送时执行钩子(hook)的注册表,用户可配置注册表在往其容器镜像仓库新增镜像/tag 时,调用镜像组件的 Webhook。
完整工作流程如下:
- 用户向容器镜像注册表推送镜像/tag;
- 注册表向镜像组件 POST 一个 JSON 载荷,其中包含:注册表 URL、镜像仓库名称、镜像 ID、镜像元数据、新 tag;
- 镜像组件收到载荷后,将镜像仓库(ImageRepository)上的元数据覆盖值应用到该镜像的元数据(文档标注:此步当时尚未实现);
- 创建一个新的 Image 资源,并更新镜像仓库的 tag 映射表。
关于 Docker Hub 的专门说明:Docker Hub 的 Webhook 载荷只提供镜像仓库名称,仅在推送了新层时才提供镜像 ID,而且从不提供镜像元数据与 tag 信息。因此短期内很可能需要一个专门的 Docker Hub Webhook 处理器:当镜像组件的 Hub Webhook 被调用时,它需要主动从 Hub 拉取最新信息,再据此更新 Image 与 ImageRepository 信息。这一细节说明"注册表 Webhook 推送"方案虽然优雅,但不同注册表的载荷能力差异会直接影响实现复杂度。
方案二:轮询注册表(polling)
对于不支持镜像/tag 推送钩子的注册表,可以配置一个DockerRegistryImageRepositoryWatcher(Docker 注册表镜像仓库监视器)来轮询容器镜像仓库的变化:
- 它按可配置的间隔查询注册表;
- 更新 tag 列表;
- 为镜像组件中当前不存在的镜像更新其元数据。
该方案本质上是以"定时拉取"换取"实时性",实现简单、通用性强,但存在延迟与额外网络开销,适合 Webhook 不可用或注册表能力受限的场景。
两条方案的取舍可总结如下:
| 维度 | 方案一:注册表 Webhook | 方案二:定时轮询 |
|---|---|---|
| 实时性 | 推送式,接近实时 | 取决于轮询间隔,存在延迟 |
| 注册表要求 | 必须支持 push hook | 仅需支持标准查询 API |
| 载荷信息 | 依赖注册表载荷能力(如 Docker Hub 载荷残缺) | 由监视器主动拉取,信息完整 |
| 实现复杂度 | 需要针对弱载荷注册表做专门处理器 | 通用实现,配置简单 |
在 OpenShift 的最终实现中,这一同步需求由 ImageStreamImport / ImageStream 的镜像导入控制器承担——用户可以通过oc import-image手动触发,也可以通过 tag 的importPolicy.scheduled配置定时导入。仓库中 examples/image-streams/image-streams-centos7.json 的scheduled-upgrade-redeploytag 即设置了"importPolicy": {"scheduled": true},说明"周期性地检查并导入最新 digest"是真实落地的用法;而 test/extended/images/imagestreamimport.go 通过部署临时镜像注册表(ephemeral registry)验证了从不安全注册表(insecure)、被屏蔽注册表(blocked)导入镜像与仓库的完整 API 行为,包括ImportPolicy.Insecure与全局RegistrySources.InsecureRegistries / BlockedRegistries的配置路径。
从设计到落地:仓库中的镜像资源实证
ImageStream 资源结构
设计文档中的"镜像仓库(ImageRepository)"概念,在 OpenShift 中落地为ImageStream。以 examples/image-streams/image-streams-centos7.json 中预置的官方镜像流为例,其结构清晰展示了元数据与标签的建模方式:
{ "kind": "ImageStream", "apiVersion": "image.openshift.io/v1", "metadata": { "name": "nodejs", "annotations": { "openshift.io/display-name": "Node.js" } }, "spec": { "lookupPolicy": { "local": false }, "tags": [ { "name": "latest", "annotations": { "description": "Build and run Node.js applications on UBI. ...", "iconClass": "icon-nodejs", "openshift.io/display-name": "Node.js (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", "supports": "nodejs", "tags": "builder,nodejs" }, "from": { "kind": "ImageStreamTag", "name": "16-ubi8" }, "generation": null, "importPolicy": {}, "referencePolicy": { "type": "Local" } } ] }, "status": { "dockerImageRepository": "" } }各字段的语义解读:
spec.tags[].name:镜像流内的 tag 名,如latest、16-ubi8、16-ubi9;spec.tags[].annotations:镜像元数据的载体——description(面向开发者的描述)、iconClass(Web 控制台图标)、openshift.io/display-name(展示名)、supports(声明支持的运行时,如nodejs)、tags(检索分类标签)、version(版本号)。这正是设计文档中"镜像元数据 = 环境变量、暴露端口、内存与 CPU 限制等"在 OpenShift 中的实际载体形态(此处以描述性注解为主,运行参数类元数据由镜像本身的 Docker 配置承载);spec.tags[].from:镜像来源,kind可为ImageStreamTag(引用本镜像流内其他 tag,实现latest跟随主版本)或DockerImage(直接引用外部注册表镜像,如registry.access.redhat.com/ubi8/nodejs-16:latest);spec.tags[].importPolicy.scheduled:置为true时,平台周期性检查该 tag 对应的上游 digest 是否有更新(对应文档"轮询"同步思想);spec.tags[].referencePolicy.type:Local表示最终解析指向集群内部集成注册表,Source表示保留指向源注册表;spec.lookupPolicy.local:控制是否允许在 Pod 镜像名中直接使用镜像流名(本地解析)。
标签操作:oc tag与镜像引用解析
设计文档中"为镜像打 tag"这一基础操作,在 OpenShift CLI 中由oc tag承担。仓库中的 test/extended/images/oc_tag.go 验证了两种关键语义:
- 外部镜像:
oc tag --source=docker busybox busybox:latest导入外部镜像后,镜像流状态的DockerImageReference保留指向外部仓库(前缀为外部仓库名@sha256:...); - 内部镜像:本地构建的镜像被 tag 后,引用会指向集成注册表(前缀为
内部注册表地址/命名空间/镜像流名@sha256:...),且复制 tag 后新的镜像流使用自己的名字生成引用。
这说明"tag"不是简单的字符串别名,而是携带完整、可解析的镜像引用语义——与设计文档中"ImageRepository 的 tag 映射表"相互印证。
镜像导入与同步的 API 验证
设计文档讨论的"注册表 Webhook / 轮询同步",在 API 层由ImageStreamImport承载。仓库中的 test/extended/images/imagestreamimport.go 验证了以下能力:
- 通过
ImageStreamImport的Spec.Import: true与Images[].From(kind: DockerImage)触发单镜像导入; - 通过
Spec.Repository触发整个仓库(repository)的导入,对应设计文档中"统一视图"与"仓库级同步"场景; ImportPolicy.Insecure: true允许从不安全的注册表导入(自签名证书场景);- 全局配置
images.config.openshift.io/cluster的spec.registrySources.insecureRegistries/blockedRegistries可批量声明不安全/屏蔽注册表——后者正是设计文档"限制镜像仓库访问范围、降低安全影响面"场景的实现手段。
镜像修剪:清理不再使用的镜像
针对设计文档的"追踪并移除不再使用的镜像"场景,OpenShift 提供oc adm prune images与镜像清理控制器。仓库中 test/extended/images/prune.go 的测试步骤可作为操作参考:
$ oc adm policy add-cluster-role-to-user system:image-pruner <user> $ oc adm prune images测试同时覆盖 schema 1 与 schema 2 两种镜像清单格式,验证旧镜像能被正确清理,印证了"镜像随时间累积、需要按引用关系安全回收"的设计目标。
延伸:镜像晋升(Image Promotion)与部署契约的实战结合
设计文档虽然聚焦于镜像资源建模与同步,但其"部署契约"场景(场景 4)与镜像变更驱动的自动部署,在仓库另一份配套文档 docs/proposals/image-promotion.md 中有完整的实操示例,可作为理解本文主题的延伸阅读:
oc tag晋升:oc tag application/image:@sha256:02c104b application/image:qa-ready——按 digest 打 tag,实现"不可变版本晋升";oc import-image手动导入:oc import-image application --from=external:application;- 跨项目晋升:先授权
oc policy add-role-to-user edit system:serviceaccount:stage:default -n prod,再oc tag stage/sample-app:stable prod/sample-app:v0.0.1; - ImageChangeTrigger 自动部署:DeploymentConfig 声明
type: ImageChange触发器监视prod-ready这类 ImageStreamTag,tag 更新即触发滚动部署。
这套流程与设计文档中的场景 1、4、7、9 一脉相承:镜像的 tag 变化成为"部署契约"变更的信号,而平台对镜像的完整追踪使得晋升、回滚、清理、审计全部有据可依。
结语
docs/images.md这份设计文档回答了一个根本问题:为什么 OpenShift 不能只把镜像当作"拉取即用"的原子,而必须把镜像仓库、镜像、标签与元数据提升为平台资源。围绕这一核心,文档给出了从"上游变更自动重建""元数据即部署契约""跨注册表统一视图"到"漏洞治理""用量控制""版本保留与清理"等十大场景,并设计了"Webhook 推送(首选)+ 定时轮询(兜底)"的双路径同步机制。
回看仓库中的实现证据——examples/image-streams/image-streams-centos7.json 的官方镜像流配置、test/extended/images/ 下覆盖导入、打 tag、清理、签名、准入的完整测试套件,以及 docs/proposals/image-promotion.md 的晋升实战——可以确认:文档中的设计蓝图几乎全部沉淀为今天 OpenShift 镜像体系的实际能力。对希望深入理解 OpenShift 应用交付模型(ImageStream、ImageChangeTrigger、镜像导入与清理)的开发者而言,这份文档与上述源码、配置、测试共同构成了完整的知识链路。
建议的下一步探索路径:
- 阅读 docs/proposals/image-promotion.md,掌握镜像晋升的完整命令矩阵;
- 研读 test/extended/images/imagestreamimport.go 与 test/extended/images/oc_tag.go,理解
ImageStreamImport、oc tag的 API 语义与测试断言; - 以 examples/image-streams/image-streams-centos7.json 为模板,在自己的命名空间内创建镜像流并配置
importPolicy.scheduled,实践"定时同步上游镜像"的轮询模式。
- 测试
- 云原生
- 质量保障
【免费下载链接】origin
Conformance test suite for OpenShift
相关推荐
DaoCloud 公开镜像仓库同步机制解析
DaoCloud 公开镜像仓库同步机制解析 镜像同步流程揭秘 在云原生技术生态中,镜像仓库的可靠性和访问速度直接影响着开发者的工作效率。DaoCloud 提供的
镜像仓库云原生终极指南:DaoCloud公开镜像仓库同步机制解析与国内加速方案
终极指南:DaoCloud公开镜像仓库同步机制解析与国内加速方案 很多国外镜像仓库如gcr.io在国内下载速度缓慢,严重影响开发效率。DaoCloud公开镜像仓
镜像仓库云原生DaoCloud 公共镜像仓库同步机制解析
DaoCloud 公共镜像仓库同步机制解析 DaoCloud 的 public image mirror 项目提供了一个高效的容器镜像同步解决方案,通过自动化流
镜像仓库云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考