TerraformとAnsibleを連携させたい
TerraformのProvisonerにAnsibleがない...でもTerraformとAnsibleを連携させたい...
その戦いの記録です。
前提
AWS構成
ディレクトリ構成
server/
├ ansible
│ └── roles
└ terraform
├── production
└── staging
- Ansibleのディレクトリ構成はベストプラクティスに準拠
やりたいこと
- a. Terraformで作成したEC2インスタンスに対して(登録したKey Pairで)
ansible-playbook
を実行したい - b. mysql_dbモジュールを利用して、EC2インスタンス経由でRDSインスタンスにデータベースを作成したい
Provisioner的な連続実行は諦めました
本当は、VagrantのProvisionerでAnsibleを実行するような流れるような実行をしたかったのですが、諦めました。
理由は以下です。
- local-execがEC2インスタンスがSSH接続できるようになる前に実行されてしまう。タイムアウトでアウト。
- RDSの接続情報も欲しい =>
terraform apply
が完全に終わってから実行したい。。
というわけで戦いの記録です。
"a. Terraformで作成したEC2インスタンスに対して ansible-playbook
を実行" の戦い
作戦1: Route53を利用して、生成したインスタンスに動的にドメインを割り当てる
- Inventoryファイルはドメイン固定で作成
- TerraformでRoute53にドメインのAレコードにEC2に割り当てたEIPを当てる
ドメインがRoute53経由であてるならアリかと。
作戦2: AnsibleのDynamic Inventory機能とterraform-inventoryを利用する
$ cd ansible/
$ TF_STATE=../terraform/staging/terraform.tfstate ansible-playbook -i $(which terraform-inventory) staging.yml --private-key=~/.ssh/b_chaoo_staging_rsa
個人的には好みです。
作戦3: null_resourceを利用してInventoryファイルを作成
# null
resource "null_resource" "for-ansible" {
provisioner "local-exec" {
command = "echo ここでがんばってInventoryファイルを作成する"
}
}
がんばる...
"b. RDSのエンドポイントを取得してmysql_dbモジュールでデータベース作成" の戦い
作戦1: null_resourceを利用してRDS情報のファイルを作成してLookupモジュールで読み込む
null_resourceを利用してRDSの情報を取得してファイルで取得します。
# null
resource "null_resource" "for-ansible" {
provisioner "local-exec" {
command = "echo ${var.db_username} > dbuser;echo ${var.db_password} > dbpass;echo ${aws_db_instance.nf-staging-rds.address} > dbhost"
}
}
で、Lookupモジュールで読み込みます。以下はsite.ymlの例
---
- name: example.com
hosts: rds.example.com
sudo: true
user: centos
vars:
docroot: /var/www/html/
dbuser: "{{ lookup('file', '../terraform/staging/dbuser') }}"
dbpass: "{{ lookup('file', '../terraform/staging/dbpass') }}"
dbhost: "{{ lookup('file', '../terraform/staging/dbhost') }}"
dbname: my_dbname
roles:
- common
- xxx1
- xxx2
- rds
CSVファイルを作ってcsvfile
Lookupを利用するのもいいかも。
ファイルが3つに分かれるのがなんとも。。。
作戦2: jqを利用してterraform.tfstateから必要情報を取得する
terraform.tfstate がJSONなのを利用してjqで情報を取得してみます。
---
- name: データベースを作成
mysql_db:
login_host="{{ lookup('pipe', 'jq \'.modules[].resources[\"aws_db_instance.nf-staging-rds\"].primary.attributes.address\' ../../../../terraform/staging/terraform.tfstate') }}"
login_user="{{ lookup('pipe', 'jq \'.modules[].resources[\"aws_db_instance.nf-staging-rds\"].primary.attributes.username\' ../../../../terraform/staging/terraform.tfstate') }}"
login_password="{{ lookup('pipe', 'jq \'.modules[].resources[\"aws_db_instance.nf-staging-rds\"].primary.attributes.password\' ../../../../terraform/staging/terraform.tfstate') }}"
name=my_dbname
state=present
encoding=utf8
まとめ
TerraformとAnsibleをいろんな作戦で連携させてみました。
やっぱりTerraformにAnsible Provisionerが欲しいです。