【実務・中級編】Pulumi入門:AWS環境構築ハンズオン(TypeScript版) – インフラ構成管理(IaC)活用バイブル

Pulumi時代の到来:TypeScriptでAWSインフラを極限まで高速かつ堅牢にコード化する実践アプローチ

テックリードの私たちが日々のインフラ運用で直面する最大のボトルネックは何か? それは「遅いフィードバックループ」と「静的解析の効かないDSL(HCLなど)によるCognitive Load(認知負荷)」だ。

Terraformは素晴らしいツールだが、複雑な条件分岐やモジュールのネスト地獄、そして何より「実際にApplyするまでエラーに気づけない」という開発体験の悪さに疲弊したチームも多いだろう。

そこで本稿では、一般的な「公式チュートリアルのなぞり書き」を一切排除し、実務の現場で即座にチーム全体の生産性を2倍にするためのPulumi(TypeScript版)の実践知見を凝縮して解説する。

—

0. プロの前提:開発速度を最大化するエコシステム設定

本題に入る前に、プロのエンジニアが作業効率を極限まで高めるために導入している「神プラグイン」と「キーボードショートカット」を共有する。

絶対に入れるべきIDE(VS Code)拡張機能

1. Pulumi (official): リソースのステートやプレビュー情報をインライン表示。
2. Error Lens: TypeScriptの型エラーやPulumiのプロパティ不足を即座にエディタ上で可視化。
3. AWS Toolkit: 生成されたリソースの挙動確認をシームレスに行う。

爆速化のためのキーバインド(`keybindings.json`)

インフラコードの記述と検証をノーマライズするために、以下のショートカットを設定せよ。

[
{
“key”: “ctrl+alt+u”,
“command”: “workbench.action.terminal.sendSequence”,
“args”: { “text”: “pulumi up –preview-only\n” }
},
{
“key”: “ctrl+alt+d”,
“command”: “workbench.action.terminal.sendSequence”,
“args”: { “text”: “pulumi destroy\n” }
}
]

これで、指をホームポジションから離すことなく、一瞬で変更の差分プレビュー(`pulumi up –preview-only`)を走らせることが可能になる。

—

1. 前提条件とPulumi CLIのインストール

環境構築でつまづく時間は無駄だ。macOSであればHomebrew一択、Linux/WSL環境でも公式のワンライナーで最新のCLIを導入する。

Pulumi CLIのインストール
curl -fsSL https://get.pulumi.com | sh

パスの永続化(zshの例)
echo ‘export PATH=$HOME/.pulumi/bin:$PATH’ >> ~/.zshrc
source ~/.zshrc

インストール確認
pulumi version

チーム開発における状態管理(State Backend)の極意

PulumiはデフォルトでPulumi Service(SaaS)にステートを保存するが、企業のセキュリティ要件やオンプレ・VPC内完結を求める場合、AWS S3 + DynamoDB(ステートロック用) をバックエンドに指定するのが鉄則だ。

環境変数でバックエンドを指定する:

export PULUMI_BACKEND_URL=”s3://my-company-pulumi-state-bucket-ap-northeast-1″

—

2. AWS認証情報の設定とプロジェクト初期化

AWSの認証は、静的なクレデンシャルをコードにハードコーディングする愚を犯してはならない。AWS SSO(IAM Identity Center)または環境変数による一時クレデンシャルを前提とする。

プロジェクトの初期化

TypeScriptで型安全なインフラ定義を行うためのプロジェクトをスクラッチから作成する。

mkdir pulumi-aws-hands-on && cd pulumi-aws-hands-on
pulumi new aws-typescript –name aws-infra-production –description “Production grade AWS infrastructure via TypeScript” –generate-only –yes

`–generate-only` を指定することで、対話形式をスキップし、CI/CDパイプラインにも組み込みやすい形で初期化できる。

ここで生成される `package.json` には、最新の `@pulumi/aws` が含まれていることを確認し、依存関係をインストールする。

npm install

—

3. VPCとEC2インスタンスをコードで構築する実装

ここからが本題だ。HCLでは冗長になりがちなVPC、サブネット、インターネットゲートウェイ、そしてEC2インスタンスの構築を、TypeScriptの強力な型システムと抽象化能力を用いて美しく実装する。

以下の構成ファイルを `index.ts` として配置する。

実用的な `index.ts` のベストプラクティス構成

import as pulumi from “@pulumi/pulumi”;
import as aws from “@pulumi/aws”;

// 1. 設定値の読み込み(Configスタックの活用)
const config = new pulumi.Config();
const instanceType = config.get(“instanceType”) || “t3.micro”;
const environment = pulumi.getStack(); // 例: dev, staging, prod

// 2. ネットワーク層の構築 (VPC & Subnet)
const vpc = new aws.ec2.Vpc(`app-vpc-${environment}`, {
cidrBlock: “10.0.0.0/16”,
enableDnsHostnames: true,
enableDnsSupport: true,
tags: {
Name: `vpc-${environment}`,
Environment: environment,
ManagedBy: “Pulumi”,
},
});

