YAML 是 Docker、Kubernetes、CI/CD 流水线和无数其他工具的首选配置格式。尽管语法对人类友好,但 YAML 出错却出奇地容易。本指南涵盖最常见的 YAML 错误及修复方法。
YAML 的使用场景
- Docker Compose (docker-compose.yml)
- Kubernetes 清单文件
- GitHub Actions / GitLab CI 工作流
- Ansible 剧本
- 配置文件(Prettier、ESLint 等)
基本 YAML 语法规则
缩进
YAML 使用空格(不能用制表符)进行缩进。同一层级的空格数必须一致:
# ✅ Correct (2-space indentation)
server:
host: localhost
port: 8080
database:
name: myapp
pool: 10
# ❌ Wrong (tab characters or inconsistent spaces)
server:
host: localhost # Tab character - INVALID!
port: 8080 # 3 spaces - inconsistent!键值对
键和值之间用冒号加空格分隔:
# ✅ Correct
name: John Doe
port: 8080
# ❌ Wrong - missing space after colon
name:John Doe多行字符串
YAML 提供两种块标量样式来处理多行字符串:
# | (literal block) - preserves newlines
description: |
This is line one.
This is line two.
Each newline is preserved.
# > (folded block) - folds newlines to spaces
description: >
This is a long paragraph
that will be joined into
a single line.YAML 数据类型
| 类型 | 语法 | 示例 |
|---|---|---|
| String | plain, "quoted", 'quoted' | name: John |
| Integer | 42, 0xFF, 0o77 | port: 8080 |
| Float | 3.14, .inf, .nan | pi: 3.14159 |
| Boolean | true/false | debug: true |
| Null | null, ~, (empty) | value: null |
| Date | YYYY-MM-DD | date: 2026-02-10 |
"挪威问题"
在 YAML 1.1 中,`NO`(如挪威的国家代码)会被解释为布尔值 `false`。因为 YAML 1.1 将 yes/no、on/off、true/false 视为布尔值。务必给国家代码等类似值加引号:
# ❌ YAML 1.1 interprets these as booleans!
country: NO # → false
answer: yes # → true
switch: on # → true
# ✅ Fix: quote the values
country: "NO" # → string "NO"
answer: "yes" # → string "yes"
switch: "on" # → string "on"集合:列表和映射
# List (sequence)
fruits:
- apple
- banana
- cherry
# Nested map
database:
host: localhost
port: 5432
credentials:
user: admin
password: secret
# Inline / Flow style
fruits: [apple, banana, cherry]
point: {x: 10, y: 20}十大常见 YAML 错误
| # | 错误 | 原因 | 修复 |
|---|---|---|---|
| 1 | Tab 字符错误 | 使用制表符缩进 | 将所有制表符替换为空格(2或4个) |
| 2 | 不一致的缩进 | 混用 2 空格和 4 空格缩进 | 在整个文件中使用一致的缩进 |
| 3 | 冒号后缺少空格 | 写成 `key:value` 而非 `key: value` | 冒号后始终加一个空格 |
| 4 | 未引用的特殊字符 | 值包含 : 或 # 但未加引号 | 给包含特殊字符的字符串加引号 |
| 5 | 布尔值强制转换 | yes/no/on/off/NO 被解释为布尔值 | 给看起来像布尔值的值加引号:`"yes"`、`"NO"` |
| 6 | 包含冒号的字符串 | `url: http://example.com` 在第二个冒号处断开 | 给整个值加引号:`url: "http://example.com"` |
| 7 | 重复的键 | 同一个映射中出现两次相同的键 | 删除重复的键(最后一个生效,但容易出错) |
| 8 | 尾部空白 | 值后面有不可见的空格 | 配置编辑器自动删除尾部空白 |
| 9 | 列表缩进错误 | 列表项与父键未对齐 | 将 `-` 与子缩进层级对齐 |
| 10 | 缺少文档分隔符 | 多个文档之间没有 `---` 分隔 | 在 YAML 文档之间添加 `---` |
YAML vs JSON vs TOML
| 特性 | YAML | JSON | TOML |
|---|---|---|---|
| Comments | # support | None | # support |
| Multi-line strings | | and > | \\n only | """ triple quotes |
| Data types | Rich (dates, etc.) | Basic (6 types) | Rich (dates, etc.) |
| Readability | High | Medium | High |
| Machine parsing | Complex | Simple | Medium |
| Best for | Config files | APIs, data exchange | App config |
验证最佳实践
- 始终在 CI/CD 流水线中使用 YAML 校验器
- 配置编辑器显示空白字符
- 使用 2 空格缩进(最常见约定)
- 给可能被误解的字符串加引号(布尔值、前导零的数字)
- 对复杂配置使用 YAML 模式验证
- 尽可能保持 YAML 文件小而模块化
常见问题
YAML 中可以使用制表符吗?
不可以。YAML 严格禁止使用制表符缩进,必须使用空格。大多数编辑器可以配置为按 Tab 键时插入空格。
YAML 中单引号和双引号的区别?
单引号保留字面字符串(无转义序列)。双引号允许转义序列如 \n、\t 和 Unicode 转义。简单字符串用单引号,需要转义字符时用双引号。
如何在 YAML 中表示 null?
可以使用 `null`、`~` 或直接留空。三种方式等价:`key: null`、`key: ~` 和 `key:`。
为什么 YAML 将 "NO" 视为 false?
YAML 1.1 规范将 yes/no、on/off、true/false(不区分大小写)视为布尔值。YAML 1.2 修复了此问题,仅识别 true/false。为安全起见,始终给可能被解释为布尔值的字符串加引号。