YAML,全称”YAML Ain’t Markup Language”(YAML 并非标记语言),是一种方便人类阅读的数据序列化格式,广泛用于配置文件和编程语言之间的数据交换。与 JSON 或 XML 不同,YAML 注重简洁性和可读性,因此对于每天处理配置管理的开发者、DevOps 工程师和系统管理员来说尤其实用。

YAML 的核心设计旨在以一种易于人类阅读和机器解析的方式存储结构化数据,它使用缩进而非复杂的语法,这意味着 YAML 文件通常看起来像一个大纲或结构化列表。这使得它不像那些充斥着括号、花括号或冗长标签的格式那样令人生畏。

例如,以下是一个典型的 YAML 格式文件:

person:
  name: RULTR
  age: 30
  skills:
    - Python
    - YAML
    - Docker

此示例描述了一个人,其中包含姓名、年龄和一系列技能。无需过多解释,大多数人都能猜出这些数据代表什么。这就是 YAML 的魔力所在——它看起来自然直观。

YAML 不仅用于配置,还用于数据交换、测试自动化、CI/CD 流水线和应用程序编制。多年来,YAML 已成为现代开发实践的基石,尤其是在 Kubernetes、Docker 和 Ansible 中得到广泛应用之后。

为什么 YAML 在 DevOps 中如此流行

YAML 的流行源于其简洁性、可读性和灵活性。在当今快节奏的软件开发世界中,工具和团队需要一目了然的配置,而 YAML 正是如此。

以下是开发人员和 DevOps 专业人员青睐 YAML 的原因:

  1. 可读性 – YAML 文件视觉上简洁,依靠缩进而不是像 {} 或 <> 这样的符号,这减轻了认知负担
  2. 广泛支持 – 从 Kubernetes 到 Docker Compose 再到 Ansible,许多现代工具都严重依赖 YAML 作为其配置语言
  3. 以人为本的设计 – YAML 的设计以人为本,这与最初为机器创建的 JSON 不同
  4. 灵活的结构 – YAML 支持标量(字符串、数字、布尔值)、列表和字典。这意味着它可以表示几乎任何类型的结构化数据
  5. 跨语言兼容性 – 大多数编程语言(包括 Python、JavaScript、Go、Ruby 和 Java)都通过库和解析器支持 YAML

在实践中,YAML 可帮助团队维护简洁、版本控制的配置。在使用 GitHub Actions、CircleCI 或 Kubernetes 清单等工具时,YAML 文件经常被共享和审查。其可读性确保不仅开发人员,项目经理或系统运维人员也能理解正在发生的事情。

正是这种人性化可读性和机器易用性的结合,使 YAML 在 DevOps 和云原生生态系统中脱颖而出。

YAML 的演变历史

YAML 的故事始于 21 世纪初。YAML 最初由 Clark Evans 于 2001 年开发,旨在成为 XML 的一种人性化替代方案。当时,XML 是结构化数据交换的主流格式,但其冗长和复杂性使其难以使用。YAML 作为一种全新的替代方案应运而生,并将简洁性放在首位。

“YAML”最初代表”Yet Another Markup Language”,但随着其目标逐渐清晰,开发人员将其重新定义为”YAML Ain’t Markup Language”——这巧妙地暗示了 YAML 反对被视为标记语言的立场。相反,YAML 严格来说是一种数据序列化格式。

自诞生以来,YAML 经历了多个版本:

  • YAML 1.0(2001 年):第一个版本,奠定了基础
  • YAML 1.1(2005 年):扩展了功能,引入了更多数据类型
  • YAML 1.2 (2009):使 YAML 与 JSON 完全兼容,允许 JSON 文件被视为有效的 YAML

YAML 的演进与 DevOps、容器化和云原生计算的兴起相呼应。随着 Kubernetes 成为领先的容器编排系统,YAML 成为定义基础设施和工作负载的事实标准。

如今,YAML 已不再只是一种配置文件格式,而是现代软件基础设施的支柱。从云配置到 CI/CD 自动化,YAML 继续发挥着关键作用,并在各行各业得到广泛应用。

YAML 基础知识

YAML 语法概述

乍一看,YAML 的语法就像是 JSON 的精简版。不过,YAML 不使用花括号和方逗号,而是依靠缩进和空格。这使得 YAML 文件看起来像是结构化的大纲或项目符号列表,因此人类阅读起来非常轻松。

YAML 语法中的三个关键元素是:

  1. 缩进:定义结构(类似于 Python)
  2. 键值对:用于映射(类似于 Python 中的字典)
  3. 列表:用连字符 – 表示每个项目。

下面的比较有助于快速说明 JSON 和 YAML 的区别,JSON 示例:

