news 2026/10/5 10:22:40

OpenEBS Helm Chart 容器镜像清单(helm.sh/images 注解)设计与自动化实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenEBS Helm Chart 容器镜像清单(helm.sh/images 注解)设计与自动化实现解析
  • 云原生
  • CLI

【免费下载链接】openebs

A popular & widely deployed Open Source Container Native Storage platform for Stateful Persistent Applications on Kubernetes.

项目地址:https://gitcode.com/gh_mirrors/op/openebs
点击查看免费下载

本文依据 OpenEBS 仓库中的设计文档 OEP 3796:Expose OpenEBS HelmChart's Container Images(状态为 implemented)编写。该提案为 OpenEBS 伞形 Helm Chart 引入了一份单一事实来源的容器镜像清单,并通过正则提取、Chart 注解存储与自动化脚本,使清单能够随 Chart 演进持续保持最新。读者读完本文后,将掌握离线(air-gapped)部署前批量获取镜像、用helm template+ 正则全量枚举 Chart 镜像、以及借助仓库脚本完成清单生成/回写/集群校验的完整实战方法。

一、设计背景与动机:为什么需要一份"镜像清单"

OpenEBS 是一个以 Helm 伞形 Chart 形式发布的云原生存储平台。打开仓库根目录下的 charts/Chart.yaml 可以看到,这个伞形 Chart 通过dependencies聚合了 8 个子 Chart:

  • openebs-crds(CRD 安装)
  • loki、alloy(可观测性,来自 Grafana Helm 仓库)
  • localpv-provisioner(Local PV Hostpath 引擎)
  • zfs-localpv、lvm-localpv、rawfile-localpv(Local PV 存储引擎)
  • mayastor(Replicated PV 复制引擎)

每个子 Chart 内部又依赖 CSI sidecar(csi-provisioner、csi-attacher、csi-resizer等)、etcd、NATS 消息总线、MinIO 对象存储等一系列镜像。结果是:部署 OpenEBS 到底需要拉取哪些容器镜像,用户和开发者很难凭肉眼从模板树中理清。

设计文档给出的动机非常直接:提供一个清晰、完整的"每个 OpenEBS Chart 所需全部容器镜像"清单,从而减少用户查找、拉取镜像的时间与精力,尤其对需要预先下载镜像的离线(air-gapped)环境至关重要。文档还指出,另一个 OEP 可以在本提案之上构建"可一键下载的镜像 tar 包"。

1.1 目标(Goals)

  • 为每个 OpenEBS Chart 提供一份详细的容器镜像清单;
  • 必须建立自动化机制,确保清单随 Chart 的任何变更保持同步更新。

1.2 非目标(Non-Goals)

  • 不创建所有镜像的可下载打包(留给后续 OEP 处理);
  • 不负责构建或维护容器镜像;
  • 不做"镜像与具体功能"的关联映射——也就是说,清单是全量的,可能包含某个用户未启用的特性所对应的镜像(这是刻意为之,见"风险"一节)。

二、总体方案:把镜像清单写进 Chart 的 annotations

提案的核心设计是:在每个 OpenEBS Chart 的Chart.yaml(或doc.yaml)中增加一个annotations字段,其中存放该 Chart 所需的全部容器镜像列表;该列表自动生成并随 Chart 变更自动更新。同时,每个 OpenEBS Chart 会复用其依赖的子 Chart 中已声明的注解,从而把"生成镜像清单"这件最可靠的工作下放到最了解自身的那个 Chart。

文档给出了一个示意示例(以 Mayastor 为例,注意其中版本号仅为示意,当前仓库 Chart.yaml 中的实际版本见后文):

project: name: OpenEBS Mayastor annotations: images: | - name: mayastor-agent-core image: docker.io/openebs/mayastor-agent-core:v2.7.1 - name: linux-utils image: docker.io/openebs/linux-utils:4.1.0 - name: promtail image: docker.io/grafana/promtail:2.8.3

在仓库的当前实现中,注解键名落地为helm.sh/images,块标量(|)内是若干- name: <组件名>/image: <完整镜像地址>键值对(见 charts/Chart.yaml)。

