概要
Terraformのテンプレートを作成したとき、production環境に適用する前に、staging環境に適用して確認したいですよね。
Terraform標準ではenvironmentsの機能は存在しないため、environmentsを表す変数を用意し、それをterraform
コマンド実行時に渡すことでenvironments機能を再現させます。
また、このときTerraformで作成したリソースの状態を保存するTerraform Stateもenvironmentsごとに分けるようにします。
ここではTerraform StateをAtlasに保存することとします。
テンプレートの書き方
まず、environmentsを表すenv
という変数を用意します。そして、environmentsによって使う値を切り替えたいものについて、environments名をキーとしたマップを作成します。
variable "env" {
description = "Environment name (production or staging)"
}
variable "instance_types" {
default = {
production = "c3.2xlarge"
staging = "t2.small"
}
}
...
こうすることで、lookup()
を使い、env
の値によって取得する値を切り替えられるようになります。
resource "aws_launch_configuration" "as_conf" {
...
instance_type = "${lookup(var.instance_types, "${var.env}")}"
...
}
AtlasにEnvironmentを作る
AtlasのEnvironmensからNew Environmentを選択し、新しいEnvironmentを作成します。
このAtlasのEnvironmentの名前には、env
変数に渡すenvironment名をサフィックスとして付与します。
例えば、sample/app-production
/sample/app-staging
のようにします。
それ以外は通常どおりEnvironmentを作成します。
Terraform Stateの保存場所の指定
上記で作成したAtlas EnvironmentをTerraform Stateの保存先として指定します。
Terraformを実行したいenvironment名に該当する方のAtlas Environmentです。
$ terraform remote config -backend-config="name=sample/app-staging"
terraformコマンドの実行の仕方
env
変数にenvironment名が渡るように、terraform
コマンドにオプションを付与します。
$ terraform plan -var 'env=staging'
$ terraform apply -var 'env=staging'
environmentの切り替え方
別のenvironmentに切り替える場合は、いったん現在のTerraform Stateを無効にする必要があります。
これには.terraform
ディレクトリをまるごと削除します。
$ rm -rf .terraform/
そして、切り替えたいenvironment名に該当するAtlas Environmentをremote configで指定します。
$ terraform remote config -backend-config="name=sample/app-production"
remote configを無効にするコマンドも存在しますが、こちらではterraform.tfstate.backup
ファイルが残存し、そのファイルが存在する状態で別のAtlas Environmentを設定すると、Atlasに保存されているTerrafrom Stateが壊れてしまいます。
$ terraform remote config -disable
もし、誤ってAtlasに保存されているTerraform Stateを壊してしまった場合は、https://atlas.hashicorp.com/<Organization名>/environments/<Atlas Environment名>/changes
を開き、Statesにチェックを入れるとTerraform Stateの履歴一覧が表示されるので、正常だったときのTerraform Stateを開いてRollbackから復旧させてください。
参考: Managing Multiple Environments (Stage, QA, Prod) - Help | Atlas by HashiCorp
簡易的なラッパースクリプト
上記のremote configの切り替えを毎回行うのは面倒ですし、現在どのAtlas Environmentを設定しているのか忘れてしまいます。
そこで以下のようなterraform
コマンドをラップするスクリプトを用意しました。jq
コマンドもインストールされていることが前提です。
./tf.sh environment名 terraformコマンドに渡すオプション
という形で呼び出します。
#!/usr/bin/env bash
set -e
atlas_organization="sample"
atlas_environemnt_base="app"
tfstate_file=".terraform/terraform.tfstate"
env=$1
shift
atlas_config_name="${atlas_organization}/${atlas_environemnt_base}-${env}"
configure_tfstate() {
terraform remote config -backend-config="name=${atlas_config_name}"
}
clear_tfstate() {
# terraform remote config -disableでは不十分
rm -rf ./.terraform/
}
check_same_environment() {
local tfstate_config_name=$(cat $tfstate_file | jq -r ".remote.config.name")
[[ $tfstate_config_name == $atlas_config_name ]]
}
if ! [[ -e $tfstate_file ]]; then
configure_tfstate
else
if ! check_same_environment; then
clear_tfstate
configure_tfstate
fi
fi
terraform "$@" -var "env=${env}"
今後のTerraform側の対応について
TerraformでのEnvironmentsの対応は以下の本家Issueでも提案されており、今後対応することに期待します。