📝

Terraformを自分なりにメモる

2024/03/02に公開
2

Terraform を自分なりに整理する

自分用にメモしたものなので、責任は追えませんのでご了承ください。

ディレクトリ構造

以下のような感じにつくるとよさげ

$ tree
.
├── environments
│   ├── production
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   └── outputs.tf
│   └── staging
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   └── outputs.tf
└── modules
    ├── ec2
    │   ├── main.tf
    │   ├── output.tf
    │   ├── provider.tf
    │   └── variables.tf
    └── ...
    └── ...

一部ファイルの説明

  • main.tf
    モジュール、ローカル、およびデータソースを呼び出してリソースを作成
  • variables.tf
    main.tf で使用される変数を宣言
  • outputs.tf
    main.tf で作成されたリソースの出力
  • versions.tf
    Terraform とプロバイダーのバージョン要件を指定

詳しくは公式を見るとよし
https://www.terraform-best-practices.com/code-structure#getting-started-with-the-structuring-of-terraform-configurations

tfstateファイル

Terraformで管理しているインフラの状態を記録するためのファイル
自動的にこのファイルへ作成したリソースの状態が記録されます

複数人で作業をする場合は、S3等のストレージに保存して共有できるようにしておく
※バケットのバージョニング推奨

backend機能を使うことで、tfstateファイルをローカルではなく別のストレージに保存することが可能になる
(つまり、S3などのパブリッククラウドサービスのストレージに保存が可能)
書き方は公式を参考すると良し
https://developer.hashicorp.com/terraform/language/settings/backends/s3

environments

環境ごとに管理するために用意する
※backendは省略

main

変数の指定とどのモジュールを扱うかを設定するために使う

ローカル変数を使って汎用的に使う変数を指定できる
もちろん、varialbesファイルを別途用意してやってもよいが、environmentごとにファイルを分けてやるパターンであれば、変数用にファイルを分ける必要がない気がする

locals {
  common = {
    environment       = "production"
    region            = "ap-northeast-1"
  }
  vpc_id = "vpc-xxxxxxxxxxxxxxxxxxxxxx"
}

モジュールを読み込む場合は、以下のようにする

  • local変数
    • local.{変数名}
  • モジュールの値
    • module.module名.output値
module "ec2" {
  source = "../../modules/ec2"

  # 1つの変数に1つの値
  environment       = local.common.environment
  vpc_id            = local.vpc_id

  # 1つの変数に複数の値(変数名は適当です)
  properties = {
    property1 = "terraform"
    property2 = 111
    property3 = [
      "memo1",
      "memo2"
    ]
  }

outputs

各モジュールでoutputした値を出力できます
Moduleの名前までにしておくことで、Module側でOutputした値がまとまった形で出力されます

output "ec2_ids" {
  value = module.ec2
}

modules

ec2などの単位で作成するリソースを分けておく。

provider

クラウド プロバイダー、SaaS プロバイダー、およびその他の API と対話するために指定する必要がある

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

variables

変数を宣言するファイル。
ディレクトリ構造に書いたやり方だと、各環境のmain.tfで指定した変数をこのファイルで受け取る必要がある。
例として、object型?のやつを受け取るときの書き方

variable "environment" {
  type = string
}

variable vpc_id {
  type = string
}

variable "properties" {
  type = object({
    property1 = string
    property2 = number
    property3 = list(string)
  })
}

main

variables.tfに記載された変数にアクセスする場合は、var.{変数名} と書きます

resource "aws_instance" "example" {

  vpc_id = var.vpc_id
  tags = {
    Environment = "${var.environment}"
    Name        = "sample-${var.environment}"
    CreateBy    = "Terraform"
    Test        = "${var.properties.property1}"
  }
}

${var.environment} のように ${} で括っているのもあれば、var.vpc_id のように括らなくても問題ない。ただし、文字列と一緒に使う場合は ${} で括る必要がある。
v0.12 から ${} はつけなくてもよくなったみたいです

object型の変数は多分 "${var.properties.property1}" の形でいいはず。

おまけ(loopを使う場合)

main.tf からリストを渡してあげる
idparameter.id で使うため設定している

  properties = [
    {
      id = 1
      property1 = 1234,
      property2 = "terraform",
      property3 = "hogehoge",
      property4 = 5678
    },
    {
      id          = 2
      property1 = 4321,
      property2 = "terraform",
      property3 = "hoge",
      property4 = 8765
    }
  ]

変数は以下のようにリストでオブジェクトを受け取るようにしておけばOK

variable "properties" {
  type = list(object({
    property1 = number
    property2 = string
    property3 = string
    property4 = number
  }))
}

for_eachで受け取る。
注意として、parameter.id ってところにユニークな値が入ってくるため、作成するリソースにユニークな値が無い場合は自分で用意する必要がある(多分)

resource "aws_instance" "sample" {

  for_each = { for parameter in var.properties : parameter.id => parameter }

  property1 = each.value.var1
  property2 = each.value.var2
  property3 = each.value.var3
  property4 = each.value.var4

}

outputs

リソースの値を出力させることで、別のモジュールで参照出来るようになる
(出力できる値は使うリソースごとに異なるためドキュメントを確認すること)
使うリソース名.論理名.対象 のような形で指定する

output "property1_id" {
  description = "Id of property1"
  value       = aws_instance.sample.id
}

Discussion

rakiraki

ftstate は誤字で tfstate が正

kaqkaq

ありがとうございます。訂正しました。