2.1 用户故事

  • Story 1:作为用户,我希望 OpenEBS Chart 有一个容器镜像的单一事实来源,以便轻松拉取部署所需镜像。
  • Story 2:作为用户,我希望这个单一事实来源可以被自动化消费(例如脚本循环拉取、镜像仓库同步),而无需人工逐条翻查模板。

三、实现细节:可发现镜像、暴露镜像与不可发现镜像

文档将镜像划分为两类,处理策略截然不同。

3.1 可发现镜像(Discoverable images):正则 + helm template 枚举

凡是在 Helm 模板中以image:键出现的镜像,都可以通过对 Chart 执行模板化(helm template)后扫描输出得到。为此提案给出了一条正则表达式:

^[ \t]*image: \K(.*:.*)$

逐段拆解如下:

片段含义
^行首断言,匹配必须从行首开始
[ \t]*匹配零个或多个空格或制表符(即 YAML 的缩进),贪婪匹配
image:字面匹配image:(区分大小写)
\K重置匹配报告的起点:此前消耗的字符不再计入最终匹配结果(PCRE 特性)
(.*:.*)捕获组:任意字符 + 冒号 + 任意字符,确保抓到的值含冒号(即<registry>/<repo>:<tag>形态)
$行尾断言

配合helm template与grep(-P启用 PCRE、-o只输出匹配部分)即可提取出全部镜像:

helm template . --set "$ENABLE_ALL_FEATURES" | grep -Po "^[ \t]*image: \K(.*:.*)$" | tr -d \"

注意:此处必须开启全部特性(enable all features),才能保证拿到一份完整、无遗漏的镜像清单——这正是文档对"全量清单"定位的直接体现。

3.2 仓库中的等价实现

设计文档的这条命令在仓库中已经被完整落地到 scripts/helm/images.sh 的generate流程里,且分成了两条互补的扫描:

# ① 通过 install.sh 的 template 模式,打开全部本地引擎与复制引擎 $SCRIPT_DIR/install.sh --locals --replicated --template --helm "--kubeconfig $CHART_DIR/fake" \ | grep -Po "^[ \t]*image: \K(.*:.*)$" | tr -d \" | LC_ALL=C sort | uniq # ② 对伞形 Chart 本身执行 helm template,并显式开启分析/遥测相关特性 helm template "$CHART_DIR" \ --set "mayastor.eventing.enabled=true,mayastor.obs.callhome.enabled=true,mayastor.obs.callhome.sendReport=true" \ --kubeconfig "$CHART_DIR/fake" --is-upgrade \ | grep -Po "^[ \t]*image: \K(.*:.*)$" | tr -d \" | LC_ALL=C sort | uniq

其中ENABLE_ALL_FEATURES在脚本中对应变量ENABLE_ANALYTICS(见 images.sh),即把 Mayastor 的 eventing 与 callhome 上报功能强制打开;而install.sh --locals --replicated会通过 scripts/helm/install.sh 中的参数拼装逻辑把engines.local.*与engines.replicated.mayastor.enabled全部置为true(对应 values.yaml 中的引擎开关)。tr -d \"去掉 YAML 中可能出现的引号,sort | uniq去重后得到干净的去重列表。

3.3 暴露镜像(Expose images):写回 annotations

拿到镜像列表后,将其作为 annotations 写入 Chart。当前 charts/Chart.yaml 中的helm.sh/images注解实际列出了约 50 个镜像条目,按用途大致可分为:

类别代表条目(当前仓库实际值)
可观测性docker.io/grafana/loki:3.4.2、docker.io/grafana/alloy:v1.8.1、docker.io/kiwigrid/k8s-sidecar:1.30.2、quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0
消息总线(NATS)docker.io/nats:2.9.17-alpine、docker.io/natsio/nats-box:0.13.8、docker.io/natsio/nats-server-config-reloader:0.10.1、docker.io/natsio/prometheus-nats-exporter:0.11.0
基础设施/工具docker.io/openebs/etcd:3.6.4-debian-12-r0、docker.io/openebs/kubectl:1.25.15、docker.io/openebs/linux-utils:4.6.0、docker.io/openebs/alpine-bash:4.6.0、docker.io/openebs/alpine-sh:4.6.0、docker.io/openebs/mc:*、docker.io/openebs/minio:*
Local PV 引擎驱动docker.io/openebs/provisioner-localpv:4.6.0、docker.io/openebs/provisioner-localpv:4.7.0-develop、docker.io/openebs/zfs-driver:2.12.0-develop、docker.io/openebs/lvm-driver:1.11.0-develop、docker.io/openebs/rawfile-localpv:v0.15.1
Replicated PV Mayastor 系列docker.io/openebs/mayastor-agent-core:develop等 12 个mayastor-*组件(agent/api-rest/csi/io-engine/eventing/obs/operator-diskpool 等)
升级任务docker.io/openebs/openebs-upgrade-job:v4.7.0-develop
CSI sidecarregistry.k8s.io/sig-storage/csi-attacher:v4.8.1、csi-provisioner(v5.2.0 / v6.1.0 / v6.3.0 三个版本)、csi-resizer(v1.13.2 / v2.0.0 / v2.2.1)、csi-node-driver-registrar(v2.13.0 / v2.17.0)、csi-snapshotter(v8.2.0 / v8.6.0)、snapshot-controller(v8.2.0 / v8.6.0)

可以观察到:同一个组件名会出现多个版本条目(如provisioner-localpv同时有 4.6.0 与 4.7.0-develop,csi-provisioner有三个版本)。这是各存储引擎子 Chart 各自声明依赖的 CSI sidecar 版本不同所致——伞形 Chart 把依赖子 Chart 的注解原样汇总,恰好印证了文档"每个 Chart 使用其所依赖 Chart 的注解"的设计意图。

3.4 不可发现/运行时镜像(Non-Discoverable / Runtime images)

并非所有镜像都能从helm template中发现。凡是在运行时才被动态部署的 Pod/Job(而非 Helm 渲染的静态资源),其镜像就无法通过扫描模板获得,文档明确指出这类镜像需要人工查找并"硬编码"进清单。仓库中恰好有两个典型实例:

实例一:LocalPV 的 helper pod(初始化容器)

localpv-provisioner在为 PVC 准备文件系统时,会按需拉起一个 init pod(helper pod)。该镜像不会出现在 helm 渲染结果中,因此 images.sh 专门实现了helm_localpv_prov_helper_image():从子 Chart 的helperPod.image.registry / repository / tag取值(支持helperPod.image.registry与global.imageRegistry两级回退),拼出完整镜像地址并追加进清单(images.sh)。对应的 values 配置见 charts/values.yaml。

实例二:openebs-upgrade-job(升级任务)

OpenEBS 的升级任务由kubectl openebs upgrade插件在升级时按需创建 Job,而非随 Chart 常驻部署。从插件源码 plugin/src/cli_utils/upgrade/mod.rs 可以看到镜像地址是在运行时拼装的:{image_registry}/{namespace}/openebs-upgrade-job:{image_tag}。为此,images.sh 中的upgrade_job_image()以 callhome 镜像的 registry/namespace 为默认来源(可用--openebs-registry/--openebs-namespace覆盖),结合 Chart 的.version生成openebs-upgrade-job:vX.Y.Z并写入镜像清单(images.sh)。脚本注释也说明了当前阶段升级任务尚未集成进 Chart,故需从清单中单独提取。

此外,伞形 Chart 自身静态渲染的资源(如 charts/templates/pre-upgrade-hook.yaml 中引用的openebs/kubectl:1.25.15升级钩子 Job)属于可发现镜像,会由helm template扫描覆盖。

四、仓库中的自动化闭环:generate / patch / verify 三命令

设计文档的"目标"章节要求"自动化机制保证清单与 Chart 同步",这一要求在 scripts/helm/images.sh 中落地为一个完整的 CI 可用闭环,脚本提供三个子命令:

