はじめに
クラウド環境におけるインフラの自動化において、「Terraformでリソースを作成し、AnsibleでOSやミドルウェアを設定する」 という組み合わせをしているのをよく目にします。
しかし、実際に自分でやろうと思うと以下のような壁にぶつかると思います。
- そもそもTerraformの後に、どうやってAnsibleを実行するの?
- Ansibleのインベントリ(対象機器の接続情報を記載するファイル)ってどうやって書いたらいいの?
本記事では、以下のようなシナリオでTerraformで構築済みのEC2インスタンスに対し、AnsibleでPlaybookを実行する手順を解説します。(インスタンスの詳細は、後述の前提条件を参照)
- AWS EC2用 動的インベントリ設定ファイルの作成
- AnsibleがEC2タグや状態(running)にもとづいて自動的に対象ホストを検出するように設定します。
- Ansible Playbookの実行
- 動的インベントリで取得したターゲット(EC2)に対して、ファクトを取得するPlaybookを実行します。
TL;DR
この記事を読めば、以下のことができるようになります
- TerraformとAnsibleの役割分担をさせる方法
- EC2インスタンス用の動的インベントリ(Dynamic Inventory)の書き方
前提条件
- Ansibleの実行対象となるEC2インスタンス2台が構築済みであること
- EC2インスタンスの
tag:Nameは、terraform-test-1-instanceとterraform-test-2-instanceとします - TerraformでEC2インスタンスを構築したい場合は、過去の記事(【Terraform】モジュールでEC2インスタンスを一気に作りたい)を参照
- EC2インスタンスの
- Ansible実行環境が、EC2インスタンスの閲覧権限以上を所有していること
- 本記事では、検証用に
AmazonEC2FullAccessを所有しています
- 本記事では、検証用に
実行環境
- Ansible
- ansible-core: 2.19.8
- Ansible Collection
- amazon.aws: 11.2.0
- Python library
- boto3: 1.42.84
- botocore: 1.42.84
詳細
1. TerraformとAnsibleの役割分担
TerraformとAnsibleを連携させる最大のポイントは、どちらか一方を選ぶのではなく、それぞれの強みを活かして完全に分担することです。
「Terraformで土台(インフラ)を構築し、Ansibleで中身(OS・ミドルウェア)をセットアップする」のが使いやすいです。
| 比較アプローチ | メリット | デメリット・課題 |
|---|---|---|
| Terraformのみ | インフラ管理が一元化できる | OS内部の細かい設定(user_data等)の実装が複雑になる |
| Ansibleのみ | インフラ作成から設定まで一括実行可能 | クラウドのリソース依存関係や「破棄・更新」の管理(状態管理)がTerraformほど強力ではない |
| Terraform × Ansible (ハイブリッド運用) |
各ツールの長所を最大化。インフラと設定の責務が分離され、コードの再利用性と可読性が向上する | ツールが2つになるため、Terraformの完了後にAnsibleへ引き継ぐ連携設計(動的インベントリ等)が必要 |
2. なぜ動的インベントリ(Dynamic Inventory)をつかうのか?
結論から言うと、クラウド環境で固定IPを手入力する運用から脱却するためです。
- Terraformでインスタンスを構築する場合に起きる課題
- Terraformでインスタンスの作成・破棄を行うクラウド環境では、IPアドレスが動的に変化するため、インベントリにIPアドレスを固定値で記入することができない
- 対策
- Ansibleの
amazon.aws.aws_ec2プラグイン(動的インベントリ)を利用することで、
IPアドレスを含めた最新のEC2インスタンスの情報を自動取得することができる
- Ansibleの
3. インベントリ(inventory_ec2.yml)
amazon.aws.aws_ec2プラグインで、EC2インスタンスの情報を自動取得します。
必要に応じてfiltersを使用してインスタンスにフィルターをかけることができます。
今回は、「instance-state-name: runningで起動しているインスタンス」、
「tag:Nameで指定したName(ワイルドカード可)のインスタンス」を検索しています。
plugin: amazon.aws.aws_ec2
regions:
- ap-northeast-1
filters:
instance-state-name: running # 起動しているインスタンス
tag:Name:
- terraform-test-* # Nameがterraform-testから始まるインスタンス
hostnames:
- tag:Name
- ip-address
- private-ip-address
compose:
ansible_user: "'ec2-user'"
ansible_host: public_ip_address
ansible_ssh_private_key_file: "'~/.ssh/private_key.pem'"
4. ファクト情報取得用Playbook(display_facts.yml)
EC2インスタンスにアクセスしてプライベートIPアドレスを表示するPlaybookです。
---
- hosts: all
gather_facts: false
tasks:
- name: Gather minimal network facts
ansible.builtin.setup:
gather_subset:
- 'network'
- name: Show private IP
ansible.builtin.debug:
var: ansible_facts['default_ipv4']['address']
5. Playbook実行
Playbookを実行すると、フィルターにかかっているEC2インスタンス2台にだけPlaybookが実行されています。
- 実行コマンド
$ ansible-navigator run display_facts.yml -i inventory_ec2.yml
- 実行ログ
$ ansible-navigator run display_facts.yml -i inventory_ec2.yml
PLAY [all] *********************************************************************
TASK [Gather minimal network facts] ********************************************
ok: [terraform-test-1-instance]
ok: [terraform-test-2-instance]
TASK [Show private IP] **********************************************************
ok: [terraform-test-1-instance] => {
"ansible_facts['default_ipv4']['address']": "10.0.1.143"
}
ok: [terraform-test-2-instance] => {
"ansible_facts['default_ipv4']['address']": "10.0.1.188"
}
PLAY RECAP *********************************************************************
terraform-test-1-instance : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
terraform-test-2-instance : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
さいごに
本記事では、Terraformで構築済みのEC2インスタンスに、Ansibleの動的インベントリ(amazon.aws.aws_ec2)でPlaybookを実行する流れを紹介しました。クラウド環境ではIPアドレスが動的に変わるため、固定のIPアドレスを書くのではなく、動的インベントリの利用を推奨します。
TerraformとAnsibleそれぞれの得意分野を理解し、連携させることで運用の手間やミスを大幅に削減できますので、ぜひ試してみてください。
参考URL
-
Ansible vs Terraform
- Ansible vs Terraformの違いについて説明