お困りごと
ここ最近 CDKTF(主に GCP を取り扱いたい)を始めたのですが、スタックの状態(tfstate)をローカルからリモートに保存するために Remote Backend を触り始めたところ、複数のスタックをデプロイ・更新する度に、古いスタックが消されるという状況に陥りました 🤔
この際、prefix
には、公式の Example を参考に terraform/state
を設定していました。
1class MyStack extends TerraformStack {
2 constructor(scope: Construct, name: string) {
3 super(scope, name);
4
5 new GcsBackend(this, {
6 bucket: "tf-state-prod",
7 prefix: "terraform/state", // <- ここ
8 });
9 }
10}
Cloud Storage に保存される tfstate ファイルを確認すると、別々のスタックをデプロイする度に、tfstate が丸々更新されて一番新しいスタックしか存在しない状態になっていました。
つまり、同じ prefix
だと、単一の tfstate ファイルで単一のスタックだけを保存・管理する挙動になっていました。
そこで、ローカルの tfstate ファイルの挙動に注目してみると、スタックごとに別々のファイルで保存されているので、リモート側でも同様に別々で保存する必要があることに気づきました。
公式では prefix オプションは次のように説明されています。
prefix - (Optional) GCS prefix inside the bucket. Named states for workspaces are stored in an object called <prefix>/<name>.tfstate.
prefix - (オプション) バケット内のGCSプレフィックス。ワークスペースの名前付きステートは、<prefix>/<name>.tfstate というオブジェクトに格納されます。
name
がどこから来たのかも気になるのですが(name
のオプションはない)、この name
を基準に別々の tfstate ファイルが生成されそうですが、実際の挙動では、prefix
が同じだと上書きされてしまうようです 🤔
私が使い方を大きく勘違いしている気もしますが...よく分かっていない 😅
対応策
サンプルのように GcsBackend
の prefix
にスタック ID を渡してユニークにして、スタックごとに tfstate を分離、別スタックの追加・更新の影響を受けないようにしました。
1import { Construct } from "constructs";
2import { TerraformStack, GcsBackend } from "cdktf";
3import { GoogleProvider } from "@cdktf/provider-google/lib/provider";
4
5export class ExampleStack extends TerraformStack {
6 constructor(scope: Construct, id: string) {
7 super(scope, id);
8
9 new GcsBackend(this, {
10 bucket: "example-bucket-name",
11 prefix: id, // <- ここをユニークな値にする!!!
12 });
13
14 new GoogleProvider(this, "GoogleProvider", {
15 project: "example-project-id",
16 region: "asia-northeast1",
17 });
18
19 // ...
20 }
21}
おわりに
TypeScript & CDK ライク で GCP インフラを書けるのは、最高です 👍