Перейти к основному содержимому
Версия: 3.19.0

Приложение: Техники работы с YAML

Большая часть этого руководства была посвящена написанию языка шаблонов. В этом разделе мы рассмотрим формат YAML. YAML обладает рядом полезных возможностей, которые мы, как авторы шаблонов, можем использовать для уменьшения количества ошибок и улучшения читаемости наших шаблонов.

Скаляры и коллекции

Согласно спецификации YAML, существует два типа коллекций и множество скалярных типов.

Два типа коллекций — это словари (map) и последовательности (sequence):

map:
one: 1
two: 2
three: 3

sequence:
- one
- two
- three

Скалярные значения — это отдельные значения (в отличие от коллекций).

Скалярные типы в YAML

В диалекте YAML, используемом Helm, тип данных скалярного значения определяется сложным набором правил, включая схему Kubernetes для определений ресурсов. Однако при выводе типов обычно действуют следующие правила.

Если целое число или число с плавающей точкой записано без кавычек, оно обычно рассматривается как числовой тип:

count: 1
size: 2.34

Но если они заключены в кавычки, они рассматриваются как строки:

count: "1" # <-- строка, не int
size: '2.34' # <-- строка, не float

То же самое относится к булевым значениям:

isGood: true   # bool
answer: "true" # строка

Слово для пустого значения — null (не nil).

Обратите внимание, что port: "80" является допустимым YAML и пройдёт как через движок шаблонов, так и через парсер YAML, но вызовет ошибку, если Kubernetes ожидает, что port будет целым числом.

В некоторых случаях можно принудительно указать определённый тип с помощью тегов узлов YAML:

coffee: "yes, please"
age: !!str 21
port: !!int "80"

В примере выше !!str указывает парсеру, что age является строкой, даже если выглядит как целое число. А port рассматривается как целое число, несмотря на то что заключён в кавычки.

Строки в YAML

Большая часть данных, которые мы размещаем в документах YAML, — это строки. YAML предоставляет несколько способов представления строк. В этом разделе описываются эти способы и демонстрируется применение некоторых из них.

Существует три «встроенных» способа объявления строки:

way1: bare words
way2: "double-quoted strings"
way3: 'single-quoted strings'

Все встроенные стили должны располагаться на одной строке.

  • Слова без кавычек (bare words) не экранируются. По этой причине нужно внимательно следить за используемыми символами.
  • Строки в двойных кавычках могут содержать экранированные символы с помощью \. Например, "\"Hello\", she said". Переносы строк можно экранировать с помощью \n.
  • Строки в одинарных кавычках являются «литеральными» строками и не используют \ для экранирования символов. Единственная последовательность экранирования — '', которая декодируется как одинарная кавычка '.

Помимо однострочных строк, можно объявлять многострочные строки:

coffee: |
Latte
Cappuccino
Espresso

В примере выше значение coffee будет рассматриваться как единая строка, эквивалентная Latte\nCappuccino\nEspresso\n.

Обратите внимание, что первая строка после | должна иметь правильный отступ. Поэтому мы можем нарушить работу примера выше, сделав так:

coffee: |
Latte
Cappuccino
Espresso

Поскольку Latte имеет неправильный отступ, мы получим ошибку вроде этой:

Error parsing file: error converting YAML to JSON: yaml: line 7: did not find expected key

В шаблонах иногда безопаснее добавить фиктивную «первую строку» содержимого в многострочном документе для защиты от подобной ошибки:

coffee: |
# Commented first line
Latte
Cappuccino
Espresso

Обратите внимание, что какой бы ни была первая строка, она сохранится в выходных данных строки. Поэтому если вы используете эту технику для вставки содержимого файла в ConfigMap, комментарий должен быть того типа, который ожидается программой, читающей эту запись.

Управление пробелами в многострочных строках

В примере выше мы использовали | для обозначения многострочной строки. Обратите внимание, что содержимое строки заканчивается символом \n. Если нужно, чтобы процессор YAML убрал завершающий перенос строки, можно добавить - после |:

coffee: |-
Latte
Cappuccino
Espresso

Теперь значение coffee будет: Latte\nCappuccino\nEspresso (без завершающего \n).

В других случаях может потребоваться сохранить все завершающие пробельные символы. Это можно сделать с помощью нотации |+:

coffee: |+
Latte
Cappuccino
Espresso


another: value

Теперь значение coffee будет Latte\nCappuccino\nEspresso\n\n\n.

Отступы внутри текстового блока сохраняются, что также приводит к сохранению переносов строк:

