mito’s blog

IT技術メインの雑記。思い立ったが吉日。

[Ansible X Terraform] Terraform Provider for Ansible 「resource "ansible_host"」を触ってみた

この記事は、Ansible Advent Calendar 2023 の3日目のエントリです。

はじめに

気になっていた Terraform Provider for Ansible をこの機に触ってみました。


Terraform Provider for Ansible のまとめ

  • Terrafromの定義ファイルにresource "ansible_host"を追加する
    • 上記の結果がtfstateに記載される
  • Ansibleのインベントリファイルにcloud.terraformプラグインを指定する
    • インベントリファイルがtfstateの該当箇所を読み込む



環境

Ubuntu 22.04.3に構築しています。

  • Ansible環境
    • Ansible core : 2.15.6
    • Python : 3.10.12
    • cloud.terraform : 2.0.0
  • Terraform環境
    • Terraform : 1.6.5


環境の準備

Ansibleコレクションにて、cloud.terraform をインストールします。

$ ansible-galaxy collection install cloud.terraform
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/cloud-terraform-2.0.0.tar.gz to /home/ubuntu/.ansible/tmp/ansible-local-12661qsgjsrrt/tmpzhqh3nnq/cloud-terraform-2.0.0-a_5loo9d
Installing 'cloud.terraform:2.0.0' to '/home/ubuntu/.ansible/collections/ansible_collections/cloud/terraform'
cloud.terraform:2.0.0 was installed successfully
$ 
$ 
$ ansible-galaxy collection list

# /home/ubuntu/.ansible/collections/ansible_collections
Collection                    Version
----------------------------- -------
cloud.terraform               2.0.0  

()
$ 


次に、terraformのansibleプラグインをインストールします。 ただしterrafrom initでインストールされるため、準備では割愛します。


TerraformでEC2インスタンスを構築する

3台のEC2インスタンスを構築します。


定義ファイルの作成

鍵はあらかじめ作成してあるものを流用、セキュリティグループはSSHのみ開けています。

terraform {
  required_providers {
    ansible = {
      version = "~> 1.1.0"
      source  = "ansible/ansible"
    }
  }
}

### ansible host details   今回のメイン。後述のtfstateに記載される。
resource "ansible_host" "inventory" {
    for_each                            = var.instance
    
    name                                = aws_instance.server[each.value.name].public_dns
    groups                              = ["test_group"]
    
    variables = {
        ansible_user                    = "ec2-user",
        ansible_ssh_private_key_file    = "~/.ssh/xxx.pem", # Terraformkey指定と違い、ファイル名なので拡張子も必要。
    }
}

provider "aws" {
    region = "ap-northeast-1"
}

variable instance {
    type = map
    default = {
        mito        = { name = "mito" },
        mito-ec2    = { name = "mito-ec2" },
        mito-ec22   = { name = "mito-ec22" },
    }
}

resource "aws_instance" "server" {
    for_each                    = var.instance

    ami                         = "ami-012261b9035f8f938"
    instance_type               = "t2.micro"
    key_name                    = "xxx"
    associate_public_ip_address = "true"
    
    vpc_security_group_ids      = [aws_security_group.blog_sg.id]
    tags = {
        Name                    = each.value.name
    }
}

resource "aws_security_group" "blog_sg" {
    name        = "blog_sg"
    description = "blog_sg"

    dynamic "ingress" {
        for_each = [22]

        content {
            from_port   = ingress.value
            to_port     = ingress.value
            protocol    = "tcp"
            cidr_blocks = ["0.0.0.0/0"]
        }
    }

    egress {
        from_port   = 0
        to_port     = 0
        protocol    = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}


terraform applyの実行結果

EC2インスタンス作成のほか、tfstateには以下のように resource "ansible_host" の結果が記載されます。

  "resources": [
    {
      "mode": "managed",
      "type": "ansible_host",
      "name": "inventory",
      "provider": "provider[\"registry.terraform.io/ansible/ansible\"]",
      "instances": [
        {
          "index_key": "mito",
          "schema_version": 0,
          "attributes": {
            "groups": [
              "test_group"
            ],
            "id": "ec2-13-114-117-20.ap-northeast-1.compute.amazonaws.com",
            "name": "ec2-13-114-117-20.ap-northeast-1.compute.amazonaws.com",
            "variables": {
              "ansible_ssh_private_key_file": "~/.ssh/xxx.pem",
              "ansible_user": "ec2-user"
            }
          },


Ansibleのansible-inventoryコマンドを実行する

まずは、resource "ansible_host" の結果がどう反映されるか確認するため、ansible-inventoryコマンドを実行します。


インベントリファイルの作成

cloud.terraformプラグインを指定します。

---
plugin: cloud.terraform.terraform_provider


ansible-inventoryコマンドの実行結果

無事に、ホスト情報が出力されました。

$ ansible-inventory -i inventory.yml --graph --vars
@all:
  |--@ungrouped:
  |--@test_group:
  |  |--ec2-13-114-117-20.ap-northeast-1.compute.amazonaws.com
  |  |  |--{ansible_ssh_private_key_file = ~/.ssh/xxx.pem}
  |  |  |--{ansible_user = ec2-user}
  |  |--ec2-35-78-213-104.ap-northeast-1.compute.amazonaws.com
  |  |  |--{ansible_ssh_private_key_file = ~/.ssh/xxx.pem}
  |  |  |--{ansible_user = ec2-user}
  |  |--ec2-13-231-192-241.ap-northeast-1.compute.amazonaws.com
  |  |  |--{ansible_ssh_private_key_file = ~/.ssh/xxx.pem}
  |  |  |--{ansible_user = ec2-user}
$ 


Ansibleのplaybookを実行する

インベントリファイルを指定して、簡単なPlaybookを実行し、動作を確認してみます。


playbookの作成

gitのみインストールします。

---
- hosts: all
  gather_facts: no
  become: yes

  tasks:
    - name: install git
      ansible.builtin.yum:
        name: git
        state: present


ansible.cfgの作成

Fingerprintのチェックを無効にしておきます。

[defaults]
host_key_checking = False


playbookの実行結果

Terraform Provider for Ansibleを指定したインベントリファイルで、正常にPlaybookが実行できました。

$ ansible-playbook -i inventory.yml playbook.yml 

PLAY [all] *************************************************************************************************

TASK [install git] *****************************************************************************************
changed: [ec2-13-114-117-20.ap-northeast-1.compute.amazonaws.com]
changed: [ec2-35-78-213-104.ap-northeast-1.compute.amazonaws.com]
changed: [ec2-13-231-192-241.ap-northeast-1.compute.amazonaws.com]

PLAY RECAP ************************************************************************************************
ec2-13-114-117-20.ap-northeast-1.compute.amazonaws.com : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ec2-13-231-192-241.ap-northeast-1.compute.amazonaws.com : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ec2-35-78-213-104.ap-northeast-1.compute.amazonaws.com : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

$ 


終わりに

インベントリーファイルに、フィルターを組み合わせて使う感じで良さそう。