Перейти к содержимому

YAML

YAML — человеко-читаемый язык для конфигураций (Docker Compose, Kubernetes, Ansible, GitHub Actions). Отступы (пробелы) вместо скобок, комментарии (#), многострочные строки (| — сохраняет переносы, > — сворачивает в пробелы), якоря и ссылки (&, *). Типы данных: строки (кавычки не обязательны, но нужны для чисел и true/false), числа, boolean, null, даты (ISO 8601). YAML vs JSON: YAML читаемее, есть комментарии и якоря, но сложнее (отступы критичны). JSON для API, YAML для конфигов. Проблемы: табуляции запрещены (только пробелы), автоматическое определение типов (version: 1.0 станет числом), безопасность (safe_load вместо load).

Введение: Человеко-читаемый язык для конфигураций

Представьте, что вы пишете инструкцию для сборки шкафа. Можно написать длинный текст. Можно нарисовать схему. А можно сделать список: “1. Взять деталь А. 2. Взять деталь Б. 3. Соединить А и Б винтом 1”. Список читается легко, его можно быстро менять, он не требует специальных программ.

В мире конфигурационных файлов таким “списком” стал YAML. Он создавался как более читаемая альтернатива XML и JSON для файлов, которые пишут и редактируют люди.

YAML (YAML Ain’t Markup Language) — это язык сериализации данных, ориентированный на читаемость человеком. В отличие от JSON, YAML не требует кавычек, скобок и запятых. Он использует отступы (пробелы) для обозначения структуры.

YAML стал стандартом для конфигурационных файлов в DevOps-мире: Docker Compose, Kubernetes, Ansible, GitHub Actions, GitLab CI, CircleCI, Swagger/OpenAPI. Почему? Потому что YAML легче читать и писать, чем JSON, и он поддерживает комментарии. Для конфигураций, которые меняются людьми, это критически важно.

Почему YAML, а не JSON

ХарактеристикаJSONYAML
ЧитаемостьХорошаяОтличная
КомментарииНетДа (# комментарий)
КавычкиОбязательны для ключей и строкТолько когда нужны
Скобки{}, []Отступы
ЗапятыеДаНет
Многострочные строки\n или конкатенацияДа (`
Ссылки (якоря)НетДа (&, *)
СложностьПростойСложнее (отступы, типы)
APIСтандартРедко

JSON: Машиночитаемый, строгий, простой в парсинге. Хорош для передачи данных по сети.

YAML: Человекочитаемый, гибкий, мощный. Хорош для конфигурационных файлов.

Основной синтаксис YAML

Комментарии

# Это комментарий
name: Иван  # комментарий после значения

Ключи и значения (пары “ключ-значение”)

# Строка (кавычки не обязательны)
name: Иван

# Число
age: 30

# Логическое
is_active: true

# null (пустое значение)
phone: null
phone: ~    # альтернативная запись

Объекты (словари, хеши, мапы)

# JSON стиль (но без кавычек и скобок)
user:
  name: Иван
  age: 30
  address:
    city: Москва
    street: Тверская

# Альтернативный синтаксис (блочный, для краткости)
user: {name: Иван, age: 30}

Массивы (списки, последовательности)

# Каждый элемент на новой строке с дефисом
phones:
  - +7-999-123-45-67
  - +7-495-123-45-67

# Альтернативный синтаксис (в одну строку)
phones: [+7-999-123-45-67, +7-495-123-45-67]

Вложенные структуры

users:
  - name: Иван
    age: 30
    phones:
      - +7-999-123-45-67
      - +7-495-123-45-67
  - name: Петр
    age: 25
    phones:
      - +7-999-765-43-21

Многострочные строки

YAML имеет мощные возможности для работы с многострочным текстом.

Блочные стили

СтильСимволПоведение
Literal block``
Folded block>Сворачивает переносы в пробелы

Пример literal block (|)

description: |
  Это первая строка.
  Это вторая строка.
  Это третья строка.

# Результат: "Это первая строка.\nЭто вторая строка.\nЭто третья строка.\n"

Пример folded block (>)

description: >
  Это длинное предложение,
  которое разбито на несколько строк,
  но в итоге будет одной строкой.

# Результат: "Это длинное предложение, которое разбито на несколько строк, но в итоге будет одной строкой.\n"

Управление переносом строк

# Сохранить переносы в конце
text: |-
  Строка без переноса в конце

# Добавить перенос в конце
text: |+
  Строка с переносом в конце

# Количество отступов для блока
code: |2
    def hello():
        print("Hello")

Типы данных в YAML

Строки

# Без кавычек
name: Иван

# В двойных кавычках (экранирование)
path: "C:\\Users\\ivan"

# В одинарных кавычках (без экранирования)
regex: '\d+'

# Пустая строка
empty: ''

Числа

integer: 42
float: 3.14
negative: -10
exponential: 1.5e3
hex: 0x2A
octal: 0o52
binary: 0b101010
infinity: .inf
not_a_number: .nan

Логические

true_value: true
false_value: false

# Альтернативные записи (лучше не использовать)
yes_value: yes
no_value: no
on_value: on
off_value: off

Даты и время

date: 2024-01-15
datetime: 2024-01-15T10:30:00Z
datetime_with_offset: 2024-01-15T10:30:00+03:00

null

empty: null
empty2: ~
empty3:   # просто ничего после двоеточия

Продвинутые возможности

Якоря (Anchors) и ссылки (Aliases)

Позволяют повторно использовать данные.

# Определение якоря &defaults
defaults: &defaults
  timeout: 30
  retries: 3
  backoff: 2

# Использование ссылки *defaults
production:
  <<: *defaults
  url: https://prod.example.com

development:
  <<: *defaults
  url: http://localhost:8080
  timeout: 60  # переопределение

Результат (как будет выглядеть после парсинга):

production:
  timeout: 30
  retries: 3
  backoff: 2
  url: https://prod.example.com

development:
  timeout: 60
  retries: 3
  backoff: 2
  url: http://localhost:8080

Якоря для массивов и объектов

users:
  - &admin
    name: Admin
    role: admin
  - &user
    name: User
    role: user

# Ссылки
admins:
  - *admin
  - name: BackupAdmin
    role: admin

users_copy: [*admin, *user]

Теги (явное указание типа)

# Явное указание типа
not_string: !!str 42
not_float: !!int 3.14
binary_data: !!binary SGVsbG8gV29ybGQ=
timestamp: !!timestamp 2024-01-15T10:30:00Z

Наборы (Sets)

# Уникальные значения (редко используется)
colors: !!set
  ? red
  ? green
  ? blue

Порядок ключей (не гарантирован)

YAML сохраняет порядок ключей (в отличие от JSON), но не стоит на это полагаться в критичных случаях.

YAML в реальных проектах

Docker Compose

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
    restart: always
  
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: DATABASE_URL
              value: postgres://db:5432/myapp
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"

GitHub Actions

name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - run: pip install -r requirements.txt
      - run: pytest tests/

Ansible

- name: Установка и настройка веб-сервера
  hosts: webservers
  become: yes
  tasks:
    - name: Установка nginx
      apt:
        name: nginx
        state: present
    
    - name: Копирование конфигурации
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: reload nginx
  
  handlers:
    - name: reload nginx
      service:
        name: nginx
        state: reloaded

OpenAPI / Swagger

openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths:
  /users/{id}:
    get:
      summary: Получить пользователя
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Успех
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string

YAML vs JSON vs XML

ХарактеристикаJSONXMLYAML
Читаемость человекомХорошаяСредняяОтличная
КомментарииНетДаДа
Размер (типичный)СреднийБольшойМаленький (без скобок)
Сложность синтаксисаНизкаяСредняяСредняя (отступы)
Ссылки/якоряНетНетДа
Многострочные строкиПлохоПлохоОтлично
Типы данныхБазовыеВсе строки (через схему)Расширенные (даты, бинарные)
Поддержка в языкахВсеВсеХорошая (но не все)
ПарсингПростойСложныйСредний
Где используетсяAPIДокументы, SOAPКонфиги, DevOps

Проблемы и ограничения YAML

Проблема 1: Отступы (критичны)

# Правильно (2 пробела)
user:
  name: Иван
  age: 30

# Ошибка (смесь пробелов и табуляций)
user:
    name: Иван   # табуляция
  age: 30        # пробелы

Правило: Только пробелы, никаких табуляций. Количество пробелов должно быть одинаковым в одном уровне.

Проблема 2: Автоматическое определение типов

# Неожиданное число
version: 1.0   # станет числом 1.0, не строкой

# Неожиданный null
null_value: null   # null
empty:             # null (пустое значение)

# Неожиданное логическое
on: on            # true
off: off          # false
yes: yes          # true
no: no            # false

Решение: Использовать кавычки для строк.

version: "1.0"
on: "on"
empty: ""

Проблема 3: Длинные файлы

Большие YAML файлы (1000+ строк) сложно редактировать из-за отступов.

Решение: Разбивать на несколько файлов или использовать JSON для больших объёмов.

Проблема 4: Безопасность

YAML может выполнять произвольный код в некоторых парсерах (например, Ruby YAML). Атака через “YAML deserialization”.

Решение: Использовать безопасные парсеры (safe_load вместо load).

# Опасно
import yaml
data = yaml.load(user_input)   # может выполнить код

# Безопасно
data = yaml.safe_load(user_input)

Проблема 5: Поддержка в языках

Не все языки имеют полноценную поддержку YAML. Например, в Go стандартная библиотека не включает YAML.

YAML vs JSON в конфигах

АспектJSONYAML
ЧитаемостьХорошая (со скобками)Отличная (без скобок)
КомментарииНетДа
Редактирование вручнуюНормально (но без комментариев)Легко
Diff в GitНормальноОтлично (меньше изменений)
Поддержка в IDEОтличная (автодополнение)Хорошая (но сложнее с отступами)

Пример: один и тот же конфиг в JSON и YAML

JSON:

{
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "myapp",
        "user": "admin",
        "password": "secret"
    },
    "redis": {
        "host": "localhost",
        "port": 6379
    },
    "features": ["analytics", "logging", "notifications"]
}

YAML:

# Конфигурация приложения
database:
  host: localhost
  port: 5432
  name: myapp
  user: admin
  password: secret

redis:
  host: localhost
  port: 6379

features:
  - analytics
  - logging
  - notifications

Вывод: Для конфигов YAML удобнее (комментарии, читаемость). Для API JSON (стандарт, простота парсинга).

Инструменты для работы с YAML

ИнструментНазначение
yaml-online-parser.appspot.comВалидация
json2yaml.comКонвертер JSON → YAML
yamltojson.comКонвертер YAML → JSON

IDE поддержка

IDEПоддержка
VS CodeПлагины: YAML, Red Hat YAML, YAML Schemas
IntelliJ IDEAВстроенная поддержка
PyCharmВстроенная поддержка
VimПлагин: vim-yaml

Распространённые ошибки

Ошибка 1: Табуляции вместо пробелов

# Плохо (табуляция)
user:
	name: Иван

# Хорошо (2 пробела)
user:
  name: Иван

Ошибка 2: Неправильные отступы

# Плохо (разное количество пробелов)
user:
  name: Иван
    age: 30

# Хорошо
user:
  name: Иван
  age: 30

Ошибка 3: Строка, похожая на число или логическое

# Плохо (станет числом 1.0)
version: 1.0

# Плохо (станет true)
feature_enabled: on

# Хорошо (строка)
version: "1.0"
feature_enabled: "on"

Ошибка 4: Пустое значение вместо null

# Плохо (null, но может быть неожиданностью)
phone:

# Лучше (явно)
phone: null
phone: ~

Ошибка 5: Двоеточие без пробела

# Плохо (синтаксическая ошибка)
name:Иван

# Хорошо
name: Иван

Ошибка 6: Дефис без пробела в массиве

# Плохо
phones:
  -+7-999-123-45-67

# Хорошо
phones:
  - +7-999-123-45-67

Резюме для системного аналитика

  1. YAML (YAML Ain’t Markup Language) — язык сериализации данных, ориентированный на читаемость человеком. Стандарт для конфигурационных файлов в DevOps.

  2. Ключевые особенности: отступы вместо скобок, комментарии (#), многострочные строки (|, >), якоря и ссылки (&, *), богатые типы данных.

  3. Где используется: Docker Compose, Kubernetes, Ansible, GitHub Actions, GitLab CI, CircleCI, Swagger/OpenAPI, Helm, Terraform.

  4. YAML vs JSON: YAML читаемее, поддерживает комментарии, многострочные строки, якоря. JSON проще, строже, быстрее парсится. YAML для конфигов, JSON для API.

  5. Проблемы: отступы критичны (только пробелы, не табуляции), автоматическое определение типов (нужны кавычки для строк, похожих на числа), безопасность (использовать safe_load).

Проверка знаний

Вопрос 1 из 4
Почему YAML так популярен для конфигурационных файлов?
За счёт чего YAML в первую очередь выражает структуру данных?
Какой символ в YAML сохраняет переносы строк 'как есть' в многострочном тексте?
Почему в теме рекомендуется использовать `safe_load`, а не `load`?

Вопросы, где были ошибки