Terraformでインフラをプロビジョニングしたあとに上物に対してAnsibleで何か(アプリをインストールしたりデータを投入したり)処理をするようなことが多いので、AnsibleからTerraformを実行するようにして一発で処理できるようにするにはどうするか実装を確認してみた。
Ansibleモジュールはcommunity.general.terraform
を使用する。
※ apply
とdestroy
を間違えてたか所を修正(23:55)
project_pathのパス指定
/path/to/tffiles
以下でterraform apply
をする構成であれば以下の通り。
- name: apply terraform community.general.terraform: project_path: /path/to/tffiles state: present
このタスクを実行すると、/path/to/tffiles
以下でterraform apply -auto-approve
を実行するのと同様の動作になる。
TerraformのコードをAnsibleとは別リポジトリで管理してあり、AnsibleからTerraformのコードをgit clone
してapply
するような構成であればこれで良いと思う。
一方で、構成によってはTerraformのコードをAnsibleと同じディレクトリで管理する場合もあるかと思う。その場合は実行に使うプレイブックからの相対パスでproject_path
を指定する。
ただ、現時点でのcommunity.general
version 8.3.0だと、ディレクトリ名だけだとパスを認識してくれないため、末尾に/
を付与する必要があるっぽい。
例えば以下のディレクトリ構成でtffiles
以下でterraform apply
を実行する想定の場合。
. ├── inventory.ini ├── playbook.yml └── tffiles ├── main.tf ├── outputs.tf ├── provider.tf └── variables.tf
タスクのコードとしては以下の通り。
- name: apply terraform community.general.terraform: project_path: tffiles/ state: present
このときにproject_path
に単にtffiles
と指定すると、以下エラーとなる。
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Path for Terraform project can not be None or ''."}
コード見ればわかるんだろうけど、末尾に/
が無いとエラーになるのはなぜだろうね。
ちなみに./tffiles
でもOK
変数指定
Terraformでvariable
を使った変数定義については、community.general.terraform
モジュールのvariables
パラメタで指定できる。
- name: apply terraform community.general.terraform: project_path: ./tffiles state: present variables: infra_region: "{{ region }}" app_ami_id: "{{ app_ami }}" db_ami_id: "{{ db_ami }}"
この定義で、Terraform側で定義している変数infra_region
、app_ami_id
、db_ami_id
をAnsibleのタスク側から上書きする動作になる。
出力変数
Terraformでプロビジョニングされたリソースの情報を取得するためのoutput
を使った定義については、Ansibleではタスクの実行結果の戻り値として参照できる。なので、register
ディレクティブを使って後続のタスクなどで参照できる。
output "route_table_id" { value = aws_route_table.example_rtb.id description = "ID of Route Table" } output "vpc_id" { value = aws_vpc.example_vpc.id description = "ID of VPC" } output "nic_id" { value = aws_network_interface.example_ni.id description = "ID of Network Interface" }
こんなoutput
定義を行っておけば、タスク定義でregister
を使って戻り値を参照でき、クラウドリソースのIDやIPアドレスを使った後続のタスクに使用できる。
以下は、AWSのルートテーブルを書き換える例。
(デフォルトで作成されるルートテーブルは作成の段階でカスタマイズできないため、作成済みのリソースをAnsibleで更新している)
- name: apply terraform community.general.terraform: project_path: ./tffiles state: present register: result - name: update routetable amazon.aws.ec2_vpc_route_table: region: "{{ region }}" route_table_id: "{{ result.outputs.route_table_id.value }}" lookup: id vpc_id: "{{ result.outputs.vpc_id.value }}" routes: - dest: 10.1.0.0/16 network_interface_id: "{{ result.outputs.nic_id.value }}"
環境
$ cat /etc/fedora-release Fedora release 39 (Thirty Nine) $ terraform providers -version Terraform v1.7.4 on linux_amd64 + provider registry.terraform.io/hashicorp/aws v5.38.0 $ ansible --version ansible [core 2.16.3] config file = None configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/venv/ansible9/lib64/python3.12/site-packages/ansible ansible collection location = /home/zaki/.ansible/collections:/usr/share/ansible/collections executable location = /home/zaki/venv/ansible9/bin/ansible python version = 3.12.2 (main, Feb 7 2024, 00:00:00) [GCC 13.2.1 20231205 (Red Hat 13.2.1-6)] (/home/zaki/venv/ansible9/bin/python) jinja version = 3.1.3 libyaml = True $ ansible-galaxy collection list community.general # /home/zaki/venv/ansible9/lib/python3.12/site-packages/ansible_collections Collection Version ----------------- ------- community.general 8.3.0
お、今年初めてプレイブック書いた気がするぞ。