Help us understand the problem. What is going on with this article?

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away