第 5 篇 Chart 文件结构详解
文章目录
- Chart.yaml
- Chart.yaml 示例
- 子 chart 对 helm 安装/升级的影响
- templates/ 与 values.yaml
- 模板与 Value 示例
- 预定义的 Values
- 全局 Values
- Values 作用域
- templates/NOTES.txt
- values.schema.json
- 用户自定义资源(CRD)
- CRD 安装顺序
- CRD 限制说明
- README.md
- LICENSE
- 相关博文
🚀 本文内容:介绍 Chart 文件结构,便于后续分析 Chart 并做修改。
⭐ 思维导图
Helm 使用的包格式称为 chart,chart 是一个描述 Kubernetes 相关资源的文件集合。
😂 怎么理解?
- 首先,它是一个文件集合。存放各种文件。
- 其次,文件是什么呢?是 Kubernetes 资源描述文件。比如 deployment、service 等 yaml 文件。
😊 示例:WordPress chart
wordpress/ # 目录名:chart 名称,不包含版本号
Chart.yaml # chart 描述信息,包含了 chart 信息的 YAML 文件
values.yaml # chart 默认配置信息
values.schema.json # 可选,chart 配置的 JSON shchema,用于验证传入的配置是否有效。
templates/ # 可选,模板目录,存放各种模板文件,与 values 结合,生成有效的 K8s manifest 文件
templates/NOTES.txt # 可选,模板简要说明,在安装后/查看版本时会打印出来(作为模板渲染,而不是纯文本)
charts/ # 可选,依赖的子 chart 目录
crds/ # 可选,自定义资源目录
README.md # 可选,READEME 文件
LICENSE # 可选,许可证文件
注意:Helm 保留使用 charts/、crds/、templates/ 目录,以及列举出的文件名。
Chart.yaml
Chart.yaml 是必需的,包含如下字段。
- 🚀 核心字段:chart 名称、chart 版本号、chart API 版本号、兼容的 Kubernetes 版本、chart 类型、chart 依赖、chart 元数据信息
- 🙂 不重要字段:chart 描述、主页、图标、关键字、维护者、源码地址
Chart.yaml 示例
下面以 bitnami/nginx 的 Chart.yaml 为例:
# chart 名称(必需)
name: nginx
# chart 版本号(必需)
## 会在包名上体现,包名是 nginx-17.1.0.tgz
version: 17.1.0
# chart API 版本(必需)
## 对于至少是 Helm3 的 chart,则值至少是 v2;
## Helm 及 Helm2,就不提了哦
apiVersion: v2
# 包含的应用版本号(可选)
## 与 version 字段没有关系,version 是 chart 的版本号
## 指定创建的应用的版本号,即 Nginx 本身的版本号是 1.26.0
appVersion: 1.26.0
# 兼容的 Kubernetes 版本(可选)
## 对 Kubernetes 版本进行约束,Helm 安装这个 chart 的时候会验证这个版本约束。
## 支持比较运算符,像下面的例子,就可以很好的避开 1.14.0 版本
## 速记符号 - 连字符:1.1 - 2.3.4 等价于 >= 1.1 <= 2.3.4
## 速记符号 - 通配符 x/X/*:1.2.x 等价于 >= 1.2.0 < 1.3.0
## 速记符号 - ~(允许改变补丁版本):~1.2.3 等价于 >= 1.2.3 < 1.3.0
## 速记符号 - ^(允许改变次版本):^1.2.3 等价于 >= 1.2.3 < 2.0.0
kubeVersion: >= 1.13.0 < 1.14.0 || >= 1.14.1 < 1.15.0
# 是否弃用 chart(可选)
## 布尔值 true/false
## 如果 lastest 版本被标记为弃用,则所有 chart 都会被标记为弃用
deprecated: false
# chart 类型(可选)
## 有两种类型:application(默认值)、library
## library 类型:提供针对 chart 构建的应用程序和功能。不能安装,不包含任何资源对象。
type: application
# chart 依赖列表 (可选)
dependencies:
## chart 名称
- name: common
## chart 版本
version: 2.x.x
## 仓库 URL(可选)
repository: oci://registry-1.docker.io/bitnamicharts
## 用于启用/禁用所有带 tag 的 chart(可选)
tags:
- bitnami-common
## 用于启用/禁用 chart(可选)
condition: bitnami-common.enabled
## 导入依赖chart中的 values 到当前 chart 中(可选)
import-values: # (可选)
- ImportValue
## chart别名(可选),需多次添加相同的chart时很有用
alias: common1
# 自定义元数据
## 自 v3.3.2 开始,不再允许添加额外的字段(会被抛弃),需使用 annotations 添加;
annotations:
category: Infrastructure
images: |
- name: git
image: docker.io/bitnami/git:2.45.1-debian-12-r0
- name: nginx
image: docker.io/bitnami/nginx:1.26.0-debian-12-r1
- name: nginx-exporter
image: docker.io/bitnami/nginx-exporter:1.1.0-debian-12-r23
licenses: Apache-2.0
# ----------------- 不重要 ---------------------------
# chart 描述信息(可选)
description: NGINX Open Source is a web server ...
# 项目 home 页面的 URL (可选)
home: https://bitnami.com
# 用做 icon 的 SVG 或 PNG 图片 URL(可选)
icon: https://bitnami.com/assets/stacks/nginx/img/nginx-stack-220x234.png
# 项目的一些关键字(可选)
keywords:
- nginx
- http
- web
- www
# 项目源码的 URL 列表(可选)
sources:
- https://github.com/bitnami/charts/tree/main/bitnami/nginx
# 项目维护者(可选)
maintainers:
- name: Broadcom, Inc. All Rights Reserved.
url: https://github.com/bitnami/charts
email: xxx@xxx.com
子 chart 对 helm 安装/升级的影响
假设:
- chart A 创建了如下 k8s 对象:A-namespace、A-StatefulSet、A-Service
- A 是依赖于 chart B 创建的对象:B-namespace、B-ReplicaSet、B-Service
那么,helm install/upgrade 的顺序是什么呢?
- A-namespace
- B-namespace
- A-Service
- B-Servie
- B-ReplicaSet
- A-StatefulSet
👉 排序规则是什么?
- 聚合成单一的集合;然后按照类型和名称排序;然后按这个顺序创建/升级。
- Kubernetes 类型排序,按 kind_sorter.go 定义的枚举顺序进行。
// InstallOrder is the order in which manifests should be installed (by Kind).
// Those occurring earlier in the list get installed before those occurring later in the list.
var InstallOrder KindSortOrder = []string{
"PriorityClass",
"Namespace",
"NetworkPolicy",
"ResourceQuota",
"LimitRange",
"PodSecurityPolicy",
"PodDisruptionBudget",
"ServiceAccount",
"Secret",
"SecretList",
"ConfigMap",
"StorageClass",
"PersistentVolume",
"PersistentVolumeClaim",
"CustomResourceDefinition",
"ClusterRole",
"ClusterRoleList",
"ClusterRoleBinding",
"ClusterRoleBindingList",
"Role",
"RoleList",
"RoleBinding",
"RoleBindingList",
"Service",
"DaemonSet",
"Pod",
"ReplicationController",
"ReplicaSet",
"Deployment",
"HorizontalPodAutoscaler",
"StatefulSet",
"Job",
"CronJob",
"IngressClass",
"Ingress",
"APIService",
}
// UninstallOrder is the order in which manifests should be uninstalled (by Kind).
// Those occurring earlier in the list get uninstalled before those occurring later in the list.
var UninstallOrder KindSortOrder = []string{
"APIService",
"Ingress",
"IngressClass",
"Service",
"CronJob",
"Job",
"StatefulSet",
"HorizontalPodAutoscaler",
"Deployment",
"ReplicaSet",
"ReplicationController",
"Pod",
"DaemonSet",
"RoleBindingList",
"RoleBinding",
"RoleList",
"Role",
"ClusterRoleBindingList",
"ClusterRoleBinding",
"ClusterRoleList",
"ClusterRole",
"CustomResourceDefinition",
"PersistentVolumeClaim",
"PersistentVolume",
"StorageClass",
"ConfigMap",
"SecretList",
"Secret",
"ServiceAccount",
"PodDisruptionBudget",
"PodSecurityPolicy",
"LimitRange",
"ResourceQuota",
"NetworkPolicy",
"Namespace",
"PriorityClass",
}
templates/ 与 values.yaml
模板编写:按 Go模板语言 书写,存放在 templates/ 目录下。当 helm 渲染 chart 时,它会通过模板引擎遍历目录中的每个文件。
Helm 增加了 50 个左右的附加模板函数(来自 Sprig库 )和一些其它的指定的函数,便于在模板中使用。
values.yaml:就是一个普通的 YAML 文件,定义配置的。
模板与 Value 示例
示例 values.yaml 如下:
imageRegistry: "docker.io"
dockerTag: "v1.1.0"
pullPolicy: "IfNotPresent"
storage: "s3"
示例模板如下:
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{ required "A valid imageRegistry is required!" .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
imagePullPolicy: {{ .Values.pullPolicy }}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{ default "minio" .Values.storage }}
上面的例子,是一个 k8s 副本控制器模板。
该模板,使用 Values 来取值,值来源于 values.yaml 文件。
- 最简单:{{ .Values.dockerTag }}:获取 dockerTag 的值
- 必填项:{{ required “A valid imageRegistry is required!” .Values.imageRegistry }} :获取 imageRegistry 的值,且必填
- 默认值:{{ default “minio” .Values.storage }}:获取 storage 的值,默认为 “minio”
模板命令要括在 {{ 和 }} 之间。
{{ .Release.Name }}
- 用点分隔每个命名空间的元素。
- 第一个点,表示从作用域最顶层的命名空间开始
- 表示从顶层命名空间开始查找 Release 对象,并在其中查找 Name 对象
预定义的 Values
Values 通过模板中 .Values 对象可访问 values.yaml 文件(或者通过–set 参数提供)的配置,也可以访问其他预定义的配置。
以下值都是预定义的,对每个模板有效,且可以被覆盖。名称区分大小写。
- Release 对象:描述了版本发布本身的信息。
- Release.Name:发布名称(非 chart )
- Release.Namespace:发布命名空间
- Release.Service:该 service 用来渲染当前模板
- Release.IsInstall:当前操作是否是安装,设置为 true
- Release.IsUpgrade:当前操作是否是升级/回滚,设置为 true
- Values 对象:从默认 values.yaml 或用传递的 yaml 或者 --set 参数提供的配置。
- Chart 对象:Chart.yaml 中的内容。比如版本,Chart.Version。
- Files 对象:访问所有非特殊文件的对象,不能使用它访问 Template 对象,只能访问其他文件
- Files.Get:通过文件名获取文件,比如 .Files.Get config.ini
- Files.GetBytes 用字节数组代替字符串获取文件内容,常用于图片类文件
- Files.Glob 用给定的 shell glob 模式匹配文件名返回文件列表
- Files.Lines 逐行读取文件内容,常用于迭代文件每一行
- Files.AsSecrets 使用 Base64 编码字符串返回文件体
- Files.AsConfig 使用 YAML 格式反馈文件体
- Capabilities 对象:提供关于 Kubenetes 集群支持功能的信息
- Capabilities.APIVersions 版本列表
- Capabilities.APIVersions.Has $version 说明集群中的版本 (比如,batch/v1) 或是资源 (比如,apps/v1/Deployment) 是否可用
- Capabilities.KubeVersion Kubernetes 版本信息
- Capabilities.KubeVersion.Version Kubernetes 版本号
- Capabilities.KubeVersion.Major 主版本号
- Capabilities.KubeVersion.Minor 次版本号
- Capabilities.HelmVersion Helm 版本信息
- Capabilities.HelmVersion.Version Helm 语义格式的版本
- Capabilities.HelmVersion.GitCommit Helm的 git sha1 值
- Capabilities.HelmVersion.GitTreeState Helm git 树的状态
- Capabilities.HelmVersion.GoVersion 使用的 Go 编译器版本
- Template 对象:包含当前被执行的当前模板信息
- Template.Name: 模板名称,含路径。 比如 mychart/templates/mytemplate.yaml
- Template.BasePath: 模板路径,比如 mychart/templates
😊 Values 命名规范:
- 内置 Values:以大写字母开始,这符合 Go 的命名惯例。
- 自定义 Values:使用小写字母开始,可方便地与内置对象区分开。很多 Artifact Hub 中的 chart,都是这样做的。
全局 Values
自 2.0.0-Alpha.2 开始,Helm 支持特殊的 global 值。
全局 Values 的作用域:只能往下传递,不会向上传递。且父 chart 的优先级更高。
- 如果子 chart 声明了一个全局 Values,则只会向下传递到子 chart 的子 chart 中,不会向上传递到父 chart。
- 子 chart 是无法影响父 chart 的值的。
- 父 chart 的全局 Values 优先于子 chart 中的全局 Values。
示例如下:
title: "My WordPress Site" # Sent to the WordPress template
# 我是全局 Values !!!
global:
app: MyWordPress
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
这个 global.app 在所有 chart 中生效。
- 在 mysql 模板中,可以访问 {{.Values.global.app}}
- 在 apache 模板中,可以访问 {{.Values.global.app}}
全局 Values 的本质:重新生成 values.yaml,给每个子 chart 也添加上 Values。
title: "My WordPress Site" # Sent to the WordPress template
global:
app: MyWordPress
mysql:
global:
app: MyWordPress
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
global:
app: MyWordPress
port: 8080 # Passed to Apache
Values 作用域
Values 作用域:父 chart 可以访问子 chart 的 Values,但子 chart 无法访问父 chart 的 Values。
比如 WordPress chart 同时有 mysql 和 apache 作为依赖。
title: "My WordPress Site" # Sent to the WordPress template
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
✔️ WordPress chart 使用 .Values.mysql.password 访问 MySQL 密码。
❌ mysql chart 无法访问 title 属性,apache/port 也无法访问。
✔️ mysql chart 使用 .Values.password 访问 MySQL 密码。【命名空间删减,所以不需要写 mysql】
templates/NOTES.txt
NOTES.text 会在安装后及查看版本状态(helm install、helm status)时从打印出来。
这个文件会作为一个模板来评估,并用来显示使用说明、后续步骤、或者其他 chart 版本的相关信息。
比如 连接数据库的说明,Web UI 访问地址等。
values.schema.json
基于 values.yaml 定义一个结构,并使用 JSON 显示。
相当于定义了一个结构,values 值使用的时候(helm install、update、lint、template),会去验证结构是否正确。
{
"$schema": "https://json-schema.org/draft-07/schema#",
"properties": {
"image": {
"description": "Container Image",
"properties": {
"repo": {
"type": "string"
},
"tag": {
"type": "string"
}
},
"type": "object"
},
"name": {
"description": "Service name",
"type": "string"
},
"port": {
"description": "Port",
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
}
},
"required": [
"protocol",
"port"
],
"title": "Values",
"type": "object"
}
一个符合上述结构的 values.yaml 文件:
name: frontend
protocol: https
port: 443
或者这样:values.yaml + --set 参数
name: frontend
protocol: https
helm install --set port=443
用户自定义资源(CRD)
使用 Kubernetes 的 CustomResourceDefinition(CRD),可声明自定义的资源类型。
在 Helm 3 中,CRD 被视作特殊对象,其会在 chart 的其它部分之前安装,并有一些限制。
CRD 文件说明:
- 放在 chart 的 crds/ 目录下,Helm 会加载此目录下所有 YAML 文件到 Kubernetes;
- 多个 CRD 可放在一个 YAML 文件中(使用 YAML 的开始和结束符分隔);
- CRD 文件无法模板化,只能是普通的 YAML 文件;
CRD 安装顺序
安装顺序:先上传 CRD,暂停 chart 安装直到 CRD 可以被 API 服务使用,然后启动模板引擎,渲染 chart 其它部分,并上传到 Kubernetes。
😁 很明显,CRD 是先运行好的,然后再执行 chart 中的相关 k8s 资源。
所以,我们可以在模板中使用 CRD 中定义的资源。
比如,如下 chart,定义了 crontab 资源。
crontabs/
Chart.yaml
crds/
crontab.yaml
templates/
mycrontab.yaml
crontab.yaml 文件如下,可以看到,没有任何模板指令,就是纯粹的 K8s 资源文件。
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
然后模板 mycrontab.yaml 可以创建一个新的 CronTab:Helm 在安装 templates/ 内容之前会保证 CronTab 类型安装成功并对 Kubernetes API 可用
apiVersion: stable.example.com
kind: CronTab
metadata:
name: {{ .Values.name }}
spec:
# ...
CRD 限制说明
CRD 的限制:不像大部分的 Kubernetes 对象,CRD 是全局安装的。
CRD 受到以下限制:
- CRD 从不重新安装。如果 Helm 确定 crds/ 目录中的 CRD 已经存在(忽略版本),Helm 不会安装或升级。
- CRD 从不会在升级或回滚时安装。Helm 只会在安装时创建 CRD。
- CRD 从不会被删除。自动删除 CRD 会删除集群中所有命名空间中的所有 CRD 内容。因此 Helm 不会删除 CRD。
希望升级或删除 CRD 时,应谨慎地手动执行此操作。
README.md
chart 的自述文件 README.md:使用 Markdown 格式
一般包含:
- chart 描述信息
- chart 先决条件
- values.yaml 的可选项、默认值、描述
- 其它相关信息
LICENSE
LICENSE 许可证,是一个包含了 chart license 的纯文本文件。
chart 可以包含一个许可证,因为模板里不仅是配置,还有代码逻辑。
如果需要,可以为 chart 安装的应用提供单独的许可证。
相关博文
1.第 1 篇 Helm 简介及安装
2.第 2 篇 Helm 部署 MySQL【入门案例】
3.第 3 篇 Helm 命令、环境变量、相关目录
4.第 4 篇 Chart 仓库详解
5.第 5 篇 Chart 文件结构详解
6.第 6 篇 自定义 Helm Chart
7.第 7 篇 Helm 部署 Nacos【详细步骤】
8.第 8 篇 Chart 修改入门示例:Nacos
9.第 9 篇 Helm 部署 Seata Server
10.第 10 篇 Chart 修改完美示例:Seata Server
11.第 11篇 Helm 部署 RabbitMQ
12.第 12 篇 Helm 部署 Redis
13.第13 篇 Helm 部署 ElasticSearch