深入解析 Bitnami Common Library Chart:OpenReplay Helm 依赖中的通用模板与函数库
可观测性开发工具前端后端【免费下载链接】openreplaySession replay, cobrowsing and product analytics you can self-host. Best for reproducing issues and iterating on your product.项目地址https://gitcode.com/gh_mirrors/op/openreplay点击查看免费下载导读本文围绕 scripts/helmcharts/databases/charts/postgresql/charts/common/README.md 展开系统讲解 Bitnami Common Library Chart0.8.1——一个不可独立部署、专门为其他 Helm Chart 提供通用模板函数template helpers的「库图表」Library Chart。在本仓库中它作为 OpenReplay 数据库部署方案所依赖的 PostgreSQL Helm Chart 的子图表出现见 requirements.yaml被 PostgreSQL 的各个模板文件高频调用。读完本文你将掌握common.names.*、common.labels.*、common.images.*、common.secrets.*、common.validations.*等十余组 helper 的用法、入参结构及其底层实现能够在自己的 Helm Chart 中直接复用这套成熟的最佳实践。什么是 Helm Library Chart为什么需要它Helm 官方支持一种特殊的图表类型——Library Chart它不部署任何 Kubernetes 资源只提供可供其他 Chart 引用的模板函数。Common Chart 正是这类图表的典型代表查看其 Chart.yaml 可知它的description明确写着 A Library Helm Chart for grouping common logic between bitnami charts. This chart is not deployable by itself.version为0.8.1类型为apiVersion: v1的经典 Chart。它的价值在于把跨 Chart 反复出现的逻辑命名规范、标签生成、镜像拼接、Secret 引用、参数校验、亲和性配置等收敛到一处让业务 Chart如本仓库中的 PostgreSQL Chart的模板保持精简且行为一致。在 OpenReplay 仓库中PostgreSQL 图表的所有模板文件如 secrets.yaml、statefulset.yaml、NOTES.txt 等都通过include common.xxx调用了这些 helper。快速接入TL;DR在任意业务 Chart 的requirements.yamlHelm 2 风格或Chart.yaml的dependencies字段Helm 3 风格中声明依赖然后更新依赖即可。原文档给出的声明方式是dependencies: - name: common version: 0.x.x repository: https://charts.bitnami.com/bitnami随后执行$ helm dependency update本仓库中 PostgreSQL 图表的 requirements.yaml 即完全遵循了这一模式并把 common 图表以子图表形式落地到charts/common目录。接入之后就可以在任何模板文件中直接使用 helper例如原文档展示的 ConfigMap 示例apiVersion: v1 kind: ConfigMap metadata: name: {{ include common.names.fullname . }} data: myvalue: Hello Worldcommon.names.fullname会按照「release 名 chart 名」的规则生成资源名细节见下文 Names 一节。前置条件Kubernetes 1.12Helm 2.12 或 Helm 3.0-beta3注意这里的版本要求是针对使用该库图表的集群与 Helm 客户端。从本仓库携带的0.8.1版本源码看capabilities 类 helper 对集群 API 版本的判定以 1.14 为分界线详见下文因此若目标集群版本过低部分模板可能无法获得最合适的 apiVersion。Helper 全景11 类模板函数原文档以表格形式罗列了全部 helper 及其期望输入。下表先给出全景随后逐一结合 templates 目录下的实现源码展开讲解读者也可对照这些.tpl文件核对实现细节。分类Helper说明期望输入Affinitiescommon.affinities.node.soft软节点亲和nodeAffinitydict key FOO values (list BAR BAZ)Affinitiescommon.affinities.node.hard硬节点亲和dict key FOO values (list BAR BAZ)Affinitiescommon.affinities.pod.soft软 Pod 亲和/反亲和dict component FOO context $Affinitiescommon.affinities.pod.hard硬 Pod 亲和/反亲和dict component FOO context $Capabilitiescommon.capabilities.deployment.apiVersion返回 Deployment 的合适 apiVersion.Chart 上下文Capabilitiescommon.capabilities.statefulset.apiVersion返回 StatefulSet 的合适 apiVersion.Chart 上下文Capabilitiescommon.capabilities.ingress.apiVersion返回 Ingress 的合适 apiVersion.Chart 上下文Errorscommon.errors.upgrade.passwords.empty升级时校验必填密码为空则中断升级dict validationErrors (list $e00 $e01) context $Imagescommon.images.image返回完整镜像名dict imageRoot .Values... global $见 ImageRootImagescommon.images.pullSecrets返回合并后的镜像拉取 Secret 列表dict images (list ...) global .Values.globalLabelscommon.labels.standard生成 Kubernetes 标准标签.Chart 上下文Labelscommon.labels.matchLabels生成 selector 用的 matchLabels.Chart 上下文Namescommon.names.name展开 chart 名支持nameOverride.Chart 上下文Namescommon.names.fullname生成完整限定应用名.Chart 上下文Namescommon.names.chartchart 名加版本.Chart 上下文Secretscommon.secrets.name生成 Secret 名称dict existingSecret ... defaultNameSuffix ... context $Secretscommon.secrets.key生成 Secret 键名支持 keyMappingdict existingSecret ... key keyNameStoragecommon.storage.class返回合适的存储类声明dict persistence ... global $见 PersistenceTplValuescommon.tplvalues.render渲染包含模板的值dict value ... context $Utilscommon.utils.fieldToEnvVar由字段名构造环境变量名dict field my-passwordUtilscommon.utils.secret.getvalue输出从 Secret 取值的 kubectl 命令dict secret ... field ... context $Utilscommon.utils.getValueFromKey按 key 路径从.Values取值dict key path.to.key context $Validationscommon.validations.values.single.empty校验单个值非空dict valueKey ... secret ... field ... context $Validationscommon.validations.values.multiple.empty批量校验多个值非空dict required (list ...) context $Validationscommon.validations.values.mariadb.passwords校验 MariaDB 密码非空dict secret ... subchart ... context $Validationscommon.validations.values.postgresql.passwords校验 PostgreSQL 密码非空dict secret ... subchart ... context $Warningscommon.warnings.rollingTag对滚动 tag 给出警告ImageRoot说明原文档 Storage 分类的表格中 helper 标识符误写为common.affinities.node.soft对照 _storage.tpl 源码实际定义的是common.storage.class本文按源码为准。Names 与 Labels资源命名与标签规范命名三兄弟_names.tpl 实现了三个命名 helpercommon.names.name返回 chart 名支持通过.Values.nameOverride覆盖结果会trunc 63截断并去掉尾部-。common.names.chart返回chart名-版本格式如postgresql-9.6.11用于helm.sh/chart标签版本中的会被替换为_replace _同样截断 63 字符。common.names.fullname生成「完整限定应用名」。规则为若设置了fullnameOverride直接用否则优先取nameOverride或 chart 名若 release 名已包含该名字则直接使用 release 名否则拼接为release-chart。所有分支统一trunc 63 | trimSuffix -——因为 Kubernetes 的 DNS 命名规范把名称长度限制在 63 字符内源码注释中对此有明确说明。标准标签与 matchLabels_labels.tpl 提供common.labels.standard输出 Kubernetes 推荐的四组标准标签app.kubernetes.io/name: chart名 helm.sh/chart: chart名-版本 app.kubernetes.io/instance: release名 app.kubernetes.io/managed-by: release服务common.labels.matchLabels只输出app.kubernetes.io/name与app.kubernetes.io/instance两项专门用于deploy.spec.selector.matchLabels和svc.spec.selector等不可动态变更的 selector 场景selector 一旦创建不可修改因此不能包含helm.sh/chart这类随版本变化的标签。在本仓库的 PostgreSQL 图表中common.labels.standard被广泛用于各类资源的 metadata.labels例如 secrets.yaml 中{{- include common.labels.standard . | nindent 4 }}的用法。Capabilities按集群版本选择 API 版本_capabilities.tpl 通过semverCompare 1.14-0 .Capabilities.KubeVersion.GitVersion判断集群版本HelperKubernetes 1.14Kubernetes ≥ 1.14common.capabilities.deployment.apiVersionextensions/v1beta1apps/v1common.capabilities.statefulset.apiVersionapps/v1beta1apps/v1common.capabilities.ingress.apiVersionextensions/v1beta1networking.k8s.io/v1beta1这是典型的兼容性适配模式不同版本的 Kubernetes 对资源的 API 组/版本要求不同Deployment/StatefulSet/Ingress 都经历过从extensions/v1beta1/apps/v1beta1到apps/v1/networking.k8s.io的演进。业务 Chart 在写apiVersion:时只需要{{ include common.capabilities.deployment.apiVersion . }}即可由库图表自动适配集群实际版本。Affinities软硬亲和性模板_affinities.tpl 提供节点亲和nodeAffinity与 Pod 亲和/反亲和podAffinity/podAntiAffinity两类每类分 soft / hard 两种强度softpreferredDuringSchedulingIgnoredDuringExecution调度器优先满足但不强制weight: 1。hardrequiredDuringSchedulingIgnoredDuringExecution调度器必须满足否则 Pod 无法调度。节点亲和输入为dict key FOO values (list BAR BAZ)生成matchExpressions中key: FOO、operator: In、values: [BAR, BAZ]的表达式。Pod 亲和输入为dict component FOO context $会借助common.labels.matchLabels生成 selector限定在 release 所在 namespace.context.Release.NamespacetopologyKey为kubernetes.io/hostnamecomponent可选非空时会追加app.kubernetes.io/component标签。此外还提供按typesoft/hard分发的总入口common.affinities.nodes与common.affinities.pods便于在 values 中通过一个字符串开关控制调度策略。Images镜像拼接与拉取凭据合并_images.tpl 包含两个核心 helpercommon.images.image输出完整的registry/repository:tag镜像名。实现上优先读取imageRoot.registry但如果传入了global且global.imageRegistry非空则用全局 registry 覆盖——这是为了让用户在顶层 values 中统一设置私有镜像仓库地址所有子图表自动跟随。common.images.pullSecrets合并全局global.imagePullSecrets与每个镜像自身的pullSecrets去重后输出imagePullSecrets:列表若最终列表为空则不输出任何内容if (not (empty $pullSecrets))守卫。这种「全局覆盖 局部细化」的设计在 OpenReplay 这类需要为 PostgreSQL、Kafka、Redis 等多个有状态服务统一配置私有仓库的环境中非常实用。Secrets复用已有 Secret 与键映射_secrets.tpl 解决一个常见痛点用户往往希望把自己预先创建好的 Secret 注入部署而不是让 Chart 自动生成。common.secrets.name默认返回common.names.fullname的结果若传入defaultNameSuffix则追加后缀用于同一部署中存在多个 Secret 的场景若传入了existingSecret则直接用其.name。common.secrets.key默认返回传入的key若existingSecret提供了keyMapping则通过index .existingSecret.keyMapping $.key把「预期键名」映射到「已有 Secret 中的真实键名」。原文档给出了完整的三段式示例Secret 模板、Deployment 的secretKeyRef引用、values 中的existingSecret配置是理解该机制最直接的素材# templates/secret.yaml --- apiVersion: v1 kind: Secret metadata: name: {{ include common.names.fullname . }} labels: app: {{ include common.names.fullname . }} type: Opaque data: password: {{ .Values.password | b64enc | quote }} # templates/dpl.yaml --- ... env: - name: PASSWORD valueFrom: secretKeyRef: name: {{ include common.secrets.name (dict existingSecret .Values.existingSecret context $) }} key: {{ include common.secrets.key (dict existingSecret .Values.existingSecret key password) }} ... # values.yaml --- name: mySecret keyMapping: password: myPasswordKey当用户提供existingSecret时Deployment 会引用用户 Secret 中名为myPasswordKey的键来填充PASSWORD环境变量未提供时则回退到 Chart 自建的 Secret 与键名。Storage存储类声明_storage.tpl 中的common.storage.class处理持久化存储类优先用persistence.storageClass其次用global.storageClass覆盖当值为-时输出storageClassName: 显式禁用动态供给强制使用默认存储类绑定已有 PV其他非空值输出storageClassName: name值为空则完全不输出 storageClassName交给集群默认行为。配合原文档的 Persistence schema见下文可以精确控制有状态组件的存储行为。TplValues 与 Utils通用工具函数common.tplvalues.render_tplvalues.tpl 允许 values 中存放「含模板语法」的字符串并在渲染阶段求值字符串值直接用tpl渲染非字符串如 map/list先toYaml再交给tpl。它让用户可以在 values 里写{{ .Release.Namespace }}之类的表达式例如 PostgreSQL 图表的 secrets.yaml 就用它渲染commonAnnotations。common.utils.fieldToEnvVar_utils.tpl 中的fieldToEnvVar把my-password这类字段名转换为环境变量名MY_PASSWORD按-分割、逐段大写、用_连接。common.utils.secret.getvaluesecret.getvalue生成一条从 Kubernetes Secret 中取值的命令用于把 Secret 值导出为环境变量export FIELD$(kubectl get secret --namespace namespace secret -o jsonpath{.data.field} | base64 --decode)common.utils.getValueFromKeygetValueFromKey按点分路径如auth.password从.context.Values逐层取值任一层取不到时调用fail抛出 please review the entire path of xxx exists in values 错误——这是后续所有校验类 helper 的取值基础设施。Validations 与 Errors安装/升级时的参数校验非空校验common.validations.values.single.empty取valueKey指向的值为空时生成一条错误消息若同时提供了secret与field还会附上「如何从 Secret 取当前值」的 kubectl 命令指导用户用--set补上参数。common.validations.values.multiple.empty遍历required列表对每个配置项调用 single 校验批量汇总错误。原文档给出了在 NOTES.txt 中的完整用法先构造多个validateValueConfdict包含valueKey、secret、field再统一交给multiple.empty处理。当值确实为空时helm install输出的提示形如$ helm install test mychart --set path.to.value00,path.to.value01 path.to.value00 must not be empty, please add --set path.to.value00$PASSWORD_00 to the command. To get the current value: export PASSWORD_00$(kubectl get secret --namespace default secretName -o jsonpath{.data.password-00} | base64 --decode) path.to.value01 must not be empty, please add --set path.to.value01$PASSWORD_01 to the command. To get the current value: export PASSWORD_01$(kubectl get secret --namespace default secretName -o jsonpath{.data.password-01} | base64 --decode)数据库密码专项校验_validations.tpl 还内置了两套数据库专项校验common.validations.values.mariadb.passwords在未提供existingSecret且 MariaDB 启用时依据用户名、架构replication时追加复制密码动态构造必填密码列表。common.validations.values.postgresql.passwords逻辑类似校验postgresqlPassword并支持replication.enabled时的replication.password。两者都通过subchart布尔参数区分「独立图表」与「子图表」两种取值上下文取值路径是否带postgresql./mariadb.前缀并且 PostgreSQL 版本还支持从global.postgresql读取全局覆盖值common.postgresql.values.use.global等辅助函数。升级阻断common.errors.upgrade.passwords.empty见 _errors.tpl把validationErrors拼接起来仅在Release.IsUpgrade为真且错误列表非空时调用fail抛出PASSWORDS ERROR: you must provide your current passwords when upgrade the release...从而在helm upgrade时强制要求用户显式提供已有密码避免误用新生成密码导致数据访问失败。Warningsrolling tag 警告_warnings.tpl 的common.warnings.rollingTag检测镜像 tag当 repository 包含bitnami/且 tag 不是形如-r数字结尾或包含sha256:的固定版本时输出警告「Rolling tag detected ... strongly recommended to avoid using rolling tags in a production environment」。它提醒使用者latest这类滚动 tag 在生产环境不可复现、不可回滚应改用带版本后缀的具体 tag。特殊输入结构Special input schemas以下四种 dict 结构是多个 helper 共用的「输入契约」原文档以 YAML schema 形式给出了完整字段定义。ImageRoot镜像根配置registry: type: string description: Docker registry where the image is located example: docker.io repository: type: string description: Repository and image name example: bitnami/nginx tag: type: string description: image tag example: 1.16.1-debian-10-r63 pullPolicy: type: string description: Specify a imagePullPolicy. Defaults to Always if image tag is latest, else set to IfNotPresent pullSecrets: type: array items: type: string description: Optionally specify an array of imagePullSecrets. debug: type: boolean description: Set to true if you would like to see extra information on logs example: false ## An instance would be: # registry: docker.io # repository: bitnami/nginx # tag: 1.16.1-debian-10-r63 # pullPolicy: IfNotPresent # debug: false字段含义registry为镜像仓库地址如docker.iorepository为仓库与镜像名如bitnami/nginxtag为镜像标签pullPolicy默认规则是 tag 为latest时取Always、否则取IfNotPresentpullSecrets为可选的镜像拉取 Secret 数组debug控制是否输出额外日志。common.images.image与common.warnings.rollingTag都以它作为输入。Persistence持久化配置enabled: type: boolean description: Whether enable persistence. example: true storageClass: type: string description: Ghost data Persistent Volume Storage Class, If set to -, storageClassName: which disables dynamic provisioning. example: - accessMode: type: string description: Access mode for the Persistent Volume Storage. example: ReadWriteOnce size: type: string description: Size the Persistent Volume Storage. example: 8Gi path: type: string description: Path to be persisted. example: /bitnami ## An instance would be: # enabled: true # storageClass: - # accessMode: ReadWriteOnce # size: 8Gi # path: /bitnami其中storageClass设为-会输出storageClassName: 以禁用动态供给这正是common.storage.class的处理逻辑accessMode常见取ReadWriteOnce/ReadWriteManysize使用 Kubernetes 容量语法如8Gipath为容器内挂载路径Bitnami 镜像惯例为/bitnami。ExistingSecret已有 Secret 引用name: type: string description: Name of the existing secret. example: mySecret keyMapping: description: Mapping between the expected key name and the name of the key in the existing secret. type: object ## An instance would be: # name: mySecret # keyMapping: # password: myPasswordKey即「期望键名 → 已有 Secret 中的真实键名」映射由common.secrets.name/common.secrets.key消费典型用法见上文 Secrets 一节的完整示例。ValidateValue校验配置项ValidateValue 本身不是 helper而是传给校验类 helper 的配置 dict字段为valueKey必填values.yaml 中待校验值的路径如mysql.passwordsecret可选存放该值的 Secret 名称如mysql-passwords-secretfield可选Secret data 中的字段名如mysql-password。当secret与field同时给出时校验失败的错误消息会附带kubectl get secret ... | base64 --decode的取值指引见上文 ValidateValue 章节的示例输出。在本仓库中的真实调用链路Common Chart 不是孤立存在的它在 OpenReplay 的 PostgreSQL 部署中承担了「通用基础库」的角色。从 NOTES.txt 可以看出完整的组合用法{{- include postgresql.validateValues . -}} {{- include common.warnings.rollingTag .Values.image -}} {{- $passwordValidationErrors : include common.validations.values.postgresql.passwords (dict secret (include postgresql.fullname .) context $) -}} {{- include common.errors.upgrade.passwords.empty (dict validationErrors (list $passwordValidationErrors) context $) -}}即安装后提示信息中先做 values 校验接着对镜像 tag 做 rolling tag 警告再专项校验 PostgreSQL 密码最后在升级场景下对空密码做fail阻断。与此同时几乎每个资源模板都在用common.labels.standard如 secrets.yaml、common.tplvalues.render如 secrets.yaml等 helper——这正体现了 Library Chart「一处实现、处处复用」的设计初衷。版本与变更说明当前仓库携带的版本为0.8.1见 Chart.yamlappVersion同为0.8.1。原文档的 Notable changes 部分标注为 N/A。由于该库图表依赖requirements.yaml中以0.x.x声明的版本范围helm dependency update时会被解析为符合该范围的可用版本实际生效版本以依赖更新后charts/common目录中的内容为准。小结Bitnami Common Library Chart 用一组设计统一的模板函数把 Helm Chart 开发中最容易出错、最容易重复的环节命名、标签、API 版本适配、镜像与 Secret 引用、参数校验、亲和性声明全部标准化。理解它的 11 类 helper 与 4 种输入结构不仅有助于深入理解 OpenReplay 仓库中 PostgreSQL 图表的工作原理也能让你在自己的 Helm Chart 中直接复用这套久经考验的工程实践写出更规范、更健壮、更易维护的部署模板。赞分享可观测性开发工具前端后端【免费下载链接】openreplaySession replay, cobrowsing and product analytics you can self-host. Best for reproducing issues and iterating on your product.项目地址https://gitcode.com/gh_mirrors/op/openreplay点击查看免费下载相关推荐深入解析 Bitnami Common Library ChartOpenReplay 依赖 Helm 图表的公共模板助手库深入解析 Bitnami Common Library ChartOpenReplay 依赖 Helm 图表的公共模板助手库 导读 Helm 官方在 v3 中可观测性开发工具前端后端Helm 库图Library Chart最佳实践深入解析 common 辅助模板的设计与用法Helm 库图Library Chart最佳实践深入解析 common 辅助模板的设计与用法 导读 本篇文章围绕 Helm 仓库中 common 这个以库云原生容器编排CLI运维深入解读 KubeSphere 依赖中的 Slim-SprigGo 模板函数的轻量级增强库深入解读 KubeSphere 依赖中的 Slim SprigGo 模板函数的轻量级增强库 Slim Sprig 是一个从 Sprig 派生的 Go 模板函数后端云原生容器编排微服务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考