cloudformation

Ansible Роль: Создание стеков CloudFormation

Мотивация | Установка | Особенности | Переменные | Использование | Шаблоны | Различия | Зависимости | Требования | Лицензия

Статус сборки Ansible Galaxy Выпуск

Ansible роль для преобразования произвольного количества шаблонов Jinja2 в файлы CloudFormation и развертывания любого количества стеков.

Мотивация

Эта роль преодолевает недостатки самих шаблонов CloudFormation и активно использует функции Ansible.

  1. Ограничения CloudFormation - Синтаксис CloudFormation довольно ограничен, когда дело доходит до программной логики, такой как условия, циклы и сложные переменные, такие как массивы или словари. Обернув свой шаблон CloudFormation в Ansible, вы сможете использовать директивы Jinja2 внутри самого шаблона CloudFormation, таким образом, имея все преимущества Ansible и все еще развертывая через стеки CloudFormation.
  2. Независимость от окружения - Благодаря возможности преобразовывать шаблоны CloudFormation с помощью пользовательских переменных цикла, вы сможете создавать полностью независимые от окружения шаблоны и повторно использовать их для производства, тестирования, развертывания и других окружений.
  3. Проверка без развертывания - Еще одно преимущество использования Ansible для развертывания ваших шаблонов CloudFormation заключается в том, что Ansible поддерживает режим проверки (--check) для развертываний CloudFormation (с версии Ansible 2.4). В этом режиме он создаст Change-set и сообщит вам, что изменится, если вы действительно его развернете. Таким образом, вы можете безопасно тестировать свои стеки перед их фактическим применением.

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

Когда шаблоны преобразованы, в каталоге роли создается временный каталог build/. Это может либо сохраняться, либо создаваться заново каждый раз, когда выполняется эта роль. Укажите поведение с помощью cloudformation_clean_build_env.

Установка

Используйте Ansible Galaxy для установки роли:

$ ansible-galaxy install cytopia.cloudformation

Или клонируйте репозиторий в каталог ваших ролей

$ git clone https://github.com/cytopia/ansible-role-cloudformation /path/to/ansible/roles

Особенности

  • Развертывание произвольного количества шаблонов CloudFormation
  • Создание шаблонов CloudFormation с использованием шаблонизатора Jinja2
  • Только преобразование шаблонов и использование вашей текущей инфраструктуры для развертывания
  • Режим проверки с помощью Ansible --check, который создаст временные Change-set (например: сообщит вам, если ресурс требует пересоздания)
  • Просмотр различий построчно между локальными и развернутыми шаблонами с помощью модуля cloudformation_diff
  • Использование Ansible vault для хранения конфиденциальной информации в зашифрованном виде

Переменные

Обзор

Следующие переменные доступны в defaults/main.yml и могут быть использованы для настройки вашей инфраструктуры.

Переменная Тип По умолчанию Описание
cloudformation_clean_build_env bool False Очистить каталог build/ с шаблонами CloudFormation, сгенерированными Jinja2, при каждом запуске.
cloudformation_generate_only bool False Вместо развертывания ваших шаблонов CloudFormation вы также можете только преобразовать их и сделать доступными в каталоге build/, чтобы можно было использовать вашу текущую инфраструктуру для их развертывания.
Совет: Укажите эту переменную через аргументы командной строки ansible.
cloudformation_run_diff bool False Эта роль поставляется с настраиваемым модулем Ansible CloudFormation cloudformation_diff. Этот модуль генерирует текстовый вывод различий между вашим локальным шаблоном cloudformation, готовым к развертыванию, и текущим развернутым шаблоном на AWS CloudFormation.
Зачем это нужно?
Текущий модуль cloudformation просто перечисляет наборы изменений в режиме --check, что позволит вам узнать, что изменится (например, группы безопасности), но не конкретно, что именно изменится (какие группы безопасности и их значения). Чтобы также видеть точные изменения, которые произойдут, включите модуль cloudformation_diff здесь.
cloudformation_diff_output string json Когда cloudformation_run_diff включен, какой вывод различий следует указать? Если вы пишете свои шаблоны cloudformation в формате json, используйте json, или если вы пишете свои шаблоны в формате yaml, используйте yaml.
cloudformation_required list [] Массив доступных ключей стеков cloudformation, которые вы хотите сделать обязательными вместо необязательных. Каждый элемент стека cloudformation будет проверен на соответствие заданным обязательным ключам. Если элемент стека не содержит ни одного из этих ключей, будет выдана ошибка до начала развертывания.
cloudformation_defaults dict {} Словарь значений по умолчанию, которые применяются ко всем стеком cloudformation. Обратите внимание, что эти значения могут быть переопределены в определении каждого стека.
cloudformation_stacks list [] Массив стеков cloudformation для развертывания.

Подробности

Этот раздел содержит более подробное описание доступных ключей словарей или массивов.

cloudformation_defaults

