
Pulumi の入門ワークショップ「Get started with Pulumi and AWS」を AWS アカウントを使わずに LocalStack で試してみて,最終的に問題なくできた❗️取り組んだ内容をまとめておく.できる限りワークショップの手順と合わせながら紹介しようと思う.
セットアップ
Install Pulumi セクションでセットアップをするときに追加で LocalStack CLI(localstack コマンド)と LocalStack AWS CLI(awslocal コマンド)と LocalStack Pulumi CLI(pulumilocal コマンド)もセットアップしておく.pulumilocal コマンドは Pulumi CLI(pulumi コマンド)のラッパーで LocalStack に対してデプロイするための設定を生成してくれる👌
$ localstack --version LocalStack CLI 4.7.0 $ aws --version aws-cli/2.28.25 Python/3.13.7 Darwin/24.6.0 exe/x86_64 $ awslocal --version aws-cli/2.28.25 Python/3.13.7 Darwin/24.6.0 exe/x86_64 $ pulumi version v3.192.0 $ pulumilocal version v3.192.0
ちなみに pulumilocal コマンドでは CONFIG_STRATEGY という環境変数で設定ファイルのマージ戦略を指定できる.値としては overwrite と override と separation から選択できる.個人的には通常の設定を汚さずに使える override もしくは separation を使いたかったけどエラーが出てしまってうまく使えなかった(実装が間違っていそうな予感がする😇).今回は overwrite にしておく.
$ export CONFIG_STRATEGY=overwrite
なお Configure access to AWS セクションで aws sts get-caller-identity コマンドを実行していて,awslocal コマンドを使うと以下のようになる.
$ awslocal sts get-caller-identity { "UserId": "AKIAIOSFODNN7EXAMPLE", "Account": "000000000000", "Arn": "arn:aws:iam::000000000000:root" }
バックエンド設定
Terraform と同じように Pulumi にもインフラ側の状態を管理するための「ステートバックエンド」という仕組みがある.デフォルトでは Pulumi Cloud を使うことになっていて,LocalStack と統合する場合も問題なく使えるけど,今回はローカル環境に統一するために DIY バックエンド(ローカルバックエンド)を使う.
よって,Create a new project セクションでプロジェクトを初期化する前に,以下のように環境変数 PULUMI_CONFIG_PASSPHRASE と PULUMI_BACKEND_URL をエクスポートしておく.
$ export PULUMI_CONFIG_PASSPHRASE=mypassphrase $ export PULUMI_BACKEND_URL=file://$(pwd)
ステートバックエンドに関してはドキュメントに詳しくまとまっている.Terraform でお馴染みの「Amazon S3 バックエンド」もある👀
pulumilocal new
そして Create a new project セクションでプロジェクトを初期化する.ここで pulumilocal コマンドを使う💡対話形式で設定を進めると Pulumi のデフォルト構成で初期化される.今回はローカルバックエンドを使うため .pulumi ディレクトリも存在する👌
$ pulumilocal new aws-typescript $ tree -L 1 -a . . ├── .git ├── .gitignore ├── .pulumi ├── index.ts ├── node_modules ├── package-lock.json ├── package.json ├── Pulumi.dev.yaml ├── Pulumi.yaml ├── README.md └── tsconfig.json 4 directories, 8 files $ tree -L 3 .pulumi .pulumi ├── locks │ └── organization │ └── pulumi-start-aws-localstack ├── meta.yaml ├── meta.yaml.attrs └── stacks └── pulumi-start-aws-localstack ├── dev.json ├── dev.json.attrs ├── dev.json.bak └── dev.json.bak.attrs 6 directories, 6 files
pulumilocal up
Deploy to AWS セクションでデプロイするときにも pulumilocal コマンドを使う💡そして pulumilocal up コマンドを実行すると Amazon S3 バケットをデプロイできた.また .pulumi/stacks/pulumi-start-aws-localstack/dev.json ファイルにはステートが書き込まれていた.
$ pulumilocal up
Stack config file ./Pulumi.dev.yaml already exists. File will be overwritten.
Only 'yes' will be accepted to approve.
Enter a value: yes
Updating this Stack with LocalStack config
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack pulumi-start-aws-localstack-dev create
+ └─ aws:s3:Bucket my-bucket create
Outputs:
bucketName: [unknown]
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack pulumi-start-aws-localstack-dev created (6s)
+ └─ aws:s3:Bucket my-bucket created (0.09s)
Outputs:
bucketName: "my-bucket-d00e87d"
Resources:
+ 2 created
Duration: 8s
LocalStack Resource Browser で Amazon S3 バケットを確認できる❗️

