cytopia.cloudformation
Ansibleロール: CloudFormationスタックの作成
動機 | インストール | 機能 | 変数 | 使用法 | テンプレート | 差分 | 依存関係 | 要件 | ライセンス
Ansibleロールは、任意の数のJinja2テンプレートをCloudFormationファイルにレンダリングし、任意の数のスタックをデプロイします。
動機
このロールは、CloudFormationテンプレートの欠点を克服し、Ansibleの機能を活用します。
- CloudFormationの制限 - CloudFormationの構文は、条件、ループ、配列や辞書のような複雑な変数のプログラミングロジックに関して非常に制限されています。CloudFormationテンプレートをAnsibleでラップすることで、テンプレート内でJinja2のディレクティブを使用できるため、Ansibleの美しさを享受しつつCloudFormationスタックをデプロイできます。
- 環境非依存 - カスタムループ変数を使用してCloudFormationテンプレートをレンダリングできるため、完全に環境非依存のテンプレートを作成し、プロダクション、テスト、ステージングなどの環境で再利用できます。
- 事前実行 - 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_output
をjson
に設定します。
TASK [cloudformation : cloudformationテンプレートファイルの差分] *********************************************
--- before
+++ after
@@ -38,7 +38,6 @@
"Type": "AWS::S3::BucketPolicy"
},
"s3Bucket": {
- "DeletionPolicy": "Retain",
"Properties": {
"BucketName": {
"Ref": "bucketName"
Yaml 差分
出力形式をyaml差分モードにするには、cloudformation_diff_output
をyaml
に設定します。
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
ライセンス
著作権 (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