AWS CloudFormation позволяет описывать инфраструктуру как код, используя шаблоны в формате JSON или YAML. Однако настоящая сила этого инструмента раскрывается, когда мы начинаем работать с его «руническими» символами – специальными функциями и псевдо‑параметрами, которые превращают статический описание в динамичный, адаптируемый код. В этой статье мы подробно рассмотрим, какие символы доступны, как они работают и как их правильно применять в реальных проектах.
Что такое «рунические коды» в CloudFormation?
Под «руническими кодами» мы понимаем набор встроенных функций и псевдо‑параметров, обозначаемых специальными символами (например, !, ${}, ::) и позволяющих:
- Ссылаться на ресурсы и их атрибуты;
- Выполнять строковые операции;
- Условно включать или исключать части шаблона;
- Преобразовывать типы данных;
- Встраивать внешние фрагменты (macros, includes).
Эти символы делают шаблон не просто статическим описанием, а живым скриптом, способным реагировать на параметры стека, регион, учетную запись и многие другие контекстные данные.
Основные рунические символы и их функции
Псевдо‑параметры
Псевдо‑параметры доступны в каждом шаблоне и начинаются с префикса AWS::. Они предоставляют информацию о среде выполнения:
AWS::StackName– имя текущего стека;AWS::Region– регион, в котором происходит развертывание;AWS::AccountId– идентификатор учетной записи AWS;AWS::NotificationARNs– список ARN тем SNS для уведомлений;AWS::NoValue– специальное значение, используемое для удаления свойства.
Встроенные функции (intrinsic functions)
Все функции обозначаються восклицательным знаком ! и могут использоваться как в JSON, так и в YAML. Наиболее часто применяемые:
| Функция | Синтаксис | Описание |
|---|---|---|
Ref | !Ref LogicalName | Возвращает значение указанного параметра, ресурса или псевдо‑параметра. |
GetAtt | !GetAtt ResourceName.Attribute | Получает атрибут ресурса (например, PublicIp у EC2). |
Join | !Join [ delimiter, [ list-of-values ] ] | Объединяет список строк в одну строку с заданным разделителем. |
Split | !Split [ delimiter, source-string ] | Разбивает строку на список по указанному разделителю. |
Sub | !Sub string или !Sub [ string, { var1: value1, var2: value2, ... } ] | Подставляет переменные в строку, аналогично Bash‑подстановке. |
Select | !Select index, list-of-values | Возвращает элемент списка по указанному индексу (начинается с 0). |
FindInMap | !FindInMap MapName, TopLevelKey, SecondLevelKey | Извлекает значение из секции Mappings. |
Condition | !Condition ConditionName | Возвращает true или false в зависимости от условия. |
And, Or, Not, Equals | !And [ condition1, condition2, … ] и т.д. | Логические операции для построения сложных условий. |
Макросы и включаемые фрагменты
Для повторного использования кусков кода CloudFormation предоставляет механизмы:
AWS::Include– подключает внешний шаблон (хранится в S3) в текущий файл;AWS::CloudFormation::Interface– позволяет задать порядок и группировку параметров в консоли;- Пользовательские макросы (через AWS Lambda) – позволяют выполнять произвольную трансформацию шаблона перед его обработкой.
Практические примеры применения рунических кодов
Пример 1: Динамическое формирование имени ресурса
Часто требуется, чтобы имя ресурса включало регион и идентификатор стека, чтобы избежать конфликтов при повторных развертываниях.
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${AWS::StackName}-${AWS::Region}-logs"
Здесь функция !Sub подставляет значения псевдо‑параметров AWS::StackName и AWS::Region в строку, получая уникальное имя бакета.
Пример 2: Условное создание ресурса в зависимости от параметра
Предположим, нам нужно создать резервную копию базы данных только если параметр CreateBackup установлен в true.
Parameters:
CreateBackup:
Type: String
AllowedValues: [true, false]
Default: false
Conditions:
CreateBackupCondition: !Equals [!Ref CreateBackup, true]
Resources:
PrimaryDB:
Type: AWS::RDS::DBInstance
Properties:
Engine: mysql
MasterUsername: admin
MasterUserPassword: {{resolve:secretsmanager:db/secret:SecretString:password}}
AllocatedStorage: 20
BackupSnapshot:
Type: AWS::RDS::DBSnapshot
Condition: CreateBackupCondition
Properties:
DBInstanceIdentifier: !Ref PrimaryDB
DBSnapshotIdentifier: !Sub "${AWS::StackName}-backup"
В этом примере условие CreateBackupCondition построено с помощью функции !Equals. Ресурс BackupSnapshot создаётся только если условие истинно.
Пример 3: Использование mappings для выбора AMI в зависимости от региона
Mappings:
RegionMap:
us-east-1:
AMI: ami-0abcdef1234567890
us-west-2:
AMI: ami-1bcdef2345678901
eu-central-1:
AMI: ami-2cdef3456789012
Resources:
MyEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionMap, !Ref AWS::Region, AMI]
InstanceType: t3.micro
Функция !FindInMap позволяет избежать жёсткой привязки к конкретному AMI и делает шаблон portable между регионами.
Пример 4: Подключение внешнего фрагмента через AWS::Include
Допустим, у нас есть общий набор правил безопасности, хранящийся в S3.
Resources:
SharedSG:
Type: AWS::Include
Properties:
Location: s3://my-templates/shared-security-group.yaml
Файл shared-security-group.yaml может содержать полное описание ресурса AWS::EC2::SecurityGroup, которое будет встроено в основной шаблон.
Пример 5: Формирование сложных строк с помощью Join и Split
Нужно собрать ARN для топика SNS, используя идентификатор стека и произвольный суффикс.
Resources:
AlertTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Join ["-", [!Ref AWS::StackName, "alerts"]]
DisplayName: !Sub "Оповещения для стека ${AWS::StackName}"
Здесь !Join объединяет два элемента (StackName и фиксированную строку "alerts") через дефис, а !Sub формирует читаемое отображаемое имя.
Лучшие практики работы с руническими кодами
- Читаемость прежде всего. Несмотря на мощь функций, старайтесь не перегружать одну строку множеством вложенных выражений. Если логика становится сложной – вынесите её в отдельный параметр или условие;
- Используйте описательные имена для параметров и условий. Это облегчает отладку и делает шаблон самодокументирующимся.
- Логируйте промежуточные значения. Хотя CloudFormation не предоставляет прямого логгирования, можно выводить важные значения через параметры вывода (
Outputs) и проверять их в консоли после создания стека. - Тестируйте изменения в отдельном стеке. Перед применением правок к продакшене создавайте тестовый стек с теми же параметрами, чтобы убедиться, что все функции работают как ожидается.
- Избегайте жёсткой привязки к конкретным учётным записям или регионам. Предпочитайте псевдо‑параметры (
AWS::Region,AWS::AccountId) и mappings вместо хардкода. - Документируйте использование макросов. Если вы применяете пользовательские макросы (Lambda‑based), храните их код в отдельном репозитории и добавляйте комментарии в шаблоне о том, какие трансформации они выполняют.
Рунические коды AWS CloudFormation – это набор символов и функций, которые превращают обычный декларативный шаблон в гибкий, контекстно‑зависимый скрипт. Освоив псевдо‑параметры, внутренние функции, условия и механизмы включения, вы сможете:
- Создавать truly multi‑region и multi‑account решения;
- Избавляться от жёсткой привязки к конкретным значениям;
- Автоматически генерировать имена, ARN и другие идентификаторы;
- Условно включать или исключать ресурсы в зависимости от входных параметров;
- Повторно использовать куски кода через includes и макросы.
Как и любые мощные инструменты, рунические коды требуют аккуратного применения: чёткая структура, понятные имена и умеренная сложность выражений делают ваш инфраструктурный код не только работоспособным, но и поддерживаемым командой DevOps на протяжении многих лет.
Пусть ваши шаблоны будут полны магии символов, а инфраструктура – надёжной и предсказуемой!