一个计算机技术爱好者与学习者

0%

Helm官方文档摘录

1. 前言

Helm官方文档写的很棒,本文会摘录Helm官方文档中的一些基础知识和最佳实践,备忘。
更细致全面的内容,请移步阅读Helm官方文档

参考文档:

2. Helm三大概念

Chart 代表着 Helm 包。它包含在 Kubernetes 集群内部运行应用程序,工具或服务所需的所有资源定义。你可以把它看作是 Homebrew formula,Apt dpkg,或 Yum RPM 在Kubernetes 中的等价物。

Repository(仓库) 是用来存放和共享 charts 的地方。它就像 Perl 的 CPAN 档案库网络 或是 Fedora 的 软件包仓库,只不过它是供 Kubernetes 包所使用的。

Release 是运行在 Kubernetes 集群中的 chart 的实例。一个 chart 通常可以在同一个集群中安装多次。每一次安装都会创建一个新的 release。以 MySQL chart为例,如果你想在你的集群中运行两个数据库,你可以安装该chart两次。每一个数据库都会拥有它自己的 release 和 release name。

在了解了上述这些概念以后,我们就可以这样来解释 Helm:
Helm 安装 charts 到 Kubernetes 集群中,每次安装都会创建一个新的 release。你可以在 Helm 的 chart repositories 中寻找新的 chart。

3. Helm安装资源的顺序

Helm按照以下顺序安装资源:

  • 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
  • Ingress
  • APIService

4. Chart模板指南

内容太多,建议直接阅读Helm官方文档 - Chart模板指南,了解基础概念和语法。

本节只简单说明几个概念和语法。

4.1. 模板

templates/目录中的.yaml文件和.tpl文件,就是模板。
当Helm评估chart时,会通过模板渲染引擎将所有文件发送到templates/目录中。 然后收集模板的结果并发送给Kubernetes。

values.yaml 文件也导入到了模板。这个文件包含了chart的 默认值 。这些值会在用户执行helm install 或 helm upgrade时被覆盖。

Chart.yaml 文件包含了该chart的描述。你可以从模板中访问它。charts/目录 可以 包含其他的chart(称之为 子chart)。

模板中横线的作用:

  • {{-`:表示在模板渲染时要去掉前面的空白字符和换行符。 - `-}}:表示在模板渲染时要去掉后面的空白字符和换行符。

4.2. 变量和作用域

Helm模板中,变量是对另一个对象的命名引用。

变量的作用域一般不是全局的,而是其声明所在的块。所谓块,是指if/elsewithrangedefinetemplateblock定义的范围。

.代表对当前作用域的引用,.Values表示在当前作用域查找Values对象。
每个模板中,默认可以访问到的内置对象有Release、Values、Chart、Files、Capabilities和Template。
如果定义了块,那么在块中不可以通过.Values找到Values对象。

$代表对根作用域的引用,$.Values表示在根作用域查找Values对象。
如果定义了块,那么在块中可以通过$.Values找到Values对象。

变量定义格式示例:{{- $name := .Release.Name -}}
在模板顶层定义变量,变量的作用域会是整个模板;在块中定义变量,变量的作用域只在块内。

4.3. 变量类型

Helm 模板语言是用强类型Go编程语言实现的。 因此,模板中的变量是 有类型的。大多数情况下,变量将作为以下类型之一显示:

  • string: 文本字符串
  • bool: true 或 false
  • int: 整型值(包含8位,16位,32位,和64有符号和无符号整数)
  • float64: 64位浮点数(也有8位,16位,32位类型)
  • 字节切片([]byte),一般用于保存(可能的)二进制数据
  • struct: 有属性和方法的对象
  • 上述某种类型的切片(索引列表)
  • 字符串键map (map[string]interface{}) 值是上述某种类型

Go里面有很多其他类型,有时你需要在模板里转换。调试对象类型最简便的方式是在模板中传递给printf “%t”,这样会打印类型。 也可以使用 typeOf 和 kindOf 函数。