coffee: |-
Latte
12 oz
16 oz
Cappuccino
Espresso

В этом случае coffee будет Latte\n 12 oz\n 16 oz\nCappuccino\nEspresso.

Отступы и шаблоны

При написании шаблонов вам может понадобиться вставить содержимое файла в шаблон. Как мы видели в предыдущих главах, есть два способа сделать это:

  • Используйте {{ .Files.Get "FILENAME" }} для получения содержимого файла из чарта.
  • Используйте {{ include "TEMPLATE" . }} для рендеринга шаблона и последующей вставки его содержимого в чарт.

При вставке файлов в YAML полезно знать правила работы с многострочными строками, описанные выше. Часто самый простой способ вставить статический файл — сделать что-то вроде этого:

myfile: |
{{ .Files.Get "myfile.txt" | indent 2 }}

Обратите внимание на отступ выше: indent 2 указывает движку шаблонов добавить отступ в два пробела к каждой строке «myfile.txt». Обратите внимание, что мы не делаем отступ для самой строки шаблона. Если бы мы это сделали, содержимое первой строки файла имело бы двойной отступ.

Свёрнутые многострочные строки

Иногда нужно представить строку в YAML на нескольких строках, но при интерпретации она должна рассматриваться как одна длинная строка. Это называется «свёртывание» (folding). Чтобы объявить свёрнутый блок, используйте > вместо |:

coffee: >
Latte
Cappuccino
Espresso


Значение coffee выше будет Latte Cappuccino Espresso\n. Обратите внимание, что все переносы строк, кроме последнего, будут преобразованы в пробелы. Вы можете комбинировать управление пробельными символами с маркером свёртывания, поэтому >- заменит или обрежет все переносы строк.

Обратите внимание, что в синтаксисе свёртывания текст с отступом сохраняет переносы строк.

coffee: >-
Latte
12 oz
16 oz
Cappuccino
Espresso

Результат будет Latte\n 12 oz\n 16 oz\nCappuccino Espresso. Обратите внимание, что пробелы и переносы строк сохранены.

Размещение нескольких документов в одном файле

В один файл можно поместить несколько документов YAML. Для этого новый документ начинается с ---, а заканчивается ...


---
document: 1
...
---
document: 2
...

Во многих случаях --- или ... можно опустить.

Некоторые файлы в Helm не могут содержать более одного документа. Например, если в файле values.yaml указано более одного документа, будет использован только первый.

Однако файлы шаблонов могут содержать несколько документов. В этом случае файл (и все его документы) обрабатывается как один объект во время рендеринга шаблона. Но затем результирующий YAML разделяется на несколько документов перед отправкой в Kubernetes.

Мы рекомендуем использовать несколько документов в одном файле только при крайней необходимости. Наличие нескольких документов в файле может усложнить отладку.

YAML — надмножество JSON

Поскольку YAML является надмножеством JSON, любой допустимый документ JSON должен быть допустимым YAML.

{
"coffee": "yes, please",
"coffees": [
"Latte", "Cappuccino", "Espresso"
]
}

Выше показан другой способ представления этого:

coffee: yes, please
coffees:
- Latte
- Cappuccino
- Espresso

И их можно смешивать (с осторожностью):

coffee: "yes, please"
coffees: [ "Latte", "Cappuccino", "Espresso"]

Все три варианта должны разбираться в одно и то же внутреннее представление.

Хотя это означает, что такие файлы, как values.yaml, могут содержать данные JSON, Helm не рассматривает расширение файла .json как допустимый суффикс.

Якоря YAML

Спецификация YAML предоставляет способ сохранить ссылку на значение и затем обращаться к этому значению по ссылке. YAML называет это «якорением» (anchoring):

coffee: "yes, please"
favorite: &favoriteCoffee "Cappuccino"
coffees:
- Latte
- *favoriteCoffee
- Espresso

В примере выше &favoriteCoffee устанавливает ссылку на Cappuccino. Позже эта ссылка используется как *favoriteCoffee. Таким образом, coffees становится Latte, Cappuccino, Espresso.

Хотя есть несколько случаев, когда якоря полезны, есть один аспект, который может вызвать незаметные ошибки: при первом чтении YAML ссылка раскрывается, а затем отбрасывается.

Поэтому если мы декодируем и затем снова закодируем пример выше, результирующий YAML будет таким:

coffee: yes, please
favorite: Cappuccino
coffees:
- Latte
- Cappuccino
- Espresso

Поскольку Helm и Kubernetes часто читают, модифицируют и затем перезаписывают файлы YAML, якоря будут утеряны.