// パブリックサブネットの作成
const publicSubnet = new aws.ec2.Subnet(`app-subnet-public-${environment}`, {
vpcId: vpc.id,
cidrBlock: “10.0.1.0/24”,
mapPublicIpOnLaunch: true,
availabilityZone: “ap-northeast-1a”,
tags: { Name: `subnet-public-1a-${environment}` },
}, { parent: vpc }); // リソース間の親子関係を明示し、削除順序を保証

// インターネットゲートウェイ
const igw = new aws.ec2.InternetGateway(`app-igw-${environment}`, {
vpcId: vpc.id,
tags: { Name: `igw-${environment}` },
}, { parent: vpc });

// ルートテーブルとルートの紐付け
const publicRouteTable = new aws.ec2.RouteTable(`app-rt-public-${environment}`, {
vpcId: vpc.id,
routes: [
{
cidrBlock: “0.0.0.0/0”,
gatewayId: igw.id,
},
],
tags: { Name: `rt-public-${environment}` },
}, { parent: vpc });

new aws.ec2.RouteTableAssociation(`app-rta-${environment}`, {
subnetId: publicSubnet.id,
routeTableId: publicRouteTable.id,
});

// 3. セキュリティグループの構築
const webSg = new aws.ec2.SecurityGroup(`app-sg-web-${environment}`, {
vpcId: vpc.id,
description: “Allow HTTP and SSH”,
ingress: [
{ protocol: “tcp”, fromPort: 22, toPort: 22, cidrBlocks: [“0.0.0.0/0”] }, // 本番では特定の踏み台IPに制限すること
{ protocol: “tcp”, fromPort: 80, toPort: 80, cidrBlocks: [“0.0.0.0/0”] },
],
egress: [
{ protocol: “-1”, fromPort: 0, toPort: 0, cidrBlocks: [“0.0.0.0/0”] },
],
tags: { Name: `sg-web-${environment}` },
}, { parent: vpc });

// 4. 最新の Amazon Linux 2023 AMI の動的取得
const ami = aws.ec2.getAmi({
filters: [
{ name: “name”, values: [“al2023-ami-2023.-x86_64”] },
{ name: “virtualization-type”, values: [“hvm”] },
],
owners: [“amazon”],
mostRecent: true,
});

// 5. EC2インスタンスの構築
const server = new aws.ec2.Instance(`app-server-${environment}`, {
ami: ami.then(ami => ami.id), // 非同期で取得したAMI IDをPromiseで解決
instanceType: instanceType,
subnetId: publicSubnet.id,
vpcSecurityGroupIds: [webSg.id],
associatePublicIpAddress: true,
tags: {
Name: `ec2-web-${environment}`,
},
// UserDataを使ったプロビジョニングの初期化
userData: `#!/bin/bash
dnf update -y
dnf install -y httpd
systemctl start httpd
systemctl enable httpd
echo “

Hello from Pulumi on AWS (${environment})

” > /var/www/html/index.html
`,
}, { parent: publicSubnet });

// 6. 出力値(Outputs)の設定
export const vpcId = vpc.id;
export const instanceId = server.id;
export const publicIp = server.publicIp;
export const publicDns = server.publicDns;

—

4. デプロイ(`pulumi up`)と破棄の流れ

コードが完成したら、いよいよインフラを現実世界に顕現させる。

スタック(環境)の作成と切り替え

Pulumiでは環境ごとに「Stack」という概念を用いる。開発環境用(dev)のスタックを作成する。

pulumi stack init dev

設定値の注入(オプション)

必要に応じて、スタックごとの設定値を投入する。

pulumi config set instanceType t3.small

デプロイの実行(`pulumi up`)

先ほど設定したキーボードショートカット、あるいは以下のコマンドを実行する。

pulumi up

実行すると、インタラクティブなUIで変更差分(プレビュー)が表示される。内容に問題がなければ `yes` を選択するだけで、数分でAWS上にVPC、サブネット、EC2が構築され、最後に `Outputs` としてパブリックIPが出力される。

ブラウザで出力された `publicIp` にアクセスせよ。「`Hello from Pulumi on AWS (dev)`」という文字列があなたを迎え入れるはずだ。

完全に環境を片付ける(`pulumi destroy`)

検証が終わったら、リソースを完全に削除し、AWSの課金を止める。

pulumi destroy –yes
pulumi stack rm dev –yes

この単一のコマンドにより、コードで定義された依存関係の逆順(EC2 $\rightarrow$ セキュリティグループ $\rightarrow$ サブネット $\rightarrow$ VPC)で美しくリソースが消し去られる。Terraformでありがちな「依存関係エラーで削除できない」というストレスから完全に解放される瞬間である。

—

テックリードからの総括

今回体験したように、PulumiをTypeScriptで扱うメリットは単に「プログラミング言語が使える」ことだけではない。

  • 強力な型補完によるAWSプロパティのドキュメント参照コストの激減
  • `Array.map` や条件分岐など、TypeScriptの言語機能をそのまま利用したDRYなコード設計
  • `{ parent: vpc }` による直感的なリソースライフサイクルの制御

インフラストラクチャはもはや「設定ファイル」ではなく、「ソフトウェアそのもの」として構築・テスト・デプロイされるべきである。この知見をあなたのチームに持ち帰り、開発スピードをネクストステージへと引き上げてほしい。

タイトルとURLをコピーしました