4.1generate:从 Chart 生成镜像清单

三步流水线(images.sh):

  1. 收集依赖注解:遍历Chart.yaml中所有带repository的依赖,用helm show chart读取各自.annotations."helm.sh/images"中的镜像(helm_dep_collect_images);
  2. 全量扫描模板:依次执行install.sh --locals --replicated --template与helm template --set "$ENABLE_ANALYTICS" --is-upgrade,用上文正则提取image:值;
  3. 补充按需镜像:调用helm_on_demand_images追加 helper pod 镜像与openebs-upgrade-job镜像。

最终sort | uniq后写入 charts/images.txt(每行一个完整镜像地址)。配合--exit-code选项,脚本会执行git diff --exit-code,一旦清单与 Chart 不同步即返回非零退出码——这正是文档"自动化测试保证清单保持最新"(见"缓解措施"一节)的具体实现,可无缝接入 CI。

4.2patch:把清单回写为 Chart 注解

patch子命令将images.txt的每一行解析出组件名(按/与:切分取倒数第二段),构造{ "name": ..., "image": ... }的 JSON 数组,通过yq写回Chart.yaml的.annotations."helm.sh/images",并确保其保持块标量(|)格式(images.sh)。这样charts/Chart.yaml注解与charts/images.txt互为可再生的同一份数据。

4.3verify:在真实集群上校验清单

verify子命令把清单与实际部署做交叉验证(images.sh):

# 从 openebs 命名空间收集所有 Pod 的容器与 initContainer 镜像 kubectl -n openebs get pods -o json \ | jq -r '.items[].spec.containers[]?.image, .items[].spec.initContainers[]?.image' \ | LC_ALL=C sort | uniq

随后将 live 镜像与images.txt、Chart.yaml注解逐条比对,任何"集群在用但清单缺失"的镜像都会触发log_fatal报错;脚本还内置了一个 sanity check(live 镜像少于 5 条视为异常),防止在空命名空间上误判通过。

这与设计文档 Test Plan 中提出的思路完全对应:可以在集群上用镜像白名单(只允许清单内的镜像被拉取)或禁用镜像拉取 + 预加载的方式,验证清单的正确性与完整性。

五、测试计划与风险缓解

5.1 测试计划(Test Plan)

文档要求随项目发展持续验证镜像清单的正确性与时效性,验证可在真实集群上执行,两种典型做法:

  • 镜像白名单:配置运行时只允许清单内的镜像被拉取,一旦部署请求了清单之外的镜像即失败,从而暴露清单缺漏;
  • 禁用镜像拉取 + 预加载:把所有镜像预先加载进集群并禁止在线拉取,模拟离线环境,验证清单是否足以支撑完整部署。

上述两种方式在仓库中均有可用的工具基础:verify子命令提供了 live 镜像与清单的自动比对,scripts/staging/mirror-images.sh 等 staging 脚本也可用于镜像的同步与校验场景。

5.2 风险与缓解(Risks and Mitigations)

文档明确列出的风险包括:

  • 可能收录非必需镜像:因为生成清单时启用了全部特性,清单会包含某些用户配置下用不到的镜像;由于镜像随用户启用的功能而异,这个问题难以从清单层面根除(这也正是 Non-Goals 中"不做镜像-功能关联映射"的原因);
  • 不可发现镜像必须人工维护:运行时镜像无法自动扫描,必须手动加入清单。

对应的缓解措施是:尽可能自动化(仓库已通过 generate/patch/verify 三命令实现),并使用自动化测试保证清单持续更新(--exit-code的 CI 接入即为此设计)。

六、如何消费这份清单:离线部署与镜像预拉取

