AWS Playbookの設計ポリシー
渡辺です。
Ansible2.2より、AnsibleのAWS関連モジュールが充実され、AnsibleでAWSリソースの構成管理を行うことが現実味を帯びてきました。 AWSリソースの構成管理を行うには、CloudFormationやteraformなど、他の選択肢も多くあります。 その中でも、EC2インスタンスの構成管理をAnsibleで行っているならば、利用するツールを共通化できるのが最大のメリットです。
今回は、そんなAWSリソースを構成管理するとき、作成するPlaybookの設計ポリシーを解説します。
localhostのlocalコネクションを利用する
一般的に、Ansibleでは、対象ホストにSSH接続を行い、構成管理を行います。 AWSリソースの場合、対象となるのはVPCなど、AWSリソースであるため、SSH接続は行えません。 このようなケースでは、対象ホストにローカルマシンを指定し、SSH接続も行わないオプションを指定します。 また、AnsibleではSSH接続時、はじめにホストの情報を収集します(gather_facts)。 これも不要となるため、Playbookの冒頭は次のようになります。
- hosts: localhost connection: local gather_facts: False
プロファイルの準備
AnsibleのAWSモジュールはPython版のAWS SDKであるbotoのラッパーです。 内部的にAWS APIを使いますので、IAM Userを作成し、適切な権限を持ったアクセスキーを作成する必要があります。 クレデンシャルファイルにプロファイルを作成してください。
なお、Playbookにアクセスキーとシークレットキーを埋め込むことも可能ですが、バージョン管理システムにコミットするなど、アクセスキーの漏洩に繋がりますので、ゼッタイに辞めましょう。 やるならば、グループファイルをvaltで暗号化するべきですが、素直にプロファイルを利用すべきです。
環境毎にグループ変数を定義する
AWS環境を構築する場合、ほとんどのケースで、本番環境と検証環境、さらに開発環境を作ることになります。 そして、リソース名など環境毎の差異が発生します。 この差異はAnsibleのグループ変数(group variable)を利用して吸収します。
グループ変数を差し替え、共通のPlaybookを利用した構築を行えば、検証環境などで構築した環境と寸分違いなく本番環境を構築可能となります これは作業ミスを防ぐ意味でも、構築の効率化を進める上でも重要です。
次のようにインベントリファイルを環境毎(prd/stg)に作成し、それぞれにグループ変数(all.yml)を定義します。
└── hosts ├── prd │ ├── group_vars │ │ └── all.yml │ └── inventory └── stg ├── group_vars │ └── all.yml └── inventory
inventoryファイルは現時点では空で良いでしょう(localhostは暗黙で追加されるため)。 all.ymlには環境毎に異なる変数を定義してください。 また、プロファイルとリージョンの2つの変数もあわせて定義します(検証環境と本番環境が同一AWSアカウントであればプロファイルは同じ場合もあるでしょう)。
# hosts/prd/group_vars/all.yml --- env: prd profile: hogehoge-prd region: ap-northeast-1
# hosts/stg/group_vars/all.yml --- env: stg profile: hogehoge-stg region: ap-northeast-1
ansible-playbookコマンド実行時には、-iオプションを利用して、環境を指定します。
ansible-playbook -i hosts/prd aws-net.yml
Playbookの分割
AnsibleのPlaybookでは、CloudFormationなどと同様に、全AWSリソースを一括で定義することもできます。 しかし、巨大な定義ファイルは可読性も低く、管理しにくくなります。 CloudFormationと同様に、適切なレイヤで分割して管理するのが妥当です。 例えば、VPCやサブネットを定義するネットワークレイヤは、aws-net.ymlで定義します。
モジュール共通オプションのprofileとregion
AnsibleのAWSモジュールの特性として、各タスク毎にprofile
とregion
を指定する必要があります。
冗長ではと考えてしまいますが、複数のリージョンに横断したシステムや、複数のAWSアカウントに横断したシステムもあることを考えると仕方ない部分とも言えます。
これらのパラメータについては、各モジュールで変数を使って設定する事を基本としておきましょう。
- ec2_vpc_net: name: VPC cidr_block: 10.0.0.0/16 profile: "{{ profile }}" region: "{{ region }}"
主要パラメータはグループ変数に定義する
変更が簡単になる用に、各リソースの主要パラメータはグループ変数に定義します。 一覧性も良くなります。
# hosts/prd/group_vars/all.yml --- env: prd vpc: name: VPC cidr_blodk: 10.0.0.0/16 subnet: - name: FrontA az: us-east-2a cidr: 10.0.1.0/24 - name: FrontC az: us-east-2c cidr: 10.0.2.0/24
各モジュールでは変数を参照する記述にすれば、Playbookの再利用性も高くなります。
- ec2_vpc_net: name: "{{ env }} {{ vpc.name }}" cidr_block: "{{ vpc.cidr_blodk }}" profile: "{{ profile }}" region: "{{ region }}"
registerで実行結果を保持する
AWSリソースを定義するには、例えばVPC IDなど、直前に実行したモジュールの実行結果から参照するパラメータが必要となります。
これらの値は、register
構文を使い、変数に保存し、後から利用します。
命名規則として、register
で登録する変数は_をプレフィックスとします。
- ec2_vpc_net: name: "{{ env }} {{ vpc.name }}" cidr_block: "{{ vpc.cidr_blodk }}" profile: "{{ profile }}" region: "{{ region }}" register: _vpc - debug: var=_vpc verbosity=1
さらにdebug
モジュールを利用して、変数の出力を行うようにしています。
毎回出力されるのも鬱陶しいので、verbosity
オプションを指定しましょう。
verbosity=1
なのでコマンド実行時に-v以上の指定があれば、変数がデバッグ出力されます。
$ ansible-playbook -i hosts/prd aws-net.yml -v $ ansible-playbook -i hosts/prd aws-net.yml
まとめ
今日は、AnsibleのAWSモジュールを利用したPlaybookの設計ポリシーについて解説しました。 Ansibleの基本を踏襲してAWSリソースを定義すれば、メンテナンス性の高いPlaybookを作ることができるでしょう。