Terraform Workspaces利用時の変数管理を考える

2021年3月2日

Terraform

Terraform の Workspaces を利用して複数の tfstate を管理しているとき、tfvars ファイルも Workspaces に合わせて環境ごとに用意することがあると思います。

たとえばディレクトリ構成はこのようになっていて

├── main.tf
├── development.tfvars
├── production.tfvars
└── variables.tf

Terraform を実行するときに Workspace と tfvars をそれぞれ指定する運用です。

$ terraform workspace select development
$ terraform plan -var-file="development.tfvars"

この方法でも運用できるのですが、Workspace と -var-file の組み合わせを間違えないようにする必要があり、毎回気をつけるのがしんどいので、どうにか楽にできないかと考えた記録を残します。

Terraform のバージョンは v0.13 です。

目次

  1. 方法1:plan, apply 用のシェルスクリプトを書く
  2. その2:ローカル変数 (locals) を使う
  3. 2つの方法を本番環境で運用してみて、結局どうしたか

方法1:plan, apply 用のシェルスクリプトを書く

ディレクトリ構成は以下の通り。冒頭のファイル構成に deploy.sh を追加しています。

├── main.tf
├── deploy.sh
├── development.tfvars
├── production.tfvars
└── variables.tf

main.tfにはリソースの定義

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = var.image_id
}

variables.tfには変数定義

variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."
}

development.tfvarsには変数の値が書かれています。

image_id = "ami-abc123"

この状況であらたにdeploy.sh を書いて(簡略化のためヘルプや入力値チェックのコードを省略しています)

#!/bin/bash
set -e

COMMAND=$1
WORKSPACE=$2

terraform workspace select ${WORKSPACE}
terraform ${COMMAND} -var-file=${WORKSPACE}.tfvars

以下のように実行をします。

deploy.sh plan development

Terraform の実行は workspaces の切り替えなどをする必要がなく 1 コマンドで済みます。ただし、Terraform のプロジェクトが増えた場合にdeploy.sh を毎回配置して回るのが少し面倒です。

その2:ローカル変数 (locals) を使う

locals を使うとローカル変数が定義できます。これを使って変数を管理します。

先に全体のディレクトリ構成。variables.tf.tfvars がありません。

├── main.tf
├── locals.tf
├── locals_development.tf
└── locals_production.tf

locals.tfで以下のように、ローカル変数の Maps/Objects を定義します。ローカル変数 variables のキーには Workspace の名前と同じ文字列(development, production)をいれます。

locals {
  variables = {
    default       = local.development
    development   = local.development
    production    = local.production
  }

  variable = local.variables[terraform.workspace]
}

locals_development.tfでは、Workspace が development のときに使用するローカル変数を定義していきます。locals_production.tf も同じようにします。

locals {
  development = {
    image_id = "ami-abc123"
  }
}

main.tfでは、以下のようにローカル変数を指定します。このようにすると Workspace が development のとき、locals_development.tf で定義した値が入るようになります。

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = local.variable["image_id"]
}

実行方法です。terraform planの後に -var-fileの指定がなくなり、Workspace を選択するだけで良くなります。

$ terraform workspace select development
$ terraform plan

2つの方法を本番環境で運用してみて、結局どうしたか

それぞれの方法で本番環境で運用をしてみて、現在はその 1 の方法を選ぶようになりました。

理由としては、その1の方法が

  • 標準的な構造なので、他のメンバーが馴染みやすく理解しやすい
  • 変数の型や説明を書くことができる
  • 変数まわりでエディタの入力補完が効く

というところが大きかったです。また、When To Use Local Values を読んで、その 2 の方法がローカル値の想定された使い方からは外れていると考えるようになりました。

ローカル変数は、設定の中で同じ値または式を複数回繰り返さないようにするのに役立ちますが、使いすぎると、実際に使われている値が隠されてしまい、将来のメンテナが設定を読みにくくしてしまう可能性があります。

ローカル変数は、1 つの値や結果が多くの場所で使用され、その値が将来的に変更される可能性がある場合のみ、適度に使用してください。ローカル変数の主な利点は、一箇所で簡単に値を変更できることです。

When To Use Local Values - Terraform by HashCorp

参考になれば幸いです。

-技術ブログ
-