kakakakakku blog

Weekly Tech Blog: Keep on Learning!

AWS アカウント不要!LocalStack x Pulumi で入門ワークショップ「Get started with Pulumi and AWS」を試そう

Pulumi の入門ワークショップ「Get started with Pulumi and AWS」を AWS アカウントを使わずに LocalStack で試してみて,最終的に問題なくできた❗️取り組んだ内容をまとめておく.できる限りワークショップの手順と合わせながら紹介しようと思う.

www.pulumi.com

セットアップ

Install Pulumi セクションでセットアップをするときに追加で LocalStack CLI(localstack コマンド)LocalStack AWS CLI(awslocal コマンド)LocalStack Pulumi CLI(pulumilocal コマンド)もセットアップしておく.pulumilocal コマンドは Pulumi CLI(pulumi コマンド)のラッパーで LocalStack に対してデプロイするための設定を生成してくれる👌

github.com

docs.localstack.cloud

$ 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 という環境変数で設定ファイルのマージ戦略を指定できる.値としては overwriteoverrideseparation から選択できる.個人的には通常の設定を汚さずに使える 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_PASSPHRASEPULUMI_BACKEND_URL をエクスポートしておく.

$ export PULUMI_CONFIG_PASSPHRASE=mypassphrase
$ export PULUMI_BACKEND_URL=file://$(pwd)

ステートバックエンドに関してはドキュメントに詳しくまとまっている.Terraform でお馴染みの「Amazon S3 バックエンド」もある👀

www.pulumi.com

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」を試せた❗️引き続きどんどん試していくぞ〜