4.4. 命名模板

命名模板(也被称作一个 部分 或一个 子模板)名称是全局的。
一个常见的命名惯例是用chart名称作为模板前缀。使用特定chart名称作为前缀可以避免可能因为 两个不同chart使用了相同名称的模板而引起的冲突。

用define和template声明和使用模板。
按照惯例,define声明的命名模板一般放在_helpers.tpl文件中。因为是模板名称是全局的,因此可以被.yaml文件引用。

template渲染时,一般传入.作为命名模板可以访问的范围。
include是template的替代,只是为了更好地处理YAML文档的输出格式,方便缩进。

4.5. NOTES.txt文件

在helm install 或 helm upgrade命令的最后,Helm会打印出对用户有用的信息。 使用模板可以高度自定义这部分信息。
要在chart添加安装说明,只需创建 templates/NOTES.txt 文件即可。该文件是纯文本,但会像模板一样处理, 所有正常的模板函数和对象都是可用的。

4.6. .helmignore 文件

.helmignore 文件用来指定你不想包含在你的helm chart中的文件。
如果该文件存在,helm package 命令会在打包应用时忽略所有在 .helmignore 文件中匹配的文件。

一些值得注意的和.gitignore不同之处:

  • 不支持**语法。
  • globbing库是Go的 ‘filepath.Match’,不是fnmatch(3)
  • 末尾空格总会被忽略(不支持转义序列)
  • 不支持!作为特殊的引导序列
  • 默认不会排除自身,需要显式添加 .helmignore

4.7. YAML技术

参考文档:《YAML语言》

5. Chart开发技巧

5.1. 模板方法

Helm使用Go模板,同时增加了两个特殊模板方法:includerequired

include方法允许你引入另一个模板,并将结果传递给其他模板方法。
比如,这个模板片段包含了一个叫mytpl的模板,然后将其转成小写,并使用双引号括起来。

1
value: {{ include "mytpl" . | lower | quote }}

required方法可以让你声明模板渲染所需的特定值。如果这个值是空的,模板渲染会出错并打印用户提交的错误信息。
下面这个required方法的例子声明了一个.Values.who需要的条目,并且当这个条目不存在时会打印错误信息:

1
value: {{ required "A valid .Values.who entry required!" .Values.who }}

tpl方法允许开发者在模板中使用字符串作为模板。将模板字符串作为值传给chart或渲染额外的配置文件时会很有用。
语法: {{ tpl TEMPLATE_STRING VALUES }}

5.2. 使用Partials和模板引用

有时你想在chart中创建可以重复利用的部分,不管是块还是局部模板。通常将这些文件保存在自己的文件中会更干净。

templates/ 目录中,任何以下划线(_)开始的文件不希望输出到Kubernetes清单文件中。
因此按照惯例,辅助模板和局部模板会被放在_helpers.tpl文件中。

5.3. 创建镜像拉取密钥

1、定义 values.yaml

1
2
3
4
5
imageCredentials:
registry: quay.io
username: someone
password: sillyness
email: someone@host.com

2、定义辅助模板(写在 _helpers.tpl 文件里)

1
2
3
4
5
{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}

3、模板中使用辅助模板

1
2
3
4
5
6
7
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}

5.4. YAML是JSON的超集

根据YAML规范,YAML是JSON的超集。这意味着任意的合法JSON结构在YAML中应该是合法的。

这有个优势:有时候模板开发者会发现使用类JSON语法更容易表达数据结构而不是处理YAML的空白敏感度。

作为最佳实践,模板应遵循类YAML语法 除非 JSON语法大大降低了格式问题的风险。

5.5. 构建复杂Chart

在CNCF的 Artifact Hub 中的很多chart是创建更先进应用的“组成部分”。但是chart可能被用于创建大规模应用实例。 在这种场景中,一个总的chart会有很多子chart,每一个是整体功能的一部分。

