本指南旨在为chart开发人员提供对如何使用Helm模板语言的深入理解,侧重于模板开发的技术方面。但是,当涉及到chart的日常实际开发时,本指南有许多事情没有涉及。这里有一些有用的文档链接及参考资料,可以帮助你创建新的chart。
1、参考文档
- CNCF的 Artifact Hub(Helm Charts项目) 是一个必不可少的chart来源。该项目还为chart开发的最佳实践制定了标准。
- Kubernetes 文档 提供了你可以使用的各种资源类型的详细示例,从ConfigMap和Secret到DaemonSet和部署。
- Helm 的 chart指南 解释了使用chart的工作流程。
- Helm 的 chart钩子指南 解释了如何创建生命周期钩子。
- Helm 的 chart技巧和陷阱 提供了编写chart时的一些有用提示。
- Sprig文档 记录了60多个模板函数。
- Go模板文档 详细解释了模板语法。
- Schelm工具 是用于调试chart的很好的辅助工具。
有时候从有经验的开发者那里问问题和获取答案更加容易。最佳方式是访问 Kubernetes Slack 的Helm频道:
最后,如果你找到了文档中的错误或疏漏,想推荐一些新内容,或者想做一些贡献,请访问 Helm 项目。
2、Go 数据类型和模板
Helm 模板语言是用强类型Go编程语言实现的。因此,模板中的变量是有类型的。大多数情况下,变量将作为以下类型之一显示:
- string: 文本字符串
- bool:
true
或false
- int: 整型值(包含8位,16位,32位,和64有符号和无符号整数)
- float64: 64位浮点数(也有8位,16位,32位类型)
- byte slice([]byte),通常用来保存二进制数据
- struct: 具有属性和方法的对象
- 上述某种类型的slice(索引列表)
- 键为字符串的map(
map[string]interface{}
),其中的值是前面的类型之一
Go里面有很多其他类型,有时你必须在模板中对它们进行转换。调试对象类型的最简单方法是通过模板中的
printf "%t"
传递它,它将打印类型。还可以看到函数的typeOf
和kindOf
。
3、YAML技术
YAML有一些有用的特性,作为模板作者,我们可以使用这些特性来降低模板出错的可能性,并使其更易于阅读。
3.1 标量和集合
根据 YAML规范,有两种类型的集合和许多标量类型。这两种类型的集合是map和序列:
map:
one: 1
two: 2
three: 3
sequence:
- one
- two
- three
标量值是单独的值(与集合相反)。
3.2 YMAL中的标量类型
在YAML的Helm方言中,值的标量数据类型由一组复杂的规则决定,包括用于资源定义的Kubernetes模式。但在推断类型时,以下规则往往适用。
如果一个整数或浮点数是一个无引号的裸字,它通常被视为一个数字类型:
count: 1
size: 2.34
但是如果它们被引号包裹,就会被当作字符串:
count: "1" # <-- string, not int
size: '2.34' # <-- string, not float
布尔值也是如此:
isGood: true # bool
answer: "true" # string
表示空值的单词是 null
(不是nil
)。
注意,
port: "80"
是有效的YAML,它可以通过模板引擎和YAML解析器,但是如果Kubernetes期望port
是整数,则会失败。
在某些情况下,可以使用YAML节点标记强制进行特定类型推断:
coffee: "yes, please"
age: !!str 21
port: !!int "80"
在上面,!!str
告诉解析器 age
是一个字符串,即使它看起来像一个整型数。port
被当作一个整型数,即使它被引号包裹。
3.3 YMAL中的字符串
我们在YAML文档中放置的大部分数据都是字符串。YAML有多种表示字符串的方法。本节解释这些方法并演示如何使用其中一些方法。
有三种“内联”方式来声明一个字符串:
way1: bare words
way2: "double-quoted strings"
way3: 'single-quoted strings'
所有内联样式必须在一行上。
- 裸字没有使用引号进行包裹,也不会进行转义。由于这个原因,你必须小心哪些字符可以使用。
- 双引号字符串可以使用
\
转义特定的字符。例如"\"Hello\", she said"
您可以使用\n
来转义换行符。 - 单引号字符串是“字面量”字符串,不能使用
\
来转义字符。唯一的转义序列是''
,它被解码为一个'
。
除了单行字符串,你可以声明多行字符串:
coffee: |
Latte
Cappuccino
Espresso
上面将把 coffee
的值视为一个单独的字符串,等价于 Latte\nCappuccino\nEspresso\n
。
注意,|
后面的第一行必须正确地缩进。所以我们可以通过这样做来破坏上面的例子:
coffee: |
Latte
Cappuccino
Espresso
因为Latte不有正确的缩进,我们会得到这样的错误:
Error parsing file: error converting YAML to JSON: yaml: line 7: did not find expected key
在模板中,有时在多行文档中放置伪“第一行”内容会更安全,这样可以防止出现上述错误:
coffee: |
# Commented first line
Latte
Cappuccino
Espresso
注意,无论第一行是什么,它都将保留在字符串的输出中。因此,如果你使用这种技术将文件的内容注入到 ConfigMap
中,那么注释的类型应该与读取该条目的内容所期望的类型相同。
3.4 在多行字符串中控制空格
在上面的例子中,我们使用 |
来表示一个多行字符串。但是请注意,字符串的内容后面跟了一个尾随的 \n
。如果我们想让YAML处理器去掉后面的换行符,我们可以在|
后面加上一个-
:
coffee: |-
Latte
Cappuccino
Espresso
现在 coffee
的值为:Latte\nCappuccino\nEspresso
(没有末尾的\n
)。
其他时候,我们可能希望保留所有的末尾空格。我们可以用 |+
符号来实现:
coffee: |+
Latte
Cappuccino
Espresso
another: value
现在 coffee
的值为:Latte\nCappuccino\nEspresso\n\n\n
。
文本块内的缩进被保留下来,结果也保留了换行符:
coffee: |-
Latte
12 oz
16 oz
Cappuccino
Espresso
在上面的例子中,coffee
的值为 Latte\n 12 oz\n 16 oz\nCappuccino\nEspresso
。
3.5 缩进和模板
在编写模板时,你可能希望将文件的内容注入到模板中。正如我们在前几章中看到的,有两种方法:
- 使用
{{ .Files.Get "FILENAME" }}
获取chart中文件的内容。 - 使用
{{ include "TEMPLATE" . }}
渲染模板,然后将其内容放入chart中。
在向YAML插入文件时,最好理解上面的多行规则。通常,插入静态文件的最简单方法是这样做:
myfile: |
{{ .Files.Get "myfile.txt" | indent 2 }}
请注意我们如何执行上面的缩进:indent 2
告诉模板引擎 myfile.txt
中的每一行缩进两个空格。注意,我们没有缩进模板行。这是因为如果这样做,第一行的文件内容将缩进两次。
3.6 折叠多行字符串
有时你希望用多行来表示YAML中的一个字符串,但希望在解释它时将其视为一个长行。这就是所谓的“折叠”。声明一个折叠块,使用 >
代替 |
:
coffee: >
Latte
Cappuccino
Espresso
以上 coffee
的值为 Latte Cappuccino Espresso\n
。请注意,除了最后一个换行外,其余都将转换为空格。你可以将空白控制与折叠的文本标记合并,因此>-
将替换或修剪所有换行。
注意,在折叠语法中,缩进文本将保留行。
coffee: >-
Latte
12 oz
16 oz
Cappuccino
Espresso
以上将生成 Latte\n 12 oz\n 16 oz\nCappuccino Espresso
。注意,空格和换行仍然在那里。
3.7 将多个文档嵌入到一个文件中
可以将多个YAML文档放入单个文件中。这是通过给一个新文档加上前缀
---
并以...
结尾来实现的。
- 在很多情况下,
---
或...
其中之前可以省略。
---
document:1
...
---
document: 2
...
在Helm中的一些文件不能包含多个文档。例如,如果在一个 values.yaml
文件中提供多个文档,也只使用第一个。
然而,模板文件可能有多个文档。当这种情况发生时,文件(及其所有文档)在模板渲染期间被视为一个对象。但是,生成的YAML在被提供给Kubernetes之前被分割成多个文档。
我们建议在绝对必要的情况下才一个文件使用多个文档,因为在一个文件中包含多个文档可能很难调试。
3.8 YAML是JSON的超集
因为YAML是JSON的超集,所以任何有效的JSON文档都应该是有效的YAML。
{
"coffee": "yes, please",
"coffees": [
"Latte", "Cappuccino", "Espresso"
]
}
以上的另一种表达方式:
coffee: yes, please
coffees:
- Latte
- Cappuccino
- Espresso
两者可以混用(小心):
coffee: "yes, please"
coffees: [ "Latte", "Cappuccino", "Espresso"]
这三者都应该解析为相同的内部表示。
而这意味着文件如 values.yaml
可能包含JSON数据,Helm不认为 .json
后缀是有效的。
3.9 YAML锚
YAML规范提供了一种方法来存储对值的引用,然后通过再引用该值。YAML称之为“锚定“:
coffee: "yes, please"
favorite: &favoriteCoffee "Cappucino"
coffees:
- Latte
- *favoriteCoffee
- Espresso
上述 &favoriteCoffee
设置了一个指向 Cappuccino
的引用。随后引用通过 *favoriteCoffee
使用。所以 coffees
变为 Latte, Cappuccino, Espresso
。
虽然有一些情况下锚是有用的,但是它们有一个方面可能会导致一些细微的bug:第一次使用YAML时,引用会被扩展,然后被丢弃。
因此,如果我们解码,然后重新编码上面的例子,得到的YAML将是:
coffee: yes, please
favorite: Cappucino
coffees:
- Latte
- Cappucino
- Espresso
因为Helm和Kubernetes经常读取、修改和重写YAML文件,所以会丢失锚。
评论区