TT Lab
はじめる
学ぶ 学習パス コース

Terraform実戦

ワークスペースは環境分離のための道具ではない

TT Labで続きを見る

一言でいうと

ワークスペースは、1つのバックエンド・1つの認証情報の中で、状態だけを複数持つ仕組みです。環境が分かれる地点が権限なら、ワークスペースでは分けられません。

なぜ必要なのか、そしてなぜ誤解されるのか

環境を分ける作業は、ほとんどいつも、こうして始まります。devで作ったスタックをprodにも載せる必要があるのに、コードを丸ごとコピーしたくありません。このとき、workspace new prodは、完璧な答えのように見えます。コードは1つで、コマンド1行で乗り換えられ、プロバイダーのキャッシュも再取得しません。

問題は、このツールが解決するものが何かにあります。ワークスペースが分けてくれるのは、状態(state)だけです。バックエンドはそのまま1つで、そのバックエンドを開く認証情報も1つで、コードも1つです。そのため、devを触る権限だけを渡すべき人にワークスペースを使わせると、その人は、prodの状態が入っている同じストレージを開く鍵を、すでに握っていることになります。

公式ドキュメントも、同じことを言っています。OpenTofuのWorkspacesのドキュメントは、ワークスペースが「システムの分解や、別の認証情報とアクセス制御が必要なデプロイには適切ではない」と書いており、より大きなシステムでは、アーキテクチャの境界に合わせて、設定そのものを分けなさいと勧めています。つまり、ワークスペースは環境を分離するツールではなく、同じ環境の一時的なコピーを作るツールです。ドキュメントが挙げる代表的な例も、機能ブランチ用の一時的な複製です。

どう動くのか

localバックエンドで実際に何が起きるかは、ファイルの配置がすべて語っています。

tfa-ws/
├── terraform.tfstate                      ← default workspace
├── terraform.tfstate.d/
│   ├── dev/terraform.tfstate
│   └── prod/terraform.tfstate
└── .terraform/
    ├── providers/                          ← 캐시는 한 벌뿐이다
    └── environment                         ← 지금 선택된 이름이 여기에만 있다

読み取るべきことが3つあります。

ディレクトリ分離は、まったく反対の性質を持ちます。環境ごとにディレクトリが別なので、状態も別、initも別、プロバイダーのキャッシュも別です。ドキュメントが認めているとおり、ディスクと帯域をより多く使い、設定の更新も、それぞれ行う必要があります。その代わり、バックエンド設定を環境ごとに違えられ、リポジトリの権限で、「prodディレクトリは、誰が変更できるのか」を、コードレビューのルールにできます。

現場での姿

最もよくある事故は、文法ではなく選択です。ターミナルには、prodとどこにも書かれておらず、プロンプトにも出ず、コマンドにも入りません。昨日prodを見ていて、そのまま退勤したディレクトリで、今朝destroyを打てば、それで終わりです。ラボのステップ5で、この事故をわざと起こします。

2つ目は、権限がすでに分かれているのに、ワークスペースで分けたチームです。監査で「dev担当者がprodの状態を読めるか」を聞かれたら、答えはいつも「はい」です。バックエンドが1つだからです。この指摘は、コードを直して防げるものではなく、ディレクトリ(または別の設定)に移す移行作業になります。

3つ目は、ワークスペース名がコードの条件式に漏れ出すことです。terraform.workspace == "prod" ? ... : ...が、3、4か所を超えると、そのコードはすでに、環境ごとに異なる2つのコードです。そのときが、ディレクトリで分ける時点です。

防ぐ方法は単純です。書き込みコマンドの前に、ガードの1行を立てて、期待したワークスペースでなければ止まるようにします。CIでは、環境名をパイプラインの変数として受け取り、同じ検査を行います。人の記憶の代わりに、終了コードが判断するようにするのです。終了コードを2つではなく3つに分けることも、実務では価値があります。「期待と違う」と「スクリプトの呼び出し方が間違っている」をパイプラインが区別できてこそ、リトライするか人を呼ぶかを決められるからです。

まとめると、選択の基準は次のようになります。状態だけを分ければよいのか、それとも、認証情報・バックエンド・レビュー権限まで分ける必要があるのか。前者ならワークスペースが最も安い答えで、後者ならワークスペースは答えではありません。両者を混ぜて使うこともよくあります。prodと非本番をディレクトリで大きく分け、非本番の中で、開発者ごとの一時的なコピーをワークスペースで持つ、という形です。

次のラボですること

/root/tfa-wsでワークスペースを3つ作り、状態ファイルがどこにできるかを自分で開いて確認し、環境ごとに違う値をマップで渡し、prodを選択したままdestroyを回して事故を起こしたあと、復旧します。続いて、同じ結果をディレクトリ分離で作り直し、状態ファイルの数とプロバイダーのキャッシュの数を数えて、2つの方式を表で比べます。