Ключ Тип Обязательный Описание
aws_access_key string необязательный AWS access key для использования
aws_secret_key string необязательный AWS secret key для использования
security_token string необязательный AWS security token для использования
profile string необязательный AWS boto profile для использования
notification_arns string необязательный Публикация уведомлений стеков по этим ARN
termination_protection bool необязательный Включить или отключить защиту от завершения стека. Работает только с botocore >= 1.7.18
region string необязательный Регион AWS для развертывания стека

cloudformation_stacks

Ключ Тип Обязательный Описание
stack_name string обязательный Имя стека cloudformation
template string обязательный Путь к шаблону cloudformation, который нужно обработать и развернуть (не нужно обрабатывать)
aws_access_key string необязательный AWS access key для использования (перезаписывается по умолчанию)
aws_secret_key string необязательный AWS access key для использования (перезаписывается по умолчанию)
security_token string необязательный AWS security token для использования (перезаписывается по умолчанию)
profile string необязательный AWS boto profile для использования (перезаписывается по умолчанию)
notification_arns string необязательный Публикация уведомлений стеков по этим ARN (перезаписывается по умолчанию)
termination_protection bool необязательный Включить или отключить защиту от завершения стека. Работает только с botocore >= 1.7.18
region string необязательный Регион AWS для развертывания стека (перезаписывается по умолчанию)
template_parameters dict необязательный Обязательные параметры стека cloudformation
tags dict необязательный Теги, связанные со стеком cloudformation

Примеры

Определите значения по умолчанию, которые будут применяться ко всем стекам (если не переопределены в определении каждого стека)

# Принудите установить 'profile' для каждого элемента стека cloudformation
cloudformation_required:
  - profile

cloudformation_defaults:
  region: eu-central-1

Определите стеки cloudformation, которые будут обработаны и развернуты

cloudformation_stacks:
  - stack_name: stack-s3
    template: files/cloudformation/s3.yml.j2
    profile: production
    template_parameters:
      bucketName: my-bucket
    tags:
      env: production
  - stack_name: stack-lambda
    template: files/cloudformation/lambda.yml.j2
    profile: production
    termination_protection: True
    template_parameters:
      lambdaFunctionName: lambda
      handler: lambda.run_handler
      runtime: python2.7
      s3Bucket: my-bucket
      s3Key: lambda.py.zip
    tags:
      env: production

Только преобразуйте ваши шаблоны Jinja2, но не развертывайте их в AWS. Преобразованные файлы cloudformation будут находиться в каталоге build/ этой роли.

$ ansible-playbook play.yml -e cloudformation_generate_only=True

Использование

Простое

Простой пример использования:

playbook.yml

- hosts: localhost
  connection: local
  roles:
    - cloudformation

group_vars/all.yml

# Определите стеки Cloudformation
cloudformation_stacks:
  # Первый стек
  - stack_name: stack-s3
    profile: testing
    region: eu-central-1
    template: files/cloudformation/s3.yml.j2
    template_parameters:
      bucketName: my-bucket
    tags:
      env: testing
  # Второй стек
  - stack_name: stack-lambda
    profile: testing
    termination_protection: True
    region: eu-central-1
    template: files/cloudformation/lambda.yml.j2
    template_parameters:
      lambdaFunctionName: lambda
      handler: lambda.run_handler
      runtime: python2.7
      s3Bucket: my-bucket
      s3Key: lambda.py.zip
    tags:
      env: testing

Продвинутое

Пример продвинутого использования, вызывающего роль независимо в разных виртуальных хостах.

inventory

[my-group]
infrastructure  ansible_connection=local
application     ansible_connection=local

playbook.yml

# Часть инфраструктуры
- hosts: infrastructure
  roles:
    - cloudformation
  tags:
    - infrastructure

# Часть приложения
- hosts: application
  roles:
    - some-role
  tags:
    - some-role
    - application

- hosts: application
  roles:
    - cloudformation
  tags:
    - application

group_vars/my-group.yml

stack_prefix: testing
boto_profile: testing
s3_bucket: awesome-lambda

cloudformation_defaults:
  profile: "{{ boto_profile }}"
  region: eu-central-1

host_vars/infrastructure.yml

cloudformation_stacks:
  - stack_name: "{{ stack_prefix }}-s3"
    template: files/cloudformation/s3.yml.j2
    template_parameters:
      bucketName: "{{ s3_bucket }}"
    tags:
      env: "{{ stack_prefix }}"

host_vars/application.yml

cloudformation_stacks:
  - stack_name: "{{ stack_prefix }}-lambda"
    template: files/cloudformation/lambda.yml.j2
    template_parameters:
      lambdaFunctionName: lambda
      handler: lambda.run_handler
      runtime: python2.7
      s3Bucket: "{{ s3_bucket }}"
      s3Key: lambda.py.zip
    tags:
      env: "{{ stack_prefix }}"

Шаблоны

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

Пример: Определения подсетей

Следующий шаблон можно развернуть в разных тестовых окружениях и он способен включать различное количество подсетей.

Переменные Ansible

