Terraformの状態、tfstateをAzure Storageに格納する方法(つまづきメモ付き)
2020-01-30
azblob://2022/11/11/eyecatch/2020-01-30-terraform-tfstate-to-azure-storage-000.png

はじめに

最近ずっとTerraformと格闘している佐藤です。
システム構成も、Terraformもまだまだ勉強不足で躓く毎日ですが、ポケモン好きなボスに教えてもらったことを忘れないようにメモしていこうと思います。
そもそも「Terraformの状態、tfstateってなんだよ!」ってところから、なんでこの手法でやらなきゃいけないのかも含めたAzure Storageに格納する設定の方法までこの記事では紹介していきます。

Terraformの状態、tfstateってなんだ…?

この公式ページによると、tfstateはその名の通り「Terraformで記述したリソースの状態が記述されているファイル」です。
具体的には以下のものが記述されています。

  • Terraformで記述したリソースと実行してできたインスタンスのマッピング
  • リソースの依存関係などのメタデータ
  • リソースのattributeなどのキャッシュデータ

チームで作業する場合、このtfstateファイルを共有することで同じリモートオブジェクトの操作が可能になります。 デフォルトでは作業ディレクトリに保存されますが、これをGitで管理するのは面倒&忘れる可能性があります。
また、今回参照したこのAzure公式チュートリアルでは以下のようにローカルにtfstateを保存するデメリットを挙げていました。

ローカルの状態は、チーム環境または共同作業環境ではあまり実用的でない。
Terraform 状態に機密情報が含まれる可能性がある。
状態をローカルに格納すると、不注意で削除される可能性が高くなる。

また、Terraformはリモートストレージへの状態の永続化をサポートしているので、今回はAzure Storageに保存して共有する方法を紹介していきます。

実行環境と今回のフォルダ構成

今回の実行環境は以下です。

  • Terraform v0.12.1
  • provider.azurerm v1.28.0

また、次回説明しますが、今回はTerraform Modules を利用した以下のようなフォルダ構成にしました。
ちなみに後でも触れますが、リソースグループ名はdemoにしてあります。

├── README.md
├── .gitignore
├── environments
│   ├── demo
│   │   ├── main.tf
│   │   ├── variables.tf 
│   │   └── README.md
└── modules
    ├── app_service
    ……

Terraformの状態をAzure Storageに格納する方法

このAzure公式チュートリアルに従って操作したのですが、ここでは私のつまづきや気づきとともに手順を紹介していきます(最近ポケモンにハマっているのでポケモン風で)。
ちなみにですが、公式チュートリアルの手順がやりづらかったので、作業の追加+作業順序の変更をしています。

<つまづき1>

  • satosatoのおもいつき:「Terraformの状態をAzure Storageを別ディレクトリにtfファイル作って作成したらコマンドでぽちぽちしなくて楽じゃないですかね?」
  • ポケモン好きなボスには効果がないようだ
  • ポケモン好きなボスのマジレス:「そのAzure Storageのtfstateはどこに保存されるの…?」
  • satosatoには効果はばつぐんだ

ということで、おそらくAzure Storageのtfstateも同じtfstateに保存するためにコマンドベースの手順になっているんだと思います(本当の理由知っている方いらっしゃったら教えてください)。

1. Azure CLI でログイン

PowerShell で以下を実行します。

az login

実行すると、ブラウザが立ち上がってログインを促されます。
ログインすると、色々出力されてから再びコマンド入力できるようになるのですが、そのいろいろ出力される中に以下のようなサブスクリプションの情報もあるので、そのnameをメモしておきます。

{
    "cloudName": "AzureCloud",
    "id": "hogehoge",
    "isDefault": hoge,
    "name": "$subscription_name",
    "state": "hogehoge",
    "tenantId": "hogehoge",
    "user": {
      "name": "hogehoge",
      "type": "hogehoge"
    }
  }

2. サブスクリプションの切り替え

PowerShell で以下を実行します。

az account set --subscription $subscription_name

3. tfstate 用ストレージを作成

PowerShell で以下を一行ずつ実行します。
ちなみにbashとかの環境が整っていたら、このAzure公式チュートリアルにあるようにbashファイルにして実行したら楽です。

> $RESOURCE_GROUP_NAME="demoetc"

> $STORAGE_ACCOUNT_NAME="demoetc"

> $CONTAINER_NAME="tfstate"

# Create resource group
> az group create --name $RESOURCE_GROUP_NAME --location japaneast

# Create storage account
> az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob

# Get storage account key
> $ACCOUNT_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query [0].value -o tsv)

# Create blob container
> az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME --account-key $ACCOUNT_KEY

# 確認
> echo "storage_account_name: $STORAGE_ACCOUNT_NAME"
> echo "container_name: $CONTAINER_NAME"
> echo "access_key: $ACCOUNT_KEY"

<つまづき2>

  • satosatoのぎもん:「Terraformで定義するリソースグループと同じにしないのは何でですか?」
  • ポケモン好きなボスのかいとう:「Terraformの管理外だから」
  • satosatoは納得した

ということで、tfファイルで作ったものの状態がtfstateに保存される以上、そのtfstateを保持するストレージのリソースグループは別の方が望ましいのではないかなーと理解しました。
実際にチュートリアルでも別のリソースグループになっています。

4. ./environments/demo/main.tf に状態バックエンド構成の追加

以下のコードを./environments/demo/main.tfに追加します。
ちなみにstorage_account_nameは$STORAGE_ACCOUNT_NAMEで既に設定済みなので、同じ名前を入力します。

terraform {
  backend "azurerm" {
    storage_account_name = "demoetc"
    container_name       = "tfstate"
    key                  = "terraform.tfstate"
  }
}

<つまづき3>

  • satosatoのていあん:「storage_account_nameの値、Variablesにした方がいいのでは…?」
  • ポケモン好きなボスは納得した:「それはやってみたらいいと思う」
  • Terraform:「「「Error: Variables not allowed!!!!!!!!!!!!!!!」」」 ということで実際にやってみた結果以下のようなエラーがでました。
Error: Variables not allowed
  on main.tf line 11, in terraform:
  11:     storage_account_name = "${var.tstate_strage_account_name}"
Variables may not be used here.

ということで、このstorage_account_nameはVariables許可されていないので、Variablesにできないようです。

ちゃんとtfstateが保存されているか確認

ポータルから先ほど作ったdemoetcリソースグループを開くと、ストレージアカウントが作成されていることが確認できます。

クリックすると以下の画面になるので、コンテナーを選択します。

作成したtfstateコンテナを選択します。

.tfstateが保存されていることが確認できました。

おわりに

Terraformの状態をAzure Storageに格納する手順をまとめました。
色々ポケモン好きなボスにそもそもなんでこうなっているのかということも聞きつつできたので理解が深まった気がします。
もし、このブログを読んで、こうしたほうがいいよなどアドバイスありましたらよろしくお願いします。

<追伸>

リニューアルしたTech Blogを盛り上げてくださったTech Blog初代編集長、奥山奈々編集長が1月末で卒業となりました。
本当にありがとうございました。

私事ですが、奈々さんに追い付きたくて必死で書き続けたブログ記事もいつの間にか100を越したり、PVが1000を超えるものがでてきたり、少しずつですが、成長してきました。
ここまでブログ記事を書けたのはすべて奈々さんのおかげです。
約10か月間、様々なサポート、本当にありがとうございました。
これからも、私は奈々さんを目指して少しずつ積み重ねていきます。
また会えた時は牡蠣食べに行きましょうね!!!!!!!!!