こんにちは!クラウドインフラの世界へようこそ。
日々のインフラ開発で、「ちょっとしたコードの変更を確認したいだけなのに、AWSへのデプロイに数分待たされる」「うっかり本番環境の近くを触ってしまってヒヤッとした」「気づいたらAWSの無料枠を超えて請求が発生していた」……そんな切ない経験はありませんか?
今回は、そんなインフラエンジニアの悩みを一刀両断する「PulumiとLocalStackを組み合わせた、クラウド費用ゼロのローカルIaCテスト環境」の作り方を、優しく、そして徹底的に深掘りして解説していきます。
これをマスターすれば、あなたの手元(ローカルPC)が完全なAWS環境に早変わり。爆速のフィードバックループを手に入れ、日々の開発体験を劇的に快適にできますよ。ぜひ最後までついてきてくださいね!
—
1. LocalStackとPulumiの統合メリット:なぜこの組み合わせが最強なのか?
まずは、今回使う2つの強力なツールの役割と、なぜそれらを組み合わせるべきなのかを整理しておきましょう。
ツールの役割
- Pulumi(プルミ):
YAMLやJSONではなく、TypeScript、Python、Goといった使い慣れたプログラミング言語を使ってインフラを定義・構築できる(IaC)次世代のツールです。TerraformのHCLにフラストレーションを感じているなら、プログラミングの制御構文(ループや条件分岐)がそのまま使えるPulumiの快適さに驚くはずです。
- LocalStack(ローカルスタック):
自分のPC(Docker上)にAWSの本物そっくりなモック環境を再現できるツールです。S3、Lambda、DynamoDB、SQSなど、主要なAWSサービスをローカルで完全にエミュレートしてくれます。
組み合わせるメリット:圧倒的な「速度」と「安心感」
この2つを掛け合わせることで、以下のような圧倒的なメリットが生まれます。
1. 完全オフライン&クラウド費用 0円
AWSアカウントすら不要です。スターバックスの片隅で、インターネットに繋がっていなくても、無限にS3バケットを作っては消し、テストを繰り返せます。当然、AWSからの請求書に怯える必要もありません。
2. 数秒で終わる爆速フィードバックループ
クラウド上のAWSリソースのプロビジョニングを待つ必要はもうありません。手元のDockerコンテナ内で完結するため、`pulumi up` の実行が驚異的なスピードで完了します。
3. CI/CDパイプラインへのシームレスな組込み
GitHub ActionsなどのCI環境でも、LocalStackをコンテナとして立ち上げれば、クラウド認証情報を汚すことなく、精度の高いインフラテストを自動化できます。
—
2. 環境構築と基礎セットアップ
それでは、実際に手を動かしていきましょう!
今回は、最も汎用性が高く書きやすい TypeScript を用いて解説を進めます。
前提条件
以下のツールがローカルPCにインストールされていることを確認してください。
- Node.js (v18以上推奨)
- Pulumi CLI
- Docker & Docker Compose
Step 1: LocalStackの起動
まずはLocalStackを立ち上げます。プロジェクトルートに `docker-compose.yml` を作成しましょう。
version: “3.8”
services:
localstack:
container_name: localstack_demo
image: localstack/localstack:latest
ports:
- “4566:4566” # LocalStackのメインエントリーポイント(全AWSサービスがここに集約されます)
environment:
- DEBUG=0
volumes:
- “${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack”
- “/var/run/docker.sock:/var/run/docker.sock”
ターミナルで以下のコマンドを実行し、LocalStackをバックグラウンドで起動します。
docker compose up -d
`http://localhost:4566/_localstack/health` にアクセスして、各サービスが “running” になっているのを確認できたら準備完了です!
Step 2: Pulumiプロジェクトの初期化
適当な作業用ディレクトリを作成し、Pulumiプロジェクトをセットアップします。
mkdir pulumi-localstack-demo
cd pulumi-localstack-demo
pulumi new aws-typescript –dir . –name pulumi-localstack –stack dev –yes
必要な依存関係をインストールしたら、いよいよマジックの核心部分に入ります。
—
3. AWSプロバイダのエンドポイントをローカルに向ける魔法のコード
通常、PulumiのAWSプロバイダは「本物のAWS(us-east-1やap-northeast-1など)」に向かってリクエストを投げます。しかし、これをLocalStack(`http://localhost:4566`)に向かわせるためには、プロバイダの設定(カスタムエンドポイント)を明示的に記述する必要があります。
ここが本記事の最も重要なポイントです。`index.ts` を以下のように書き換えてみてください。
import as pulumi from “@pulumi/pulumi”;
import as aws from “@pulumi/aws”;
// 1. LocalStack用のカスタムエンドポイント設定
// すべてのAWSサービスリクエストを、ローカルのポート4566にルーティングします
const localstackEndpoint = “http://localhost:4566”;
const localProvider = new aws.Provider(“local-provider”, {
region: “us-east-1”,
// 認証情報のダミー化(LocalStackは認証を厳密にチェックしないため適当な値でOK)
accessKey: “mock_access_key”,
secretKey: “mock_secret_key”,
skipCredentialsValidation: true,
skipRequestingAccountId: true,
skipMetadataApiCheck: true,
s3UsePathStyle: true, // S3のエンドポイントパス解決に必要不可欠な設定
// エンドポイントの向き先をすべてLocalStackに強制する
endpoints: [{
apigateway: localstackEndpoint,
cloudformation: localstackEndpoint,
cloudwatch: localstackEndpoint,
dynamodb: localstackEndpoint,
ec2: localstackEndpoint,
es: localstackEndpoint,
iam: localstackEndpoint,
kinesis: localstackEndpoint,
lambda: localstackEndpoint,
route53: localstackEndpoint,
s3: localstackEndpoint,
secretsmanager: localstackEndpoint,
sns: localstackEndpoint,
sqs: localstackEndpoint,
ssm: localstackEndpoint,
sts: localstackEndpoint,
}],
});
// 2. HelloWorld的リソースの定義:S3バケットの作成
// 先ほど定義した `localProvider` を明示的に指定するのがポイントです!
const bucket = new aws.s3.Bucket(“my-local-bucket”, {
bucket: “my-first-localstack-bucket”,
}, { provider: localProvider });
// 3. 出力値(Outputs)の定義
export const bucketName = bucket.id;
export const bucketEndpoint = pulumi.interpolate`http://s3.localhost.localstack.cloud:4566/${bucket.bucket}`;
—
4. 実行と動作確認:いざ、ローカルデプロイ!
コードの準備ができたら、実際にデプロイしてみましょう。
ターミナルで以下のコマンドを実行します。
pulumi up
画面にプレビューが表示され、「実行しますか?」と聞かれるので `yes` を選択します。
数秒後……どうでしょう? 驚くほどのスピードで `pulumi up` が成功したはずです!
本当にローカルで作られたか確認してみよう
AWS CLIを使って、今のリソースがLocalStack上にちゃんと存在するか確認してみます。LocalStack向けの専用ラッパーコマンド `awslocal` を使うと非常に便利です(あるいは `–endpoint-url=http://localhost:4566` を付与します)。
AWS CLI経由でローカルのS3バケット一覧を取得
aws –endpoint-url=http://localhost:4566 s3 ls
実行結果に `my-first-localstack-bucket` が表示されていれば大成功です!おめでとうございます!あなたは今、完全オフライン環境でIaCのプロビジョニングを完遂しました。
—
5. 現場で役立つ!さらに一歩進んだTips
この環境を手に入れたあなたへ、現場のSREとしてさらに役立つ知見をいくつかシェアしておきます。
- スタックの切り替え(Local / Production)
Pulumiのコンフィグレーション機能や環境変数(`pulumi.Config`)をうまく使うことで、同じコードベースのまま「開発時はLocalStack、本番時は本物のAWS」という切り替えをスマートに行う設計に昇華させることができます。
- テストコードとの統合
Pulumiには独自のユニットテスト・統合テストのフレームワーク(`pulumi.test`)があります。LocalStackと組み合わせることで、「インフラコードを書き換える ⇒ ローカルに適用してスモークテストを行う」という一連の流れを、完全に自動化されたCIパイプライン(GitHub Actionsなど)上で数秒単位で回せるようになります。
—
おわりに
いかがでしたでしょうか?
PulumiとLocalStackを組み合わせることで、クラウドの制約から解放され、まるでただのアプリケーションコードを書いているかのような軽快さでインフラを構築・テストできるようになります。
「インフラの変更テストに時間がかかる、お金がかかる」というこれまでの常識は、今日で終わりです。
ぜひこの環境をご自身のローカルでも構築し、日々の開発・検証を圧倒的なスピードへと加速させてくださいね。
あなたのインフラ開発ライフが、より創造的で楽しいものになりますように!