LoginSignup
23
20

More than 5 years have passed since last update.

TerraformとAnsibleを連携させたい

Last updated at Posted at 2015-12-18

TerraformとAnsibleを連携させたい

TerraformのProvisonerにAnsibleがない...でもTerraformとAnsibleを連携させたい...

その戦いの記録です。

前提

AWS構成

ec2-and-rds.png

ディレクトリ構成

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が欲しいです。

23
20
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
20