nazolabo

Webエンジニアのnazoさんのブログです。お仕事募集中です。 https://nazo.dev/

TerraformのWorkspaceはstaging/productionの切り替えに使うべきではない

Workspaceって何だっけ?

簡単に言うと「同一のtfファイル群を別のtfstateとして扱う、それを切り替える」機能です。

なんでだめなの?

公式がそう言っているからです。

In particular, organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages (e.g. staging vs. production) or different internal teams. In this case, the backend used for each deployment often belongs to that deployment, with different credentials and access controls. Named workspaces are not a suitable isolation mechanism for this scenario. State: Workspaces - Terraform by HashiCorp

どういうこと?

公式の言い分としては、「全く同じ環境のコピーを作るならいいけど、そうじゃない場合(staging/productionのような)は資格情報とか認証情報とか合わないから使えないよ」ということです。これは例えばstagingとproductionで別のAWSアカウントを使用している場合に該当すると思います。この場合は向いていないのが直感的に理解できるかと思います。

また、公式では「その場合は再利用可能なモジュールを使うべき」としています。つまり、部分的にモジュール化したものを組み合わせて別の構成として取り扱うべきとしています。これであればどのような構成でも部分的にモジュールを組み合わせて使う形になるので、自由な構成を組むことが可能です。

現実では小さい環境であれば片方の環境からコピペして必要なところだけ書き換えて新しい環境を作る、という感じでも最初のうちは困らないことが多いと思いますが、環境が増えそうであれば早めにモジュール化していくのが良いでしょう。

公式が言ってたらダメなの?使えるから使っても良くない?

以下は私の独自見解になります。

大前提として「stagingとproductionのtfstateは分けるべき」と考えています。これはapply時の影響範囲を狭めることができるためです。

その上で、私としては「そんなにstagingとproductionって同一環境ではないのでは?」というような理由で、Workspaceをその用途に使うべきではないのではと思っております。

The Twelve-Factor Appでは、外部環境は本番環境と開発環境のギャップがないようにすべきとされています。これは「開発環境ではローカルメモリに保存するけど本番はMemcached」のような、プロトコルレベルで違うようなものを使うと、それによるアダプターの実装の差異による思わぬ事故が発生する可能性があるためです。

一方で、外部リソースはアタッチされたリソースとして扱うというのもあり、そこでは「リソースを簡単に切り替えることができるようにしておく」とされています。

つまり、「アプリケーションレベルでは常に同一の対象に対してアクセスしているように振る舞うが、その先の通信対象が何なのかはアプリケーションが関与しない」ということです。これは問題が発生したときに責任がどちらにあるのか明確になり、性能限界などでの差し替え時にも容易に差し替えることができるためスケールしやすいアプリケーションになります。

これを踏まえた上で、一般的によくあるケースとして「本番ではメールを送信したいがstagingではメールを送りたくない」といったケースがあります。この場合、本番では普通のメールサーバーを構築します(外部のサービスを使うかもしれません)が、stagingでは「送信したメールを全て吸収してWeb上で表示してくれるサービスに送る」というようなことをすることがあります。具体的にはMailHogMailtrap.ioといったようなものです。私は前者を使うことが多いので、前者用のインスタンスをstagingのみで組み込んでおくということをします。

同様に、AWSでは「stagingではシンプルなRDSを使うが、本番ではAuroraクラスタを組む」というようなケースもよくあります。これも大幅に設定が変わる内容になります。Auroraクラスタまでいかなくても、DBのパラメーターを細かく変えることはあると思いますので、それをWorkspaceでどうにかするのはなかなか大変ではないかと思います。

上記の観点から、そもそもWorkspaceでstaging/productionのような「似てるようで用途が違うもの」の切り替えには向いていないのではないかと思います。が、これらを理解した上で「それでもWorkspaceで切り替えるのがベストだ!」となるのであれば、それでもいいかもしれません。

それじゃWorkspaceって何のためにあるの?

公式では以下のようになっています。

A common use for multiple workspaces is to create a parallel, distinct copy of a set of infrastructure in order to test a set of changes before modifying the main production infrastructure. For example, a developer working on a complex set of infrastructure changes might create a new temporary workspace in order to freely experiment with changes without affecting the default workspace. State: Workspaces - Terraform by HashiCorp

簡単に言うと、「インフラの変更のテスト用にもう1つ作っておいてそこで試すため」とあります。Terraformは実際にapplyする時の挙動は当然apply先のクラウドサービスに依存していますので、applyするまでどうなるかわからないということは多々あります。そのような場合を試すのにはベストなケースだと思います。

同様に、「本番環境と全く同じものを作って、そこでないと発生しないようなバグのテストをする」というようなケースにも良いのではないかと思います。

どちらにしても、「Workspaceを切り替えて複数環境を作れるようにする(しておく)」というのは設計上欠かせない要素になります。必要な設定を切り出しておいて、いつでもWorkspaceで切り替えれる状態を作っておくようにしましょう。

まとめ

  • 公式がそう言っているのでなるべく従いましょう。
  • stagingとproductionってそこまで同一環境ではないので、公式が言ってなくても向いていないのではないかと思います。
  • Workspace機能自体は常に使える準備をしておきましょう。