一、介绍
YAML(YAML Ain’t Markup Language)作为一种人类可读性强的配置语言被广泛应用在各个应用系统中,包括:Kubernetes、Ansible、Docker Compose等等。
1.1 基本语法规则
键值对:
name: John
age: 30
缩进表示层级:
- 使用空格缩进,禁止使用 tab
- 通常每层缩进用 2 或 4 个空格
person:
name: John
age: 30
列表(数组):
persons:
- name: John
age: 30
- name: Mike
age: 28
嵌套结构:
server:
host: localhost
ports:
- 80
- 443
多行字符表示:
- 使用
|
表示保留换行 - 使用
>
表示折叠成一行
description: |
Line one
Line two
summary: >
This is a very long
line that will be folded.
注释:
name: John # 这是注释
布尔、null、数字:
enabled: true
disabled: false
nothing: null
count: 100
1.2 常见使用错误
- 缩进混用空格和tab
- 缩进不对齐
- 键名重复
- 行尾隐藏字符(如空格、零宽字符等不可见字符)
二、行尾不可见字符
常见的 YAML 行尾不可见字符
- 空格(space,
0x20
)- 多余空格有时会影响多行字符串的拼接或注释识别。
- 制表符(tab,
0x09
)- YAML 禁止使用 tab 来缩进,但若 tab 出现在行尾,不一定会报错,却可能影响格式或行为。
- 不可见的 Unicode 字符(如
U+200B
零宽空格)- 通常是从复制粘贴中引入,肉眼难以察觉。
三、Go 程序解析
行尾不可见字符,程序解析 YAML 内容时,并不会读取行尾不可见字符,如果希望程序读取某个变量时,需要内容末尾的空格,那么整个内容需要通过引号进行包裹。
例如:
version: 1
name: 'Alice '
age: 30
四、Go 程序渲染
以下程序用于将 test.yaml 中的内容嵌入作为 Config 结构体实例中 Content 变量的内容,并输出为 Config 结构体的 yaml 文本。
package main
import (
_ "embed"
"fmt"
"gopkg.in/yaml.v3"
)
type Config struct {
Content string `yaml:"content"`
}
//go:embed test.yaml
var content string
func main() {
m := Config{
Content: content,
}
raw, err := yaml.Marshal(m)
if err != nil {
panic(err)
}
fmt.Println(string(raw))
}
首先,正常 test.yaml 内容如下:
version: 1
name: Alice
age: 30
对应输出文本如下:
content: |-
version: 1
name: Alice
age: 30
可见,content 中的内容,依旧保持着 yaml 语法的人类可读性强的特点。
然而,如果内容中某一行末尾存在不可见字符,比如下面 test.yaml 中的 name 行 Alice 后面还有一个空格:
version: 1
name: Alice
age: 30
那么在渲染文本时,YAML 就会对内容进行转义,对应输出文件如下:
content: "version: 1\n\nname: Alice \nage: 30"
那么,遇到确实内容末尾需要加上空格,就必须使用引号进行包裹,比如:
version: 1
name: 'Alice '
age: 30
其对应输出如下:
content: |-
version: 1
name: 'Alice '
age: 30
依旧能够保持良好的可读性。
五、Kubernetes Config Map
以下是一份因为行尾跟随了不可见字符而渲染之后的 Kubernetes Config Map 配置:
apiVersion: v1
data:
api-config: "server:\n address: 0.0.0.0:80 \n mode: debug"
kind: ConfigMap
而这样的因为行尾不可见字符渲染出来的配置,往往会给排查环境问题工作带来麻烦。
而其对应正常内容应该如下:
apiVersion: v1
data:
api-config: |-
server:
address: 0.0.0.0:80
mode: debug
kind: ConfigMap
六、检查与防范
6.1 检查工具 cat
通过 cat 命令可以显示不可见字符:
$ cat -A file.yaml
其中:末尾 $
表示行尾
version: 1$
$
name: Alice $
age: 30$
6.2 清理
通过 sed 命令可批量移除行尾空格:
$ sed -i 's/[ \t]*$//' file.yaml
6.4 预防建议
- 统一使用空格缩进,禁用 tab
- 启用编辑器的“保存时自动去除行尾空格”
- 使用版本控制 + Lint 工具进行 YAML 格式校验
- 避免从网页、PDF、Excel 等非纯文本源复制内容进 YAML