{
  "name": "Alice",
  "age": 28,
  "languages": ["Python", "JavaScript"]
}

YAML 的等效示例:

name: Alice
age: 28
languages:
  - Python
  - JavaScript

需要注意的是,YAML 会在非必要的情况下避免使用引号、逗号和括号。这样一来,结构简洁,但含义仍然相同。

另一个重要方面是可以使用注释,注释以”#”开头。这与 JSON 不同(JSON 不支持注释),YAML 支持内联注释,这使得注释配置更加容易:

# This is a YAML comment
app:
  version: 1.0  # app version

这就是 YAML 的设计理念:如果人类可以轻松阅读,那么它就是好的 YAML。

缩进和结构

缩进是 YAML 的基石。与其他空格可选的格式不同,YAML 需要缩进来定义层次结构。这既是优点也是缺点——它使文件整洁,但如果空格不一致,也会带来出错的风险。

YAML 缩进的关键规则:

  • 仅使用空格(不允许使用制表符)
  • 缩进通常为每层 2 个空格
  • 嵌套结构依赖于缩进深度

正确缩进示例:

server:
  host: localhost
  port: 8080

错误缩进示例:

server:
 host: localhost   # 错误,只空了一格
   port: 8080      # 错误,空了三格

由于缩进定义了层次结构,YAML 的使用体验与 Python 类似。许多了解 Python 的开发者认为 YAML 非常直观,因为它们共享相同的结构化方法。

为了避免错误,最好将文本编辑器或 IDE 配置为自动使用空格而不是制表符。许多与 YAML 相关的错误都是由隐藏的制表符引起的。

键值对

键值对是 YAML 的基本构成块。键表示名称,值表示数据。它们共同构成映射(在编程语言中也称为字典或哈希值)。

基本结构如下所示:

key: value

值可以是字符串、数字、布尔值,甚至是复杂的嵌套结构。例如:

user:
  name: Alice
  age: 25
  is_active: true

上述示例中:

  • name 是字符串
  • age 是数字
  • is_active 是 布尔值

YAML 支持内联映射和块映射:

# 内联映射
person: { name: John, age: 30 }

# 块映射
person:
  name: John
  age: 30

块映射更易读且更常用,尤其是在较大的配置文件中。

键值对的强大之处在于它们允许嵌套。这使得 YAML 能够极其灵活地表示复杂的配置,例如 Kubernetes 清单或 CI/CD 流水线。

列表和数组

YAML 中的列表使用连字符 (-) 表示,以便于阅读。与需要方括号的 JSON 数组不同,YAML 列表的编写方式类似于清单:

fruits:
  - Apple
  - Banana
  - Orange

示例表示一个字符串数组。列表也可以包含对象:

users:
  - name: Alice
    age: 25
  - name: Bob
    age: 30

这里,每个列表项都是一个字典,它们有自己的键和值。

YAML 也支持内联列表,尽管它们的可读性较差:

fruits: [Apple, Banana, Orange]

对于复杂的配置,块状列表更受欢迎,因为它们更易于维护和注释。

列表还可以嵌套在映射中,从而创建多级结构,非常适合部署文件、Docker Compose 服务或 Ansible 中的清单文件。

YAML 的注释

YAML 相较于 JSON 的优势之一是它支持注释,这使得文件更易于记录和理解。YAML 中的注释以 # 符号开头,一直到行末。

例如:

# Application configuration
app:
  name: MyApp  # App name
  version: 1.2
  debug: true  # Enable debug mode

处理大型 YAML 文件时,注释至关重要。它允许团队解释配置、提供说明或为未来的维护人员留下注释。

在协作环境中,注释通常用作内联文档,使开发人员无需查阅外部资源即可了解特定配置的功能。

然而,需要注意的是,YAML 注释会被解析器忽略,这意味着它们对执行没有任何影响。它们的目的仅仅是为了指导用户。

YAML 数据类型和结构

YAML 中的标量

标量是 YAML 中最简单的数据类型,表示单个值,例如字符串、数字和布尔值。YAML 处理标量的方式非常灵活,除非必要,否则您可以不用引号来书写它们。

标量示例:

string_value: Hello World
integer_value: 42
float_value: 3.14
boolean_true: true
boolean_false: false
null_value: null

YAML 还允许使用标签进行显式输入:

explicit_integer: !!int "42"
explicit_float: !!float "3.14"

这种灵活性使得 YAML 更容易编写,但也容易引起混淆。例如,除非明确引用,否则 YAML 会将某些单词(例如 yes、no、on、off)解释为布尔值。例如:

light: on    # 解释为 true
switch: "on" # 解释为字符串

因此,当需要明确的字符串值时,最佳做法是使用引号。

