1. YAML 概念
YAML (YAML Ain’t Markup Language) 是一种人性化的数据序列化格式:
- 专注于数据而非标记(与 XML 不同)
- 使用简洁的语法表示复杂数据结构
- 可读性高,适合人类编写和阅读
- 广泛应用于配置文件(如 Docker Compose, Ansible, Kubernetes)
2. YAML 核心原理
- 缩进表示层级:类似 Python,使用空格缩进
- 最小化符号:避免引号、括号等干扰符号
- 数据类型推断:自动识别数字、布尔值等类型
- 锚点与引用:支持数据复用(
&
定义锚点,*
引用) - 多文档支持:单个文件可包含多个文档(用
---
分隔)
3. YAML 语法规范
基本结构
# 注释以 # 开头
server: web01 # 键值对
ports:
- 80 # 列表项
- 443
environment: production
config:
max_connections: 1000 # 嵌套对象
timeout: 30
核心语法规则
- 缩进规则:
- 使用空格(不能使用 Tab)
- 同一层级缩进必须一致
- 数据类型:
- 字符串:可加引号也可不加(除非有特殊字符)
- 数字:整数(
42
)、浮点数(3.14
) - 布尔值:
true
/false
或yes
/no
- 空值:
null
或~
- 日期:
2023-11-15
(ISO 8601 格式)
- 数据结构:
- 列表(数组):使用
-
开头 - 对象(字典):使用
key: value
格式
- 列表(数组):使用
- 多行文本:
description: | 这是多行文本 保留所有换行符 summary: > 这是折叠文本 会合并为单行
- 特殊语法:
- 锚点
&name
和引用*name
- 合并
<<: *name
(合并映射)
- 锚点
4. Python YAML API (PyYAML)
安装
pip install pyyaml
核心功能
函数 | 功能 | 主要参数 |
---|---|---|
yaml.safe_load() |
安全解析 YAML | stream (文件或字符串) |
yaml.load() |
解析 YAML(不安全) | stream , Loader |
yaml.safe_dump() |
安全序列化为 YAML | data , stream , indent |
yaml.dump() |
序列化为 YAML | data , default_flow_style |
关键参数
- dump/dump_all:
indent
:缩进空格数default_flow_style
:是否使用流式风格(默认 False)allow_unicode
:是否允许 Unicode 字符sort_keys
:是否按键排序
- load/load_all:
Loader
:指定加载器(推荐yaml.SafeLoader
)
5. YAML 处理流程
6. 应用示例
示例1:基本读写
输入 (Python对象):
data = {
"server": "web01",
"ports": [80, 443],
"environment": "production",
"backup": True,
"config": {
"max_connections": 1000,
"timeout": 30.5
}
}
序列化 (Python → YAML):
import yaml
# 转换为YAML字符串
yaml_str = yaml.dump(data, indent=2)
print(yaml_str)
输出 (YAML字符串):
server: web01
ports:
- 80
- 443
environment: production
backup: true
config:
max_connections: 1000
timeout: 30.5
反序列化 (YAML → Python):
# 从YAML字符串转换回Python对象
loaded_data = yaml.safe_load(yaml_str)
print(loaded_data["ports"][0]) # 输出: 80
示例2:文件操作
写入YAML文件:
config = {
"database": {
"host": "db.example.com",
"port": 3306,
"user": "admin",
"password": "secret"
},
"logging": {
"level": "debug",
"path": "/var/log/app.log"
}
}
with open("config.yaml", "w") as f:
yaml.dump(config, f, indent=4, default_flow_style=False)
生成的config.yaml:
database:
host: db.example.com
port: 3306
user: admin
password: secret
logging:
level: debug
path: /var/log/app.log
读取YAML文件:
with open("config.yaml", "r") as f:
loaded_config = yaml.safe_load(f)
print(loaded_config["database"]["host"]) # 输出: db.example.com
示例3:复杂结构处理
YAML输入 (network.yaml):
network:
devices:
- name: router01
interfaces:
- name: Gig0/0
ip: 192.168.1.1
mask: 255.255.255.0
- name: Gig0/1
ip: 10.0.0.1
mask: 255.255.255.252
ospf:
enabled: true
areas: [0, 1]
- name: switch01
vlan:
default: 1
enabled: yes
Python解析代码:
import yaml
with open("network.yaml") as f:
data = yaml.safe_load(f)
for device in data["network"]["devices"]:
print(f"设备: {device['name']}")
if "interfaces" in device:
for interface in device["interfaces"]:
print(f" 接口: {interface['name']}, IP: {interface['ip']}")
输出:
设备: router01
接口: Gig0/0, IP: 192.168.1.1
接口: Gig0/1, IP: 10.0.0.1
设备: switch01
示例4:锚点与引用
YAML输入:
defaults: &defaults
adapter: postgres
host: localhost
port: 5432
development:
<<: *defaults
database: dev_db
test:
<<: *defaults
database: test_db
Python解析后:
{
'defaults': {
'adapter': 'postgres',
'host': 'localhost',
'port': 5432
},
'development': {
'adapter': 'postgres',
'host': 'localhost',
'port': 5432,
'database': 'dev_db'
},
'test': {
'adapter': 'postgres',
'host': 'localhost',
'port': 5432,
'database': 'test_db'
}
}
示例5:多文档处理
YAML输入 (multi_doc.yaml):
---
server: web01
status: active
...
---
server: db01
status: maintenance
...
Python读取多文档:
with open("multi_doc.yaml") as f:
documents = list(yaml.safe_load_all(f))
for doc in documents:
print(f"服务器: {doc['server']}, 状态: {doc['status']}")
输出:
服务器: web01, 状态: active
服务器: db01, 状态: maintenance
7. 安全注意事项
- 避免使用
yaml.load()
:可能执行任意代码(使用safe_load
代替) - 验证来源:不要加载不可信的 YAML 文件
- 自定义安全加载器:
from yaml import SafeLoader class RestrictedLoader(SafeLoader): pass # 禁用特定标签 RestrictedLoader.add_constructor(None, None)
8. 常见错误处理
# 缩进错误示例
bad_yaml = """
server: web01
ports: # 错误:不应缩进
- 80
"""
try:
data = yaml.safe_load(bad_yaml)
except yaml.YAMLError as e:
print(f"YAML解析错误: {e}")
# 输出: mapping values are not allowed here
9. 最佳实践
- 字符串引号:当字符串包含
:
、#
等特殊字符时使用引号 - 列表缩进:列表项使用相同缩进
- 复杂结构:避免超过 4 层嵌套
- 行内风格:简单结构可使用行内风格(如
ports: [80, 443]
) - 多文档分隔:使用
---
分隔多个配置段 - 数据类型明确:对可能混淆的类型(如
yes
)添加类型标签is_active: !!bool "yes" # 明确指定为布尔值
10. YAML 与其他格式对比
特性 | YAML | JSON | XML |
---|---|---|---|
可读性 | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
简洁性 | ★★★★★ | ★★★★☆ | ★☆☆☆☆ |
数据类型 | 丰富 | 基本 | 文本为主 |
注释支持 | ✓ | ✗ | ✓ |
锚点引用 | ✓ | ✗ | ✗ |
学习曲线 | 低 | 低 | 中 |
总结
YAML 是自动化运维中最重要的配置文件格式之一,主要特点包括:
- 极高的可读性和简洁性
- 灵活的数据结构表示
- 支持复杂嵌套和引用
- 与脚本语言(如 Python)自然兼容
- 广泛应用于 Ansible、Kubernetes、Docker 等工具
掌握 YAML 能帮助您高效处理各种配置管理任务,提升自动化运维效率。