当前从离散组件组成一个复杂应用的最佳实践是创建一个顶层总体chart构建全局配置,然后使用charts子目录嵌入每个组件。

6. 最佳实践

6.1. 一般惯例

6.1.1. chart名称

chart名称必须是小写字母和数字。单词之间可以使用横杠分隔(-)。

6.1.2. 版本号

Helm尽可能使用 SemVer 2来表示版本号。(注意Docker镜像的tag不一定遵循SemVer, 因此被认为是一个不幸的例外规则。)

当SemVer版本存储在Kubernetes标签中时,我们通常把+字符改成_,因为标签不允许使用+作为值进行签名。

6.1.3. 格式化YAML

YAML 文件应该按照 双空格 缩进(绝不要使用tab键)。

6.1.4. Helm 和 Chart的用法

以下是几个 Helm 和 helm 的惯用方法。

  • Helm 是指整个项目
  • helm 是指客户端命令
  • chart 不是专有名词,不需要首字母大写
  • Chart.yaml 需要首字母大写,因为文件名大小写敏感

若有疑问,使用 Helm (‘H’大写)。

6.2. Values

6.2.1. 命名规范

变量名称以小写字母开头,单词按驼峰区分

6.2.2. 扁平或嵌套的Value

YAML是一种灵活格式,值可以嵌套得很深,也可以是扁平的。
大多数场景中,扁平的优于嵌套的。因为对模板开发者和用户来说更加简单。

6.2.3. 类型清楚

YAML的类型强制规则有时候是很反常的。比如,foo: false 和 foo: “false” 是不一样的。大整型数如:foo: 12345678 有时会被转换成科学计数法。

避免类型强制规则错误最简单的方式是字符串明确定义,其他都是不明确的。或者,简单来讲, 给所有字符串打引号。

通常,为了避免整数转换问题,将整型存储为字符串更好,并用 {{ int $value }} 在模板中将字符串转回整型。

在大多数场景中,显式的类型标记更好,所以 foo: !!string 1234 会将1234作为字符串对待。 但是,YAML解析器会消耗标记,因此类型数据在一次解析后会丢失。

6.2.4. 考虑用户使用value

有三种value来源:

  • chart的values.yaml文件
  • helm install -f提供的values文件
  • 在执行helm install 时传递给–set 或 –set-string 参数的values

当设计values的结构时,记得你的chart用户可能会通过-f 参数或–set选项覆盖他们。
由于–set在表现上更有限,编写你values.yaml文件的第一指导原则是确保它容易被–set覆盖。因此使用map构建values文件更好。

6.2.5. 给values.yaml写文档

values.yaml中每个定义的属性都应该文档化。文档字符串应该以它要描述的属性开头,并至少给出一句描述。

6.3. 模板

6.3.1. templates 结构

templates/目录结构应该如下:

  • 如果生成YAML输出,模板文件应该有扩展名.yaml。 扩展名是.tpl可用于生成非格式化内容的模板文件。
  • 模板文件名称应该使用横杠符号(my-example-configmap.yaml),不用驼峰记法。
  • 每个资源的定义应该在它自己的模板文件中。
  • 模板文件的名称应该反映名称中的资源类型。比如:foo-pod.yaml, bar-svc.yaml

6.3.2. 定义模板的名称

定义的模板(在{{ define }}命令中定义的模板)是可全局访问的。这就意味着chart和所有的子chart都可以访问用{{ define }}创建的所有模板。

因此, 所有定义的模板名称应该被命名空间化。

正确的:

1
2
3
{{- define "nginx.fullname" }}
{{/* ... */}}
{{ end -}}

不正确的:

1
2
3
{{- define "fullname" -}}
{{/* ... */}}
{{ end -}}

强烈建议通过helm create命令创建新chart,因为模板名称是根据此最佳实践自动定义的。

6.3.3. 格式化模板

模板应该使用两个 空格 缩进(永远不要用tab)。
模板命令的大括号前后应该使用空格。
正确的:

1
2
3
{{ .foo }}
{{ print "foo" }}
{{- print "bar" -}}

不正确的:

1
2
3
{{.foo}}
{{print "foo"}}
{{-print "bar"-}}

6.3.4. 生成模板中的空格

最好在生成的模板中将空格量保持在最小值。尤其是大量的空行不应该相邻出现。但偶尔有空行(尤其在逻辑块之间)是没问题的。

6.3.5. 注释

YAML和Helm模板都有注释标记符。
YAML注释:

1
2
# This is a comment
type: sprocket

模板注释:

1
2
3
4
{{- /*
This is a comment.
*/}}
type: frobnitz

6.3.6. 在模板和模板输出中使用JSON

YAML是JSON的超集。在某些情况下,使用JSON语法比其他YAML表示更具可读性。

比如,这个YAML更接近表示列表的普通YAML方法:

1
2
3
arguments:
- "--dirname"
- "/foo"

但是折叠成JSON列表样式时会更易阅读:

1
arguments: ["--dirname", "/foo"]

使用JSON可以很好地提高易读性。然而,JSON语法不应用于表示更复杂的结构。

6.4. 标签和注释

建议使用 helm.sh/chart: NAME-VERSION 作为标签,以便操作员可以找到特定chart的所有实例。

如果元数据项不是用于查询,就应该设置为注释。

标准标签参考文档:标签和注释

6.5. Pod和Pod模板

Pod指的是Pod,Pod模板指的是Deployment、ReplicationController、ReplicaSet、DaemonSet、StatefulSet等。

容器镜像应该使用固定的tag或镜像SHA。不应该使用latest, head, canary等标签或其他被设计为“浮动的”标签。

所有的Pod模板部分应该指定一个selector。比如:

1
2
3
4
5
6
7
selector:
matchLabels:
app.kubernetes.io/name: MyName
template:
metadata:
labels:
app.kubernetes.io/name: MyName

6.6. 基于角色的访问控制

RBAC 资源有:

  • ServiceAccount (namespaced)
  • Role (namespaced)
  • ClusterRole
  • RoleBinding (namespaced)
  • ClusterRoleBinding

RBAC和服务账户配置应该使用独立的key。它们是独立的内容。在YAML中将这两个概念分开可以消除歧义使其更加清晰。

1
2
3
4
5
6
7
8
9
10
rbac:
# Specifies whether RBAC resources should be created
create: true

serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name:

rbac.create 应该是布尔值,用于控制RBAC资源是否被创建。默认是 true。用户想自己管理RBAC访问控制时可以设置为false (示例如下)。

serviceAccount.name 要设置为由chart创建的访问控制资源的ServiceAccount的名称。 如果serviceAccount.create是true,则使用该名称的ServiceAccount会被创建。如果没有设置名称, 则会使用fullname模板生成一个名称。如果serviceAccount.create是false,则不会被创建,但仍然会与相同的资源关联, 以便后续手动创建的引用它的RBAC资源可以正常工作。如果serviceAccount.create是false且没有指定名称, 会使用默认的ServiceAccount。

1
2
3
4
5
6
7
8
9
10
{{/*
Create the name of the service account to use
*/}}
{{- define "mychart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "mychart.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

7. 调试

7.1. 语法检查

1
helm lint

7.2. 测试本地渲染

1
helm template --debug

7.3. 测试服务器渲染

1
helm install --dry-run --debug

7.4. 忽略检查测试服务器渲染

1
helm install --dry-run --disable-openapi-validation

7.5. 查看安装在服务上的模板

1
helm get manifest
  • 本文作者: 好好学习的郝
  • 原文链接: https://www.voidking.com/dev-helm-doc-extract/
  • 版权声明: 本文采用 BY-NC-SA 许可协议,转载请注明出处!源站会即时更新知识点并修正错误,欢迎访问~
  • 微信公众号同步更新,欢迎关注~