こんにちは!クラウドインフラの世界へようこそ。
日々、膨大なサーバーやコンテナ、サーバーレスの構築に追われていませんか?
「Terraformで書いたコードのプラン結果を待つ時間がもどかしい…」
「Lambdaのデプロイパッケージを作るために、わざわざシェルスクリプトでzipを固めてS3にアップロードして……って、何回同じボイラープレートを書けばいいんだ!」
そんな毎日のインフラ運用の苦痛を、鮮やかに、そして劇的に解決してくれる秘密兵器が Pulumi(プルミ) です。
今回は、初心者の方でも迷わず手を動かせるように、Pulumiの基礎からAWS Lambdaの高速デプロイ、そしてコールドスタート対策までを、優しく丁寧に紐解いていきます。これをマスターすれば、あなたのデプロイ作業は劇的に快適になりますよ。それでは、一緒に旅を始めましょう!
—
1. なぜ今、Pulumiなのか?(ツールの役割と本質)
私たちがインフラをコード化(IaC)する際、長年デファクトスタンダードだったのはHCL(HashiCorp Configuration Language)を使うTerraformでした。もちろんTerraformも素晴らしいツールです。しかし、複雑な条件分岐、ループ処理、そして「コードをビルドしてパッケージングする」というアプリケーション領域のロジックが絡むと、途端にHCLの記述は苦行に変わります。
Pulumiの最大の特徴は、「使い慣れたプログラミング言語(TypeScript、Python、Go、C#など)でインフラを定義できる」という点です。
インフラ定義も、アプリケーションコードも、同じ言語で、同じエコシステム(npmやpipなど)の中で完結する。つまり、Lambda関数のソースコードをビルド・圧縮してクラウドへデプロイする一連のパイプラインを、完全にプログラムの制御下に置くことができるのです。これが、インフラ自動化のゲームチェンジャーと呼ばれる理由です。
—
2. 10分で完了!Pulumiのインストールと基礎セットアップ
まずは、あなたの手元でPulumiを動かせる環境を作りましょう。今回は最もポピュラーな TypeScript を使って解説します。
ステップ1: ツールのインストール
macOSであればHomebrewで一撃です。WindowsやLinuxをお使いの方も、公式ドキュメントに沿って数分で導入できます。
Pulumi CLIのインストール
brew install pulumi
動作確認
pulumi version
ステップ2: AWS認証情報の準備
Pulumiは背後でAWS SDKを叩いています。普段お使いのAWS CLIの認証情報(`~/.aws/credentials` や環境変数)がそのまま利用できます。
aws configure
Access KeyやRegionが正しく設定されていることを確認してください
ステップ3: プロジェクトの初期化
適当な作業用ディレクトリを作り、プロジェクトを初期化しましょう。
mkdir pulumi-lambda-demo
cd pulumi-lambda-demo
pulumi new aws-typescript
途中でプロジェクト名(project name)、スタック名(stack name:今回は `dev` など)、AWSのリージョンを聞かれますので、基本はデフォルト(Enter連打)で進めて大丈夫です。
これだけで、ディレクトリ内に `index.ts`(インフラ定義のエントリーポイント)や `package.json` が生成されます。プロジェクトの骨組みは、もうあなたの手の中にあります。
—
3. 精度高い「Hello World」:TypeScriptでLambdaをデプロイする
生成された `index.ts` を開き、中身を書き換えてみましょう。
ここでは、TypeScriptで書かれたLambda関数を、Pulumiの力でビルド・パッケージングし、AWS上にデプロイします。
まずはLambdaのソースコードを置くディレクトリを作成します。
mkdir lambda
cat << 'EOF' > lambda/index.ts
import { APIGatewayProxyHandler } from ‘aws-lambda’;
export const handler: APIGatewayProxyHandler = async (event) => {
console.log(“Event: “, JSON.stringify(event, null, 2));
return {
statusCode: 200,
body: JSON.stringify({
message: “Hello from Pulumi & AWS Lambda!”,
timestamp: new Date().toISOString(),
}),
};
};
EOF
次に、プロジェクトのルートにある `index.ts` を編集し、このLambda関数をAWSにデプロイするコードを書きます。ここがPulumiの真骨頂です。
import as pulumi from “@pulumi/pulumi”;
import as aws from “@pulumi/aws”;
// 1. Lambda実行用のIAMロールを作成
const lambdaRole = new aws.iam.Role(“lambdaExecutionRole”, {
assumeRolePolicy: JSON.stringify({
Version: “2012-10-17”,
Statement: [{
Action: “sts:AssumeRole”,
Effect: “Allow”,
Principal: {
Service: “lambda.amazonaws.com”,
},
}],
}),
});
// 基本的なログ出力権限をアタッチ
const lambdaPolicyAttachment = new aws.iam.RolePolicyAttachment(“lambdaBasicExecution”, {
role: lambdaRole.name,
policyArn: “arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole”,
});
// 2. Pulumiの機能を使って、ローカルのTypeScriptコードを自動ビルド・ZIP化してLambdaにデプロイ
const lambdaFunction = new aws.lambda.Function(“helloLambda”, {
code: new pulumi.asset.AssetArchive({
// “index.js” にコンパイルされる前提で、アセットを指定
“.”: new pulumi.asset.FileAsset(“./lambda”),
}),
runtime: aws.lambda.Runtime.NodeJS18X,
handler: “index.handler”, // index.ts の export された handler関数を指定
role: lambdaRole.arn,
}, { dependsOn: [lambdaPolicyAttachment] });
// 3. デプロイ後にLambdaのエンドポイント(ARNなど)を出力
export const lambdaArn = lambdaFunction.arn;
デプロイを実行する!
さあ、魔法のコマンドを実行しましょう。
pulumi up
画面に「これから作成されるリソースのプラン」が表示されます。「Yes」を選ぶと、Pulumiが自動的にTypeScriptのトランスパイル、ZIPアーカイブの作成、そしてAWSへのアップロードまでを数秒で完了させてくれます。
完了すると、ターミナルに `lambdaArn` が表示されます。これで、あなたの最初のサーバーレス環境がコードによって完全自動構築されました!
—
4. 現場で役立つ極限の知見:高速デプロイとコールドスタート対策
「おめでとうございます、デプロイできましたね」で終わらないのが、私たちの目指すSRE・インフラエンジニアの世界です。
プロダクション環境では、「デプロイ速度の遅さ」 と 「コールドスタート(初回起動時の遅延)」 が常に開発者の頭を悩ませます。ここをどう最適化するか、プロの知見を授けましょう。
知見①:巨大なnode_modulesをデプロイメントパッケージから排除する
よくある失敗が、Lambdaのコードと一緒に重たい `node_modules` ごとZIPに固めてデプロイしてしまうケースです。これではパッケージサイズが肥大化し、S3へのアップロードも、Lambdaのロード時間(コールドスタート)も劇的に遅くなります。
【対策】AWS Lambda Layerを活用せよ!
依存関係(lodashやaws-sdkなど)はすべて Lambda Layer に分離し、ビジネスロジックのコードだけを軽量なZIPとしてデプロイします。
// サードパーティライブラリ用のLayerを作成する例
const vendorLayer = new aws.lambda.LayerVersion(“vendorLayer”, {
code: new pulumi.asset.AssetArchive({
“nodejs/node_modules”: new pulumi.asset.FileArchive(“./lambda/node_modules”),
}),
compatibleRuntimes: [aws.lambda.Runtime.NodeJS18X],
});
// 本体側には Layer をアタッチし、コード自体は超軽量にする
const optimizedLambda = new aws.lambda.Function(“optimizedLambda”, {
code: new pulumi.asset.AssetArchive({
“.”: new pulumi.asset.FileAsset(“./lambda/dist”), // コンパイル後の軽量JSのみ
}),
runtime: aws.lambda.Runtime.NodeJS18X,
handler: “index.handler”,
role: lambdaRole.arn,
layers: [vendorLayer.arn], // ここでLayerを紐付け!
});
これにより、コードの変更によるデプロイ時間が数秒単位になり、CI/CDパイプラインが爆速になります。
知見②:コンパイル・バンドルプロセスの統合(esbuildの活用)
TypeScriptを使う場合、生のJSに変換するだけでなく、`esbuild` などの超高速バンドラーをPulumiのビルドプロセスに組み込むのが現代のベストプラクティスです。
Pulumiには、こうしたビルド処理をプログラム内でフックして実行するための柔軟な仕組みがあります。ファイルサイズを極限まで小さくし、実行時のメモリ消費とコールドスタートを最小限に抑えることができます。
—
まとめ
今回は、Pulumiの基本から、AWS Lambdaのモダンなデプロイ、そして現場で即効性のあるコールドスタート対策までを駆け足で解説しました。
- Pulumiを使えば、インフラとアプリケーションのビルド・デプロイを一つの言語でシームレスに統合できる。
- コードの自動パッケージングにより、シェルスクリプトの苦しみから解放される。
- Lambda Layerやバンドラーを駆使することで、デプロイの爆速化とコールドスタート対策を両立できる。
これをマスターすれば、毎日のインフラ作業やデプロイ待ちの時間が劇的に楽になり、より本質的なコードを書くことに集中できるようになりますよ。
さあ、あなたのプロジェクトでも `pulumi up` の爽快感をぜひ味わってみてください。次のインフラストラクチャの旅でまたお会いしましょう!