---
# файл: staging.yml
vpc_subnets:
  - directive: subnetA
    az: a
    cidr: 10.0.10.0/24
    tags:
      - name: Name
        value: staging-subnet-a
      - name: env
        value: staging
  - directive: subnetB
    az: b
    cidr: 10.0.20.0/24
    tags:
      - name: Name
        value: staging-subnet-b
      - name: env
        value: staging
---
# файл: production.yml
vpc_subnets:
  - directive: subnetA
    az: a
    cidr: 10.0.10.0/24
    tags:
      - name: Name
        value: prod-subnet-a
      - name: env
        value: production
  - directive: subnetB
    az: b
    cidr: 10.0.20.0/24
    tags:
      - name: Name
        value: prod-subnet-b
      - name: env
        value: production
  - directive: subnetC
    az: b
    cidr: 10.0.30.0/24
    tags:
      - name: Name
        value: prod-subnet-c
      - name: env
        value: production

Шаблон CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: Шаблон VPC
Resources:
  vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: {{ vpc_cidr_block }}
      EnableDnsSupport: true
      EnableDnsHostnames: true
{% if vpc_tags %}
      Tags:
{% for tag in vpc_tags %}
        - Key: {{ tag.name }}
          Value: {{ tag.value }}
{% endfor %}
{% endif %}
{% for subnet in vpc_subnets %}
  {{ subnet.directive }}:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: {{ subnet.az }}
      CidrBlock: {{ subnet.cidr }}
      VpcId: !Ref vpc
{% if subnet.tags %}
      Tags:
{% for tag in subnet.tags %}
        - Key: {{ tag.name }}
          Value: {{ tag.value }}
{% endfor %}
{% endif %}

Пример: Группы безопасности

Определение групп безопасности с правилами, специфичными для IP, может быть очень сложным, если вы хотите сохранить независимость от окружения и все еще использовать один и тот же шаблон CloudFormation для всех окружений. Тем не менее, это можно легко преодолеть, предоставив специфичные для окружения определения массивов через Jinja2.

Переменные Ansible

---
# файл: staging.yml
# В staging все открыто, чтобы разработчики могли
# подключаться с прикрепленных VPN
security_groups:
  - protocol:  tcp
    from_port: 3306
    to_port:   3306
    cidr_ip:   10.0.0.1/32
  - protocol:  tcp
    from_port: 3306
    to_port:   3306
    cidr_ip:   192.168.0.15/32
  - protocol:  tcp
    from_port: 3306
    to_port:   3306
    cidr_ip:   172.16.0.0/16
---
# файл: production.yml
# В производственной среде значительно меньше правил и другие
# диапазоны ip.
security_groups:
  - protocol:  tcp
    from_port: 3306
    to_port:   3306
    cidr_ip:   10.0.15.1/32

Шаблон CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: Шаблон VPC
Resources:
  rdsSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Группа безопасности RDS
{% if security_groups %}
      SecurityGroupIngress:
{% for rule in security_groups %}
        - IpProtocol: "{{ rule.protocol }}"
          FromPort: "{{ rule.from_port }}"
          ToPort: "{{ rule.to_port }}"
          CidrIp: "{{ rule.cidr_ip }}"
{% endfor %}
{% endif %}

Различия

Когда вы включите cloudformation_run_diff, вы сможете видеть построчные различия между вашим локальным (обработанным jinja2) шаблоном и тем, который в настоящее время развернут на AWS. Чтобы вам было представление о том, как это выглядит, смотрите следующий пример вывода:

Не забудьте запустить Ansible с --diff, чтобы это работало:

$ ansible-playbook play.yml --diff

Json различия

Чтобы вывести в режиме json diff, установите cloudformation_diff_output в json.

TASK [cloudformation : diff cloudformation template file] *********************************************
--- before
+++ after
@@ -38,7 +38,6 @@
             "Type": "AWS::S3::BucketPolicy"
         },
         "s3Bucket": {
-            "DeletionPolicy": "Retain",
             "Properties": {
                 "BucketName": {
                     "Ref": "bucketName"

Yaml различия

Чтобы выводить в режиме yaml diff, установите cloudformation_diff_output в yaml.

TASK [cloudformation : diff cloudformation template file] *********************************************
--- before
+++ after
@@ -14,7 +14,6 @@
               Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
       Bucket: !Ref 's3Bucket'
   s3Bucket:
-    DeletionPolicy: Retain
     Type: AWS::S3::Bucket
     Properties:
       BucketName: !Ref 'bucketName'

Зависимости

Эта роль не зависит от других ролей.

Требования

Используйте как минимум Ansible 2.5, чтобы иметь возможность использовать режим --check для cloudformation.

Модуль python cfn_flip требуется при использовании постричного сравнения локальных и удаленных шаблонов CloudFormation (cloudformation_run_diff=True). Его можно легко установить локально:

$ pip install cfn_flip

Лицензия

MIT License

Copyright (c) 2017 cytopia

О проекте

Ansible role to render an arbitrary number of Jinja2 templates into cloudformation files and create any number of stacks.

Установить
ansible-galaxy install cytopia/ansible-role-cloudformation
Лицензия
mit
Загрузки
5190
Владелец
DevOps Engineer