字符串、数值和布尔值

字符串可以为空白或使用引号:

plain_string: Hello World
single_quote: 'YAML is easy'
double_quote: "Supports escape characters like \n"

YAML 还支持多行字符串,这对于长文本块来说至关重要:

description: |
  This is a multi-line
  string in YAML.

“|”可以保留格式,而”>”将文本折叠为一行:

note: >
  This is a long string
  but folded into one line.

数值

YAML 支持整数、浮点数和科学计数法:

int_value: 100
float_value: 3.1415
scientific: 1.23e4

布尔值

布尔值可以用多种方式编写:

flag1: true
flag2: false
flag3: yes
flag4: no

由于”yes”和”no”等词可能会引起歧义,因此坚持使用”true”和”false”更安全。

复杂结构(嵌套数据)

YAML 最大的优势之一在于它能够轻松表示嵌套数据结构。这也是它在配置管理中如此受欢迎的原因。

例如,YAML 中的 Web 服务器配置可能如下所示:

server:
  host: localhost
  port: 8080
  routes:
    - path: /home
      method: GET
    - path: /login
      method: POST

这里,我们有:

  • 映射(server)
  • 嵌套的键值对(host、port)
  • 字典列表(routes)

这种嵌套结构使 YAML 能够以自然易读的格式描述现实世界中的系统,例如 Kubernetes Pod、Docker Compose 服务或 CI/CD 流水线。

与 JSON 或 XML 相比,嵌套的 YAML 结构更简洁,需要的符号更少,因此更不容易出错,也更直观。

YAML 高级功能

锚点和别名

锚点 (&) 和别名 (*) 是两个强大的 YAML 功能,可让用户重复使用数据而无需重复操作。

defaults: &defaults
  retries: 3
  timeout: 30
service1:
  <<: *defaults
  host: service1.local
service2:
  <<: *defaults
  host: service2.local

这里:

  • &defaults 定义一个锚点
  • *defaults 引用它
  • << 将锚点合并到另一个映射中。

这在大型配置文件中非常有用,因为重复的值会使文件更难维护。而 YAML 允许您一次定义,即可在任何地方重复使用。

例如,在 Kubernetes 清单中,锚点可以通过在多个部署中重复使用配置模板来简化服务定义。

多行字符串

处理日志、长描述或代码片段时,YAML 提供了一些运算符来优雅地处理多行字符串。

文字块(|)——保留换行符:

log: | Line one Line two Line three

折叠块(>)——将换行符折叠成空格:

message: > This text will be written in one continuous line.

“|”和”>”之间的选择取决于是否需要保留格式。如果格式很重要(例如 SQL 查询、诗歌或配置片段),则使用”|”。如果不是,则使用”>”可以使文本更紧凑。

标签和自定义数据类型

YAML 支持标签来明确定义数据类型。标量通常会被自动推断,而标签则能赋予开发者更多控制权。

示例:

int_value: !!int "42"
float_value: !!float "3.14"
bool_value: !!bool "true"

我们还可以为特定应用程序定义自定义标签,尤其是在使用支持扩展架构的工具解析 YAML 时。

例如,在某些配置系统中,可能会看到:

date: !!timestamp "2025-08-18"

标签使 YAML 更加精确,减少了自动推理可能导致错误的情况下的歧义。

使用键别名

除了锚点和别名之外,YAML 还支持合并键。这允许一个映射继承另一个映射的值,从而减少冗余。

示例:

defaults: &defaults
  retries: 5
  timeout: 60
service1:
  <<: *defaults
  host: api.service1.com
service2:
  <<: *defaults
  host: api.service2.com

service1 和 service2 都继承了默认的重试次数和超时设置,同时覆盖了 host 的配置。

此模式在 Docker Compose 和 Kubernetes 清单中被广泛使用,在这些清单中,服务通常共享通用配置。它确保了一致性并简化了维护,尤其是在具有多种配置的大型项目中。

YAML 不仅仅是一种配置文件格式,更是现代软件基础架构的基石。其简洁性、易读性和灵活性使其成为开发者、DevOps 工程师和系统管理员的理想之选。

从 Kubernetes 清单到 CI/CD 流水线,从 Docker Compose 文件到 Ansible 剧本,YAML 在当今的技术版图中无处不在。虽然与 JSON 相比,它在速度和内存效率方面存在局限性,但其人性化的设计在大多数实际场景中弥补了这些问题。

通过遵循最佳实践、使用 linters 和验证器并牢记安全性,YAML 可以在各种规模的项目中安全有效地使用。展望未来,YAML 很可能仍将是 DevOps 和云原生系统的默认配置语言,并继续塑造团队管理和自动化基础架构的方式。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注