cytopia.cloudformation

Ansibleロール: CloudFormationスタックの作成

動機 | インストール | 機能 | 変数 | 使用法 | テンプレート | 差分 | 依存関係 | 要件 | ライセンス

ビルドステータス Ansible Galaxy リリース

Ansibleロールは、任意の数のJinja2テンプレートをCloudFormationファイルにレンダリングし、任意の数のスタックをデプロイします。

動機

このロールは、CloudFormationテンプレートの欠点を克服し、Ansibleの機能を活用します。

  1. CloudFormationの制限 - CloudFormationの構文は、条件、ループ、配列や辞書のような複雑な変数のプログラミングロジックに関して非常に制限されています。CloudFormationテンプレートをAnsibleでラップすることで、テンプレート内でJinja2のディレクティブを使用できるため、Ansibleの美しさを享受しつつCloudFormationスタックをデプロイできます。
  2. 環境非依存 - カスタムループ変数を使用してCloudFormationテンプレートをレンダリングできるため、完全に環境非依存のテンプレートを作成し、プロダクション、テスト、ステージングなどの環境で再利用できます。
  3. 事前実行 - CloudFormationテンプレートをデプロイする際にAnsibleを使用するもう一つの利点は、AnsibleがCloudFormationデプロイ用の事前実行モード(--check)をサポートしていることです。このモードでは変更セットが作成され、実際にデプロイした場合に何が変更されるかを確認できます。これにより、スタックを適用する前に安全にテストできます。

このロールは、cloudformation_generate_onlyを使用してテンプレートを生成するだけでなく、レンダリングしたテンプレートをデプロイすることもできます。すでにデプロイインフラストラクチャが整っている場合でも、このロールを使ってテンプレートをレンダリングし、後で既存のインフラストラクチャに渡すことができます。

テンプレートがレンダリングされると、一時的なbuild/ディレクトリがロールディレクトリ内に作成されます。このディレクトリは、ロールが実行されるたびに維持または再作成できます。動作をcloudformation_clean_build_envで指定します。

インストール

Ansible Galaxyを使用してロールをインストールするか:

$ ansible-galaxy install cytopia.cloudformation

または、ロールディレクトリにgit cloneします:

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

機能

  • 任意の数のCloudFormationテンプレートをデプロイ
  • Jinja2テンプレーティングエンジンを使用してCloudFormationテンプレートを作成
  • テンプレートをレンダリングするだけで、現在のインフラストラクチャを使用してデプロイ
  • Ansibleの--checkモードによる事前実行をサポート(例:リソースの再作成が必要かを確認)
  • cloudformation_diffモジュールを使用したローカルとデプロイされたテンプレートの行単位の差分出力
  • Ansible Vaultを使用して機密情報を暗号化して保存

変数

概要

以下の変数はdefaults/main.ymlにあり、インフラストラクチャを設定するために使用できます。

変数 タイプ デフォルト 説明
cloudformation_clean_build_env bool False 各実行時にJinja2でレンダリングされたCloudFormationテンプレートのbuild/ディレクトリをクリーンアップします。
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 文字列 json cloudformation_run_diffが有効な場合、どの形式で差分出力を指定しますか?CloudFormationテンプレートをjsonで作成する場合はjsonを、yamlで作成する場合はyamlを指定します。
cloudformation_required リスト [] オプションではなく必須にするCloudFormationスタックキーの配列。各CloudFormationスタックアイテムは、カスタムで設定された必須キーに対してチェックされます。
cloudformation_defaults 辞書 {} すべてのCloudFormationスタックに適用するデフォルト値の辞書。これらの値は、スタック定義ごとに上書きできます。
cloudformation_stacks リスト [] デプロイするCloudFormationスタックの配列。

詳細

このセクションでは、使用可能な辞書または配列のキーについての詳細な説明を提供します。

cloudformation_defaults

キー タイプ 必須 説明
aws_access_key 文字列 任意 使用するAWSアクセスキー
aws_secret_key 文字列 任意 使用するAWSシークレットキー
security_token 文字列 任意 使用するAWSセキュリティトークン
profile 文字列 任意 使用するAWS botoプロファイル
notification_arns 文字列 任意 これらのARNにスタック通知を発行
termination_protection bool 任意 スタックの終了保護を有効または無効にします。botocore >= 1.7.18でのみ機能します。
region 文字列 任意 スタックをデプロイするAWSリージョン

cloudformation_stacks

キー タイプ 必須 説明
stack_name 文字列 必須 CloudFormationスタックの名前
template 文字列 必須 レンダリングおよびデプロイするCloudFormationテンプレートのパス(レンダリングする必要はありません)
aws_access_key 文字列 任意 使用するAWSアクセスキー(デフォルトを上書き)
aws_secret_key 文字列 任意 使用するAWSシークレットキー(デフォルトを上書き)
security_token 文字列 任意 使用するAWSセキュリティトークン(デフォルトを上書き)
profile 文字列 任意 使用するAWS botoプロファイル(デフォルトを上書き)
notification_arns 文字列 任意 これらのARNにスタック通知を発行(デフォルトを上書き)
termination_protection bool 任意 スタックの終了保護を有効または無効にします。botocore >= 1.7.18でのみ機能します。
region 文字列 任意 スタックをデプロイするAWSリージョン(デフォルトを上書き)
template_parameters 辞書 任意 必須のCloudFormationスタックパラメータ
tags 辞書 任意 CloudFormationスタックに関連付けられたタグ

すべてのスタックに適用されるデフォルト値を定義します(スタック定義ごとに上書きされない場合)。

# 各CloudFormationスタック項目に'profile'を設定することを強制
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
  # 2番目のスタック
  - 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 }}"

テンプレート

このセクションでは、Jinja2ディレクティブを使用してCloudFormationテンプレートで何ができるかの簡単な概要を示します。

例: サブネット定義

次のテンプレートは、異なるステージング環境に展開でき、異なる数のサブネットを含めることができます。

Ansible変数

---
# file: 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
---
# file: 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変数

---
# file: staging.yml
# ステージングは広く開放されており、開発者が
# 接続できるようにしています。
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
---
# file: 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差分モードにするには、cloudformation_diff_outputjsonに設定します。

TASK [cloudformation : cloudformationテンプレートファイルの差分] *********************************************
--- before
+++ after
@@ -38,7 +38,6 @@
             "Type": "AWS::S3::BucketPolicy"
         },
         "s3Bucket": {
-            "DeletionPolicy": "Retain",
             "Properties": {
                 "BucketName": {
                     "Ref": "bucketName"

Yaml 差分

出力形式をyaml差分モードにするには、cloudformation_diff_outputyamlに設定します。

TASK [cloudformation : cloudformationテンプレートファイルの差分] *********************************************
--- 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'

依存関係

このロールは他のロールに依存しません。

要件

CloudFormation用の--checkモードを持つためには、Ansible 2.5以上を使用してください。

ローカルとリモートのCloudFormationテンプレートの行単位の差分を使用する場合は、Pythonモジュールcfn_flipが必要です。これを簡単にローカルでインストールできます:

$ pip install cfn_flip

ライセンス

MITライセンス

著作権 (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.cloudformation
ライセンス
mit
ダウンロード
5.2k
所有者
DevOps Engineer