Pulumi はステートを スタック (Stack) に保持しています。 スタックはリネームや別の Organization への移動はサポートされていますが、自分のOrganization の別プロジェクトへの移動はサポートされていません。
しかしスタックを後から整理したいときには、このスタックを別のプロジェクトに移動させたいというのはやりたくなるでしょう。 公式にはまとまっていないので、いずれサポートされるまでのワークアラウンドを見てみましょう。
tl;dr;
- Pulumi CLI で
pulumi import
とpulumi export
を使ってステートを取り込みなおせばステートを別プロジェクトのスタックに移動できる - スタックの移動前にスタック名を移動先で使いたい名前にリネームしましょう
- 今あるプロジェクトにスタックを追加するのが忘れがち
主にこの流れですが、別プロジェクト名なのでステートの編集が必要です。
何をしたいのか
スタック移動したい例を考えてみましょう。
下の図は、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 をいじる力業で何とかなります。 とはいえ、ミスをすると怖いので、やるときは実験プロジェクトなどで要領を把握してからやるといいでしょう。