atlas
Terraform

環境ごとにAtlasのEnvironmentを分けてTerraformのテンプレートをproduction環境とstaging環境で共有する

More than 3 years have passed since last update.


概要

Terraformのテンプレートを作成したとき、production環境に適用する前に、staging環境に適用して確認したいですよね。

Terraform標準ではenvironmentsの機能は存在しないため、environmentsを表す変数を用意し、それをterraformコマンド実行時に渡すことでenvironments機能を再現させます。

また、このときTerraformで作成したリソースの状態を保存するTerraform Stateもenvironmentsごとに分けるようにします。

ここではTerraform StateをAtlasに保存することとします。


テンプレートの書き方

まず、environmentsを表すenvという変数を用意します。そして、environmentsによって使う値を切り替えたいものについて、environments名をキーとしたマップを作成します。


variables.tf

variable "env" {

description = "Environment name (production or staging)"
}

variable "instance_types" {
default = {
production = "c3.2xlarge"
staging = "t2.small"
}
}

...


こうすることで、lookup()を使い、envの値によって取得する値を切り替えられるようになります。


main.tf

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コマンドに渡すオプションという形で呼び出します。


tf.sh

#!/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でも提案されており、今後対応することに期待します。