本文的目标不限于对Helm官方文档的翻译或解释,更在于帮助开发者能够快速编写出一个标准且合理的helm chart。
Helm简介
一句话描述:Helm是Kubernetes的包管理工具
Helm vs Operator
Helm 和 Operator都可以实现在k8s上安装应用。但二者有着不同的适用场景。
Helm适用于:
- 开发者群体
- 门槛低:熟悉k8s即可
- 重点在于实现应用的“安装-升级-删除”
Operator适用于:
- 运维或SRE团队
- 门槛高:对k8s精通,并能结合k8s编写自运维脚本,实现复杂且定制化的配置
- 重点在于实现应用的自运维、高可靠。
Helm2 or Helm3
Helm2和Helm3,从开发者的视角有如下差别:
- 增加了JSON格式的校验,可以输出更容易让人理解的错误报告
- Release name从可选变成必选
- Release name作用域从全局被限制到了namespace级别
- Namespaces不再自动创建。如果chart中的namespace不存在,需要手动创建namespace
- 将requirements.yaml,requirements.lock的内容合并到Chart.yaml,Chart.lock
- Chart.yaml的apiVersion从v1到v2
其实对开发者来说,helm2 与helm3差异不大,就是helm3对于helm编写体验更加友好。
Heml的安装
Helm的github地址:https://github.com/helm/helm
可以选择安装最新的Helm3,也可以使用Helm2,通过tag找到2.x的最新版本:2.17. 在release中有编译好的mac二进制程序可以下载直接使用。
Helm 开发技巧
命名模板(named templates)
命名模板(named templates)也可以成为子模板,但他是有个名称的,可以结合include使用。
我们可以方便把一个模板文件中,公共或通用的部分,提取出来,放到一个新的文件中,并给其命名,这样就可以带其他地方使用
通过 define
定义模板
{{ define "MY.NAME" }}
# body of template here
{{ end }}
include
记住标准用法
{{ include "named template" . }}
解释: . 表示的是scope。 这里也可以改成 .Values
空格
注意:换行也算空格
{{- 表示左边的空格和换行会移除
-}} 表示右边的空格和换行会移除
实例:
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" -}}
mug: "true"
{{ end }}
会渲染出
food: "PIZZA"
mug: "true"
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" -}}
mug: "true"
{{- end -}}
会渲染出
food: "PIZZA"mug: "true"
正确的写法是
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" }}
mug: "true"
{{- end }}
Helm 本地测试技巧
格式化校验
helm lint Path [flag]
- Path: a path of chart
本地渲染
helm template path [flag]
helm template命令来自于开源的 https://github.com/technosophos/helm-template
Helm chart最佳实践
基本规约
Chart命名
必须是小写字母,分割符用-
版本规范
版本号遵循SemVer2的规范
Yaml缩进
使用两个空格缩进,不能用tab
Values 自定义变量
values.yaml编写的最佳实践
命名规范
首字母小写的驼峰式命名
反例:
Chicken: true # initial caps may conflict with built-ins
chicken-noodle-soup: true # do not use hyphens in the name
所有Helm内置的变量都是大写开头(如.Chart.Name, .Capabilities.KubeVersion),这样可以和用户自定义的变量区分开
变量平铺 Or 层叠
Yaml格式灵活,里面的变量既可以平铺也可以层叠编写
层叠:
server:
name: nginx
port: 80
平铺:
serverName: nginx
serverPort: 80
通常:平铺更好,因为简单
当相关的一些变量是可选的,为了安全起见,使用层叠方式,并在每个层级中都对变量进行校验。
{{ if .Values.server }}
{{ default "none" .Values.server.name }}
{{ end }}
类型清醒
Yaml的类型转化的规则有时是反直觉的。比如foo: false
和foo: "false"
不一样。 大数 foo:1234567
在某些场景下会变成科学计数法表达。
最简单,清醒的做法:所有变量都用 ""引号 表达成字符串。
在需要使用数字时,用 {{ int $value }}
进行变量转换
使用字典而不是数组
由于values.yaml的变量是可以支持被命令行的参数 --set
或--set-string
改写,而参数的写法有限。
所以values.yaml变量的写法尽可能使用map,而不是数组
反例:
servers:
- name: foo
port: 80
- name: bar
port: 81
如何用--set
改写端口, Helm2.4之前不支持, 2.5之后可以用 --set servers[0].port=80
。 但表意不明确,万一values里的顺序改变了,就糟糕了。
正例:
servers:
foo:
port: 80
bar:
port: 81
改foo的端口 --set servers.foo.port=80
注释
每个变量都应该注释。
注释必须以变量名开头
正例
# serverHost is the host name for the webserver
serverHost: example
# serverPort is the HTTP listener port for the webserver
serverPort: 9191
变量名开头的注释有利于在grep时,可以快速抓取变量及其文档说明
Templates 模板
templates
的结构化规范:
- 所有的yaml模板必须有
.yaml
后缀, 非格式化内容的模板使用.tpl
后缀 - 模板文件的命名使用小写,
-
虚线表示法。如(my-example-configmap.yaml) - 每种资源的定义必须单独的模板文件
- 模板文件名必须反应出其表示的资源。如:
foo-pod.yaml
,bar-svc.yaml
命名模板
{{ define }}
创建出命名模板是全局可见的,为了避免名称冲突,命名中应该带上命名空间。
正例
{{- define "nginx.fullname" }}
{{/* ... */}}
{{ end -}}
反例
{{- define "fullname" -}}
{{/* ... */}}
{{ end -}}
推荐使用helm create
创建新的chart,它会自动循序最佳实践
模板命令
{{ }}
表示模板命令。在{{
后和}}
前需要用一个空格隔开
正例
{{ .foo }}
{{ print "foo" }}
{{- print "bar" -}}
反例
{{.foo}}
{{print "foo"}}
{{-print "bar"-}}
注释
Yaml注释: 常用注释,而且在helm install --debug
调试时可见
# This is a comment
type: sprocket
模板注释:多行注释,常用于对模块、方法的说明
{{- /*
This is a comment.
*/}}
type: frobnitz
Lable和Anonotation
二者都是元数据,有着各自的适用场景。
Label
- 被k8s用来标识资源
- 被运维用来查询
上述两个目的外的场景,都应该使用Annonation
标准标签
Name | Status | Description | |
---|---|---|---|
app.kubernetes.io/name | 推荐 | {{ .Chart.Name }} | |
helm.sh/chart | 推荐 | {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} |
app.kubernetes.io/managed-by | 推荐 | {{ .Release.Service }}, 可用来找Helm托管的应用 | |
app.kubernetes.io/instance | 推荐 | {{ .Release.Name }} | |
app.kubernetes.io/version | 可选 | {{ .Chart.AppVersion }} | |
app.kubernetes.io/component | 可选 | 标记应用在系统的角色。如app.kubernetes.io/component: frontend | |
app.kubernetes.io/part-of | 可选 | 标记所属的整体 |
Pod 容器
Image
镜像需要用固定的标签或镜像的sha值,不能用 latest
,head
, canary
这些“引用”性质标签
ImagePullPolicy
deployment.yaml
imagePullPolicy: {{ .Values.image.pullPolicy }}
values.yaml
image:
pullPolicy: IfNotPresent
PodTemplates
必须定义一个selector
selector:
matchLabels:
app.kubernetes.io/name: MyName
template:
metadata:
labels:
app.kubernetes.io/name: MyName
一个标准的Helm Chart
待补充
引用
https://cloudblogs.microsoft.com/opensource/2020/04/02/when-to-use-helm-operators-kubernetes-ops/
https://searchitoperations.techtarget.com/tip/When-to-use-Kubernetes-operators-vs-Helm-charts