pulumilocal up(2回目)
Make an update セクションでは Amazon S3 静的ウェブサイトホスティングを設定してスタックをアップデートする.ワークショップの手順に従ってコードを書き換えつつ,もう一度 pulumilocal up コマンドを実行する.
$ pulumilocal up
Stack config file ./Pulumi.dev.yaml already exists. File will be overwritten.
Only 'yes' will be accepted to approve.
Enter a value: yes
Updating this Stack with LocalStack config
Previewing update (dev):
Type Name Plan
pulumi:pulumi:Stack pulumi-start-aws-localstack-dev
+ ├─ aws:s3:BucketPublicAccessBlock public-access-block create
+ ├─ aws:s3:BucketOwnershipControls ownership-controls create
+ ├─ aws:s3:BucketObject index.html create
+ └─ aws:s3:BucketWebsiteConfiguration website create
Outputs:
+ url : [unknown]
Resources:
+ 4 to create
2 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status
pulumi:pulumi:Stack pulumi-start-aws-localstack-dev
+ ├─ aws:s3:BucketWebsiteConfiguration website created (0.05s)
+ ├─ aws:s3:BucketOwnershipControls ownership-controls created (0.04s)
+ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.04s)
+ └─ aws:s3:BucketObject index.html created (0.01s)
Outputs:
bucketName: "my-bucket-d00e87d"
+ url : "http://my-bucket-d00e87d.s3-website-us-east-1.amazonaws.com"
Resources:
+ 4 created
2 unchanged
Duration: 7s
ちなみに LocalStack Resource Browser では Amazon S3 静的ウェブサイトホスティングの設定は確認できないため,AWS CLI で確認して問題なさそうだった.
$ awslocal s3api get-bucket-website --bucket my-bucket-d00e87d { "IndexDocument": { "Suffix": "index.html" } }
さらにワークショップの手順にあるコマンドだと AWS アカウント上にある Amazon S3 静的ウェブサイトホスティングの URL になってしまうため,今回は LocalStack 上にある Amazon S3 静的ウェブサイトホスティングの URL にするため少しコマンドを修正した.
$ pulumi stack output url http://my-bucket-d00e87d.s3-website-us-east-1.amazonaws.com $ echo http://$(pulumi stack output bucketName).s3-website.us-east-1.localhost.localstack.cloud:4566 http://my-bucket-d00e87d.s3-website.us-east-1.localhost.localstack.cloud:4566 $ curl http://my-bucket-d00e87d.s3-website.us-east-1.localhost.localstack.cloud:4566 <html> <body> <h1>Hello, Pulumi!</h1> </body> </html>
LocalStack も Amazon S3 静的ウェブサイトホスティングをサポートしているため LocalStack 上にある Amazon S3 静的ウェブサイトホスティングで index.html を表示することができた👌

pulumilocal up(3回目)
Create a component ではデプロイした構成を Pulumi のコンポーネントとしてリファクタリングして再デプロイするという内容になっている.ワークショップの手順に従ってコードを書き換えつつ,pulumilocal up コマンドを実行すれば OK👌Amazon S3 バケットは作り直される前提の手順になっていてそこは問題なし.
$ pulumilocal up
Stack config file ./Pulumi.dev.yaml already exists. File will be overwritten.
Only 'yes' will be accepted to approve.
Enter a value: yes
Updating this Stack with LocalStack config
Previewing update (dev):
Type Name Plan
pulumi:pulumi:Stack pulumi-start-aws-localstack-dev
+ ├─ quickstart:index:AwsS3Website my-website create
+ │ ├─ aws:s3:Bucket my-bucket create
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls create
+ │ ├─ aws:s3:BucketWebsiteConfiguration website create
+ │ ├─ aws:s3:BucketObject index.html create
+ │ └─ aws:s3:BucketPublicAccessBlock public-access-block create
- ├─ aws:s3:BucketObject index.html delete
- ├─ aws:s3:BucketOwnershipControls ownership-controls delete
- ├─ aws:s3:BucketPublicAccessBlock public-access-block delete
- ├─ aws:s3:BucketWebsiteConfiguration website delete
- └─ aws:s3:Bucket my-bucket delete
Outputs:
- bucketName: "my-bucket-d00e87d"
Resources:
+ 6 to create
- 5 to delete
11 changes. 1 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status
pulumi:pulumi:Stack pulumi-start-aws-localstack-dev
+ ├─ quickstart:index:AwsS3Website my-website created (5s)
+ │ ├─ aws:s3:Bucket my-bucket created (0.07s)
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls created (0.01s)
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.01s)
+ │ ├─ aws:s3:BucketWebsiteConfiguration website created (0.02s)
+ │ └─ aws:s3:BucketObject index.html created (0.01s)
- ├─ aws:s3:BucketObject index.html deleted (0.01s)
- ├─ aws:s3:BucketOwnershipControls ownership-controls deleted (0.01s)
- ├─ aws:s3:BucketWebsiteConfiguration website deleted (0.01s)
- ├─ aws:s3:BucketPublicAccessBlock public-access-block deleted (0.01s)
- └─ aws:s3:Bucket my-bucket deleted (0.01s)
Outputs:
- bucketName: "my-bucket-d00e87d"
~ url : "http://my-bucket-d00e87d.s3-website-us-east-1.amazonaws.com" => "http://my-bucket-d55080e.s3-website-us-east-1.amazonaws.com"
Resources:
+ 6 created
- 5 deleted
11 changes. 1 unchanged
Duration: 7s
LocalStack Resource Browser で作り直された Amazon S3 バケットも確認できて成功❗️

pulumilocal destroy と pulumilocal stack rm
最後に Cleanup & destroy the stack セクションでお掃除をしておく.
$ pulumilocal destroy
$ pulumilocal stack rm
まとめ
LocalStack を使えば AWS アカウントを使わずに Pulumi の入門ワークショップ「Get started with Pulumi and AWS」を試せた❗️引き続きどんどん試していくぞ〜