5月28日 03:55

YAML 是什么?语法规则和常见踩坑一次讲清

YAML 是 Kubernetes、Docker Compose、GitHub Actions 这些工具的配置文件格式——如果你在做云原生或 DevOps,YAML 几乎天天写。但它有个让人又爱又恨的特点:语法看起来简单,踩坑却一个接一个。

YAML 是什么

YAML 全称"YAML Ain't Markup Language"(递归缩写,故意这么玩的),是一种面向人类的数据序列化格式。和 JSON、XML 一样,它用来表示结构化数据,但设计目标很明确:让人能直接读和写。

一句话区分:JSON 是给机器看的,YAML 是给人看的。

YAML 的三种数据结构

所有 YAML 内容都由这三种结构组合而成,理解它们就能看懂任何 YAML 文件。

映射(键值对)

yaml
name: nginx port: 8080

冒号后面必须跟一个空格,这是 YAML 最基本的规则。漏掉这个空格会直接报解析错误。

序列(列表)

yaml
features: - authentication - logging - monitoring

列表项用 - 开头,注意连字符后面也有一个空格。

标量(单个值)

字符串、数字、布尔值、null 都是标量。YAML 会自动推断类型:

yaml
version: 1.2 # 浮点数 debug: true # 布尔值 host: localhost # 字符串 timeout: null # null

自动推断有时候会坑人。比如 off 会被解析为 falseyes 会被解析为 true,版本号 1.10 看起来像浮点数。需要原样保留字符串时,加上引号:

yaml
version: "1.10" # 强制字符串,不会被转成 1.1 switch: "off" # 强制字符串,不会被转成 false

这个坑在生产环境排查过的人都知道——一个引号之差,配置就跑偏了。

YAML vs JSON vs XML

实际项目中这三种格式经常需要选择,核心区别一目了然:

特性YAMLJSONXML
注释支持 #不支持支持
多行字符串支持 `>`不支持
可读性
解析速度
数据类型丰富(含日期、时间戳)基本类型全是字符串
超集关系JSON 的超集

YAML 是 JSON 的超集,意味着任何合法的 JSON 写法直接放进 YAML 文件也能解析。所以在 YAML 里嵌入 JSON 片段是完全合法的。

选择建议:配置文件用 YAML,API 数据交换用 JSON,需要严格验证结构用 XML。

缩进:YAML 的命门

YAML 用缩进表示层级关系,这条规则没有商量的余地:

  • 只能用空格,不能用 Tab。混用空格和 Tab 是 YAML 解析报错的第一大原因
  • 同层元素必须对齐。缩进空格数不限制(2 个或 4 个都行),但同一层必须一致
  • 推荐 2 个空格缩进,Kubernetes 和 Docker Compose 的官方示例都用 2 空格
yaml
# 正确:同层对齐 server: host: localhost port: 8080 features: - auth - logging # 错误:缩进不对齐,解析器直接报错 server: host: localhost port: 8080 # 多了一个空格

大多数编辑器可以设置"将 Tab 转换为空格",强烈建议开启。VS Code 底部状态栏点击"Tab Size"就能改。

多行字符串:配置文件的救星

YAML 处理多行文本的方式比 JSON 优雅得多,有两种模式:

| 保留换行(literal block):每一行换行原样保留,适合脚本、证书等

yaml
startup_script: | #!/bin/bash echo "Starting service..." sleep 3 systemctl start app

> 折叠换行(folded block):连续换行合并成一个空格,适合长段落文本

yaml
description: > This is a long description that will be folded into a single line when parsed.

在 Docker Compose 里写启动命令、在 Kubernetes 里挂载配置文件,这两种写法用得最多。

锚点和引用:YAML 的复用机制

当配置文件里有重复内容时,锚点(&)和引用(*)能减少冗余:

yaml
defaults: &defaults timeout: 30 retries: 3 log_level: info production: <<: *defaults log_level: warning retries: 5 staging: <<: *defaults timeout: 10

&defaults 定义锚点,*defaults 引用它,<<: 表示合并(merge)。这在多环境配置中非常实用——基础配置写一次,各环境只覆盖差异项。

多文档分隔

一个 YAML 文件可以包含多个文档,用 --- 分隔。Kubernetes 的资源清单经常这么用:

yaml
--- apiVersion: v1 kind: Service metadata: name: nginx-svc --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy

一个文件管理多个资源,kubectl apply 一次搞定。

真实项目配置示例

一个完整的 Docker Compose 配置,把前面提到的语法串起来:

yaml
version: "3.8" x-logging: &default-logging # 锚点定义 driver: json-file options: max-size: "10m" max-file: "3" services: web: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro logging: *default-logging # 锚点引用 healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 30s timeout: 10s retries: 3 db: image: postgres:15 environment: POSTGRES_DB: myapp POSTGRES_PASSWORD: "${DB_PASSWORD}" # 引用环境变量 volumes: - db-data:/var/lib/postgresql/data logging: *default-logging volumes: db-data:

这个配置用到了映射、序列、锚点引用、多行字符串、环境变量插值——基本上 YAML 的核心特性全覆盖了。

常见踩坑清单

现象解决方案
Tab 混用空格解析报错"found character that cannot start any token"编辑器开启"Tab 转空格"
冒号后没空格key:value 被当成字符串写成 key: value
自动类型转换offfalse1.101.1加引号强制字符串
缩进不一致解析报错或数据嵌套错误保持同级缩进对齐
特殊字符未转义:, {, [, , 等字符导致解析异常用引号包裹含特殊字符的值
文件编码问题含中文时解析乱码确保文件为 UTF-8 编码

这些坑在实际项目中反复出现,养成习惯比事后排查高效得多。

标签:YAML