附录:YAML 技术
本指南的大部分内容都集中在编写模板语言上。在本节中,我们将了解 YAML 格式。YAML 具有我们作为模板作者可以用来使我们的模板更不易出错且更易于阅读的一些有用功能。
标量和集合
根据 YAML 规范,有两种类型的集合,以及许多标量类型。
两种类型的集合是映射和序列
map:
one: 1
two: 2
three: 3
sequence:
- one
- two
- three
标量值是单个值(与集合相反)
YAML 中的标量类型
在 Helm 的 YAML 方言中,值的标量数据类型由一组复杂的规则决定,包括资源定义的 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
是一个字符串,即使它看起来像一个 int。而 port
被视为 int,即使它被加了引号。
YAML 中的字符串
我们放在 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,则注释应是读取该条目时所期望的类型。
控制多行字符串中的空格
在上面的示例中,我们使用 |
来指示多行字符串。但请注意,我们的字符串内容后面跟着一个尾随的 \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
。
缩进和模板
在编写模板时,您可能会发现自己想将文件的內容注入模板。正如我们在前几章中看到的那样,有两种方法可以做到这一点
- 使用
{{ .Files.Get "FILENAME" }}
获取图表中文件的內容。 - 使用
{{ include "TEMPLATE" . }}
渲染模板,然后将其內容放置到图表中。
在将文件插入 YAML 时,了解上面的多行规则很重要。通常,插入静态文件的简便方法是执行以下操作
myfile: |
{{ .Files.Get "myfile.txt" | indent 2 }}
请注意我们上面的缩进方式:indent 2
告诉模板引擎将“myfile.txt”中的每一行缩进两个空格。请注意,我们没有缩进该模板行。这是因为如果我们这样做了,第一行的文件內容将缩进两次。
折叠的多行字符串
有时您希望在 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
。请注意,空格和换行符都还在。
在一个文件中嵌入多个文档
可以将多个 YAML 文档放置在一个文件中。这是通过在新的文档前面加上 ---
并用 ...
结束文档来完成的
---
document:1
...
---
document: 2
...
在许多情况下,可以省略 ---
或 ...
。
Helm 中的一些文件不能包含多个文档。例如,如果在 values.yaml
文件中提供了多个文档,则只会使用第一个文档。
但是,模板文件可能包含多个文档。在这种情况下,该文件(及其所有文档)在模板渲染期间被视为一个对象。但随后,生成的 YAML 在被馈送到 Kubernetes 之前会被拆分为多个文档。
我们建议仅在绝对必要时才使用每个文件多个文档。在文件中使用多个文档可能难以调试。
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
视为有效的后缀。
YAML 锚点
YAML 规范提供了一种方法来存储对值的引用,然后通过引用来引用该值。YAML 将此称为“锚定”
coffee: "yes, please"
favorite: &favoriteCoffee "Cappuccino"
coffees:
- Latte
- *favoriteCoffee
- Espresso
在上面的示例中,&favoriteCoffee
设置对 Cappuccino
的引用。稍后,该引用将被用作 *favoriteCoffee
。因此 coffees
变成 Latte, Cappuccino, Espresso
。
虽然锚点在一些情况下很有用,但它们的一个方面会导致一些细微的错误:第一次使用 YAML 时,引用会被扩展,然后被丢弃。
因此,如果我们要解码然后重新编码上面的示例,生成的 YAML 将是
coffee: yes, please
favorite: Cappuccino
coffees:
- Latte
- Cappuccino
- Espresso
因为 Helm 和 Kubernetes 通常会读取、修改然后重写 YAML 文件,所以锚点会丢失。