对于读者而言,消费这份清单的最直接场景是离线(air-gapped)部署:

  1. 查看清单:完整的镜像地址列表在 charts/images.txt(每行一个);带组件名/镜像地址的注解形式在 charts/Chart.yaml。
  2. 批量拉取:逐行docker pull或接入镜像同步工具将镜像导入离线镜像仓库,即可在无外网集群上完成 OpenEBS 部署。
  3. 按需筛选:需要注意清单是全量的——若只部署部分引擎(例如在 values.yaml 中关闭engines.replicated.mayastor.enabled,或在安装时加--set engines.replicated.mayastor.enabled=false,见 charts/README.md 的安装示例),清单仍会包含 Mayastor 系列镜像,请结合自己的启用项决定是否全部预拉。
  4. 自定义镜像仓库:清单记录的是默认 registry(docker.io、registry.k8s.io、quay.io等)。若通过global.imageRegistry全局覆盖镜像仓库(charts/values.yaml),实际拉取地址会与清单不同,预拉取时应换算为覆盖后的地址。

七、局限性与替代方案

文档坦诚地列出了该方案的代价与备选:

  • Drawback:在无法全自动生成清单的场景下(即存在不可发现镜像时),需要额外的维护精力来保持清单更新;
  • Alternatives:维持现状——不提供集中清单,由用户在部署时手动逐个发现所需容器镜像。这显然更耗时且更容易出错,也正是本提案被采纳(状态为 implemented)的原因。

八、实施历史与展望

按 OEP 流程,文档经历了Summary与Motivation合并以表明 owner 接受提案的阶段;当前仓库中的helm.sh/images注解、images.txt清单与images.sh自动化脚本即为该设计的最终落地形态。正如文档开篇所展望的,这份"单一事实来源"的镜像清单还可以作为后续 OEP 的基础,用于构建"包含全部所需容器镜像、可一键下载的 tar 包",进一步降低离线交付 OpenEBS 的门槛。


延伸阅读(均为仓库内文件):

  • 设计文档原文:designs/helm-charts/expose-container-images.md
  • 镜像清单(纯镜像地址):charts/images.txt
  • 镜像注解(名称+地址):charts/Chart.yaml
  • 自动化脚本(generate/patch/verify):scripts/helm/images.sh
  • 模板化安装脚本(全特性开启逻辑):scripts/helm/install.sh
  • 引擎开关与镜像相关 values:charts/values.yaml
  • 升级任务镜像的运行时拼装:plugin/src/cli_utils/upgrade/mod.rs
  • 云原生
  • CLI

【免费下载链接】openebs

A popular & widely deployed Open Source Container Native Storage platform for Stateful Persistent Applications on Kubernetes.

项目地址:https://gitcode.com/gh_mirrors/op/openebs
点击查看免费下载
上一篇:Memray transform 子命令完全指南:将内存追踪文件转换为 gprof2dot、CSV 与 speedscope 格式
下一篇:在 Flet 应用中集成地理定位:flet-geolocator 扩展包完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 10:21:49

Chart MCP Server MCP 服务说明文档

1. 服务概述一句话简介&#xff1a;历史图表模式搜索引擎MCP服务器&#xff0c;2400万模式嵌入&#xff0c;10年历史数据&#xff0c;15000股票服务名称&#xff1a;Chart MCP Server (Chart Library)版本号&#xff1a;1.1.1开发者/提供方&#xff1a;grahammccain协议类型&am…

作者头像 李华
网站建设 2026/10/5 10:20:42

最弱模型竟成顶级AI解码器

AI蒸馏&#xff0c;实锤了&#xff1f;2026年&#xff0c;硅谷最敏感的一桩悬案&#xff0c;就是AI蒸馏。每当, 一款新模型, 突然变强, 跑分, 直追GPT, 回答, 又带着的味道, 同一个问题, 就会开始, 在业内游荡。所有人都在怀疑&#xff0c;却没有人能把证据拍在桌上。直到今天&…

作者头像 李华
网站建设 2026/10/5 10:18:39

快速上手LangGraph:5分钟搭建能记住状态的AI智能体编排系统

快速上手LangGraph&#xff1a;5分钟搭建能记住状态的AI智能体编排系统 【免费下载链接】langgraph Build resilient agents. 项目地址: https://gitcode.com/GitHub_Trending/la/langgraph 做过Agent的人都踩过同一个坑&#xff1a;LLM跑着跑着就"失忆"了&am…

作者头像 李华