Pulumiはステートをスタック (Stack) に保持しています。 スタックはリネームや別のOrganizationへの移動はサポートされていますが、自分のOrganizationの別プロジェクトへの移動はサポートされていません。
しかしスタックを後から整理したいときには、このスタックを別のプロジェクトに移動させたいというのはやりたくなるでしょう。 公式にはまとまっていないので、いずれサポートされるまでのワークアラウンドを見てみましょう。
概要
- Pulumi CLIで
pulumi importとpulumi exportを使ってステートを取り込みなおせばステートを別プロジェクトのスタックに移動できる - スタックの移動前にスタック名を移動先で使いたい名前にリネームしましょう
- 今あるプロジェクトにスタックを追加するのが忘れがち
主にこの流れですが、別プロジェクト名なのでステートの編集が必要です。
https://github.com/pulumi/pulumi/issues/3389#issuecomment-826841537
何をしたいのか
スタック移動したい例を考えてみましょう。
下の図は、FooとFoo-GuardDutyの2プロジェクトがあり、それぞれmasterというスタックがある状態です。
Foo Master Foo-GuardDuty Master
プロジェクト名を見てわかる通り、 Foo-GuardDutyはAWS GuardDuty専用の処理なのでFooとは別に作りたかったようですが、プロジェクトで分けてしまいました。このやり方だと、同じプロジェクトなのにその関係が疑問付きになりますし、Pulumi UI上でも縦に伸びて見にくなります。
そこで下の図のように、Foo-Devプロジェクトの中にmasterとguarddutyというスタックを持つ構成に変えましょう。
Foo Master Guardduty
これなら関連のあるプロジェクトFooでまとめつつ、その構成の違いはスタックで示すことができます。
変更の流れ
次の流れでやっていきます。
- 移動先のスタックを既存プロジェクトに作成
- 移動元のスタック名を移動先のスタック名にリネーム
- 移動元のスタックをエキスポート
- エキスポートしたjsonを編集
- 移動先のスタックに編集したjsonをインポート
- 移動先のスタックでシークレットやコンフィグをセットしなおし
- pulumi refresh && pulumi preview && pulumi up
変更前のフォルダ構成
ちなみに変更前は次のようなフォルダ構成です。
$ tree . ├── Foo-GuardDuty.Master └── Foo.Master
変更後のフォルダ構成
変更後は次のようになります。
. ├── Foo.GuardDuty └── Foo.Master
移動先のスタックを既存プロジェクトに作成
すでにあるプロジェクトFooにスタックguarddutyを追加するには、pulumi initをプロジェクトとスタック名で初期化します。
今回スタックを置くフォルダ名を、Foo.GuardDutyとしましょう。
mkdir Foo.GuardDuty cat <<EOF > Foo.GuardDuty/Pulumi.yaml name: Foo runtime: dotnet description: AWS Foo account EOF cat <<EOF > Foo.GuardDuty/Pulumi.GuardDuty.yaml config: aws:region: ap-northeast-1 EOF
これで次のようなフォルダとファイルができたはずです。
$ tree
.
└── Foo.GuardDuty
├── Pulumi.GuardDuty.yaml
└── Pulumi.yaml
既存プロジェクトにスタックを作る準備ができたので、 pulumi cliでFooプロジェクトにguarddutyスタックを作ります。
pulumi stack init guardduty
これで既存のFooプロジェクトに空のスタックguarddutyが追加されます。
移動元のスタック名を移動先のスタック名にリネーム
続いて移動元のプロジェクトのスタック、Foo-GuardDuty/Masterのスタック名を移動先のスタック名GuardDutyに変えましょう。 pulumi cliスタック名がリネームできます。
cd Foo-GuardDuty.Master pulumi stack rename GuardDuty cd ..
スタックのエキスポート前にやっておくと、エキスポートしたスタックのjsonを編集する手間が減るのでオススメです。
移動元のスタックをエキスポート
pulumi cliでFoo-GuardDuty/GuardDutyのステートをエキスポートして、Foo.GuardDutyにコピーしておきましょう。
cd Foo-GuardDuty.Master pulumi stack export --file guardduty.stack.checkpoint.json cp guardduty.stack.checkpoint.json ../Foo.GuardDuty/. cd ../Foo.Guard
エキスポートした json を編集
jsonには、プロジェクト名とスタック名が書かれており、これが一致しないとインポートできません。 スタックのプロジェクト名が変わるので、jsonをsedやVS Codeなどで開いて一括置換しましょう。
置換は、::プロジェクト名::で行うと間違えた場所を置換する心配がありません。
- 検索文字列:
::Foo-GuardDuty:: - 置換文字列:
::Foo::
移動先のスタックに編集したjsonを インポート
移動先のスタックで置換したjsonをインポートします。
cd Foo.GuardDuty pulumi stack import --file guardduty.stack.checkpoint.json
正常に取り込めたはずです。
移動先のスタックでシークレットやコンフィグをセットしなおし
スタックをインポートで取り込んでも、pulumi configで設定していたコンフィグやシークレットは入りません。 適当にいい感じに設定しましょう。
pulumi config set foo bar
pulumi refresh && pulumi preview && pulumi up
Pulumiコードを元の環境から持ってきたら、新しいスタック環境でリソースとスタックの同期をとっていきましょう。 まずは実環境の状態をステートに取り込んでおきます。特に差分は出ないはず。
pulumi refresh
最後に実行して終わりです。
pulumi preview pulumi up
プロジェクト名が変わったので、最上位urnであるプロジェクト名だけ入れ替えが出ますが、個別のリソースステートに差分は出ず影響ありません。
終わったらエキスポートしたjsonを消したり、元のプロジェクトを消しましょう。 CIを組んであるなら、pulumiのプロジェクトパスを直したりすれば完璧ですね。
まとめ
pulumiはステートの扱いがかなり緩いので、比較的jsonをいじる力業で何とかなります。 とはいえ、ミスをすると怖いので、やるときは実験プロジェクトなどで要領を把握してからやるといいでしょう。