LoginSignup
5
3

More than 3 years have passed since last update.

Terraformのかゆい所に手をのばす 〜 meta-arguments 〜

Last updated at Posted at 2019-12-27

この記事はフューチャー Advent Calendar 2019(2)の5日目の記事です。4日目の記事はKhdbbleさんのEbitenでImage操作 ~キャラクターを動かす~でした。筆者もゲームエンジンで遊びたくなりました。

はじめに

業務内で、Terraformのコードやissueを見ていると、「案外、知られていないのでは?」と思うような設定項目いくつかあることに気づきました。また、resourceごとにそれらが作成される際の個数や挙動を変えたいことがしばしばあり、ちょうどそのような内容のissueをいくつか担当しました。

本記事では、そんなTerraformのかゆい所に手が届く(かもしれない)resourceのmeta-argumentについてまとめてみます。

意外と知られていないmeta-argumentたち

resourceのmeta-argumentとは、どんなリソースタイプにも使えて、そのリソースの動作を変更できる設定のことです。

resourceで設定できるmeta-argumentは以下の通りです。

  • depends_on
  • count
  • for_each
  • provider
  • lifecycle
  • provisioner
  • connection

ここでは、depends_on, count, lifecycleを紹介します。
その他のmeta-argumentについては、こちらを参照してください。

depends_on

depends_onは、resourceの依存関係を解決するmeta-argumentです。すべてのresourceブロック内で利用可能です。「Terraformって、依存関係を自動的に見てくれるのでは?」と疑問に思われるかもしれませんが、参照関係がないresource間で依存関係を設定したい場合に、depends_onを利用します。

以下はAWSでの例です。リファレンスのコードを抜粋しました。

resource "aws_iam_role_policy" "example" {
  name   = "example"
  role   = aws_iam_role.example.name
  policy = jsonencode({
    "Statement" = [{
      # EC2がS3にアクセスするためのポリシー
      "Action" = "s3:*",
      "Effect" = "Allow",
    }],
  })
}

resource "aws_instance" "example" {
  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"

  # aws_iam_instance_profile.exampleは定義済み
  # Terraformが参照から依存関係を推測します
  iam_instance_profile = aws_iam_instance_profile.example

  # S3へのアクセスが必要になるので、aws_iam_role_policy.exampleが作成されていて欲しい
  depends_on = [
    aws_iam_role_policy.example,
  ]
}

便利なdepends_onですが、リファレンスに「最終手段(last resort)」と、強気な書き方がされている1ように、利用する際は注意が必要です。

依存関係の管理はできるだけTerraformに任せるべきであり、、開発者が依存関係を考えながらコードを書くのは好ましくありません。
どうしてもdepends_onを利用する場合は、他の編集者に設定の意図が伝わるようにドキュメントやコメントを残し、depends_onに設定する依存関係は最小限なるように心掛けましょう。

count

countは数値を設定することで、設定されたリソースの個数を指定することができます。これもresourceブロックで利用可能です。例えば、GCPのリソースの場合は以下に使います。

variable "count_standard" {
  default = {
    "prod" = 1
    "dev"  = 2
  }
}

resource "google_compute_instance" "standard" {
  name         = "sample"
  count        = var.count_standard["${terraform.workspace}"]
  machine_type = "n1-standard-1"
  zone         = "asia-northeast1-b"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }
  ...(以下略)...
}

この場合、prod環境2では1つ、dev環境では2つのGCEインスタンスが作成されます。
variableのブロックを別ファイルに書き出すことで、リソースの個数を別のファイルで管理することもできます。

lifecycle

lifecycleではTerraformのリソース操作を変更できます。こちらも全てのresourceブロック内で利用可能です。項目としては以下のようなものがあります。

  • create_before_destroy
  • prevent_destroy
  • ignore_changes

例えば、リソースによっては設定に変更があった場合、そのリソースを一度削除して再作成します。このとき、リソースの削除が再作成に先行してしまうと、もしそのリソースのへの参照を持ったリソースがある場合に名前解決ができなくなってしまいます。
そこでcreate_before_destroyを用います。先に新しい設定を取り込んだリソースを作成し、参照を切り替えた後に古いリソースを削除することで、参照元が名前解決できるようになります。

また、ignore_changesは特定の設定を無視するためのmeta-argumentです。

再作成の生じるリソースにおいて、設定を変更するたびに削除・作成が行われるのは、時間がかかることもあり、好ましくありません。そこで、ignore_changesで例えば、Terraform管理外のラベル(タグ)の変更を実体に反映させないことで、無駄な再作成を防ぐことができます。

終わりに

resourceのmeta-argumentについて紹介させていただきました。筆者もTerraform歴がまだまだ浅いので、これからもTerraformの利用方法についても考えていければと思います。


  1. https://www.terraform.io/docs/configuration/resources.html#depends_on-explicit-resource-dependencies 

  2. Workspace機能を利用すると、同じコードを環境ごとに使い分けることができます 

5
3
0

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
5
3