tech.guitarrapc.cóm

Technical updates

Pulumi で今のスタックを異なるプロジェクトのスタックに移動させる

Pulumi はステートを スタック (Stack) に保持しています。 スタックはリネームや別の Organization への移動はサポートされていますが、自分のOrganization の別プロジェクトへの移動はサポートされていません。

しかしスタックを後から整理したいときには、このスタックを別のプロジェクトに移動させたいというのはやりたくなるでしょう。 公式にはまとまっていないので、いずれサポートされるまでのワークアラウンドを見てみましょう。

tl;dr;

  • Pulumi CLI で pulumi importpulumi export を使ってステートを取り込みなおせばステートを別プロジェクトのスタックに移動できる
  • スタックの移動前にスタック名を移動先で使いたい名前にリネームしましょう
  • 今あるプロジェクトにスタックを追加するのが忘れがち

主にこの流れですが、別プロジェクト名なのでステートの編集が必要です。

github.com

何をしたいのか

スタック移動したい例を考えてみましょう。 下の図は、FooFoo-GuardDuty の2プロジェクトがあり、それぞれ master というスタックがある状態です。

Foo
  Master
Foo-GuardDuty
  Master

プロジェクト名を見てわかる通り、 Foo-GuardDuty は AWS GuardDuty 専用の処理なので Foo とは別に作りたかったようですが、プロジェクトで分けてしまいました。このやり方だと、同じプロジェクトなのにその関係が疑問付きになりますし、Pulumi UI 上でも縦に伸びて見にくなります。

そこで下の図のように、Foo-Dev プロジェクトの中に master と guardduty というスタックを持つ構成に変えましょう。

Foo
  Master
  Guardduty

これなら関連のあるプロジェクト Foo でまとめつつ、その構成の違いはスタックで示すことができます。

変更の流れ

次の流れでやっていきます。

  1. 移動先のスタックを既存プロジェクトに作成
  2. 移動元のスタック名を移動先のスタック名にリネーム
  3. 移動元のスタックをエキスポート
  4. エキスポートした json を編集
  5. 移動先のスタックに編集したjsonを インポート
  6. 移動先のスタックでシークレットやコンフィグをセットしなおし
  7. 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 をいじる力業で何とかなります。 とはいえ、ミスをすると怖いので、やるときは実験プロジェクトなどで要領を把握してからやるといいでしょう。