こんにちは!クラウドインフラ・SREの世界へようこそ。
今日は、開発現場の誰もが一度は頭を悩ませる「環境管理」の苦しみを根本から解決する、最高にエキサイティングな技術のお話をします。
「PR(プルリクエスト)ごとに本番そっくりの検証環境を自動で立ち上げ、用事が済んだら跡形もなく綺麗に消し去る」——そんな夢のようなエフェメラル環境(Ephemeral Environments)を、次世代IaCツール「Pulumi」とGitHub Actionsを使って実現する方法を、優しく、そして徹底的に深掘りしていきましょう。
これをマスターすれば、もう「ステージング環境の奪い合い」や「消し忘れたリソースによるAWS高額請求の恐怖」に怯える必要はなくなります。毎日の開発作業が劇的に楽になりますよ。それでは、一緒に旅を始めましょう!
—
1. なぜ「エフェメラル環境」なのか?(ツールの役割と設計思想)
従来のインフラ運用では、「dev環境」「stg環境」「prod環境」といった固定的な環境を数個用意するのが一般的でした。しかし、これには大きな問題があります。
- 複数の開発者が同じstg環境を使ってしまい、デプロイがコンフリクトする。
- 「俺のローカルでは動いたのに!」という環境差異の悪夢。
- 使っていない夜間や週末も稼働し続け、財布を直撃するクラウド代。
ここで登場するのが、「ゼロトラストなエフェメラル環境」という思想です。
「コード変更(PR)が発生したら、その瞬間だけの隔離されたインフラを動的に生成し、レビューが終わってマージされたら、容赦なく完全破棄(ゼロ化)する」。
これを支えるのが、プログラミング言語のパワーをそのままIaCに持ち込めるPulumiです。Terraformのような独自DSL(HCL)の縛りから解放され、TypeScriptやPythonなどの慣れ親しんだ言語で、if文やループを駆使した堅牢なインフラを構築できます。
—
2. 基礎セットアップ:Pulumiの世界へ飛び込もう
まずは、手元のマシンにPulumiを迎え入れましょう。今回は、最もエコシステムが安定している TypeScript を使用します。
インストール(macOSの場合)
brew install pulumi
※Windows(winget)やLinux環境でも、公式サイトから一発でインストール可能です。
プロジェクトの初期化
適当なディレクトリを作成し、プロジェクトをセットアップします。
mkdir pulumi-ephemeral-env
cd pulumi-ephemeral-env
pulumi new aws-typescript
対話形式でプロジェクト名やパスワード(暗号化用)を聞かれますが、基本はEnterキー連打でOKです。これだけで、TypeScriptのプロジェクト構造と必要な設定ファイルが生成されます。
—
3. 「Hello World」:動的プレビュー環境のコード設計
ここからが腕の見せ所です。PRごとに環境を作るということは、リソース名が衝突しないように一意のサフィックス(接尾辞)を動的に付与する必要があります。
以下のコードを見てください。これがエフェメラル環境構築の心臓部です。
`index.ts` を開き、次のように書き換えてみてください。
import as pulumi from “@pulumi/pulumi”;
import as aws from “@pulumi/aws”;
// 1. 現在のPulumiスタック名(例: pr-123)を取得する
// これにより、PRごとに完全に分離された名前空間を動的に作ります
const stackName = pulumi.getStack();
// 2. リソース名がグローバルで重複しないよう、一意のプレフィックスを生成
const namePrefix = `ephemeral-${stackName}`;
// 3. ネットワーキング層:この環境専用のVPCを爆誕させる
const vpc = new aws.ec2.Vpc(`${namePrefix}-vpc`, {
cidrBlock: “10.100.0.0/16”,
enableDnsHostnames: true,
enableDnsSupport: true,
tags: {
Name: `${namePrefix}-vpc`,
Environment: “Ephemeral”,
ManagedBy: “Pulumi”,
},
});
// 4. パブリックサブネットの作成
const subnet = new aws.ec2.Subnet(`${namePrefix}-subnet`, {
vpcId: vpc.id,
cidrBlock: “10.100.1.0/24”,
mapPublicIpOnLaunch: true,
tags: { Name: `${namePrefix}-subnet` },
});
// 5. 動作確認用の最小限のEC2インスタンス(またはECSなど)
// 今回はコストがかからないよう、最小構成のセキュリティグループと組み合わせます
const sg = new aws.ec2.SecurityGroup(`${namePrefix}-sg`, {
vpcId: vpc.id,
description: “Ephemeral environment security group”,
ingress: [
{ 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”] },
],
});
// 6. 外部に出力するエンドポイント(Outputs)
// CI/CDパイプラインやPRのコメント欄に自動通知するために使います
export const vpcId = vpc.id;
export const subnetId = subnet.id;
手元での動作確認(プレビュー)
Pulumiの最大の特徴は、実際にクラウドをいじる前に「何が起きるか」を完全に可視化できる点です。
スタック(環境の単位)をPR番号に見立てて作成・切り替え
pulumi stack init pr-42
プレビューの実行(ドライラン)
pulumi preview
ターミナルに、これから作成されるAWSリソースの計画が美しく描出されたはずです。「これをCI/CDに組み込めばいいのか!」と直感的に理解できたなら、もうエンジニアとしての視座が一つ上のステージに上がっています。
—
4. 究極の自動化:GitHub ActionsによるCI/CDワークフロー設計
さて、ここからが本番です。GitHubのPull RequestのライフサイクルとPulumiを完全に同期させます。
以下のワークフローファイルを作成してください。
`.github/workflows/ephemeral-env.yml`
name: Ephemeral Environment Pipeline
on:
pull_request:
types: [opened, synchronize, closed]
permissions:
id-token: write # AWS OIDC認証に必須
contents: read
pull-requests: write # PRにコメントを残す権限
jobs:
pulumi-ephemeral:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ’20’
cache: ‘npm’
- name: Install Dependencies
run: npm ci
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsPulumiRole
aws-region: ap-northeast-1
- name: Login to Pulumi
uses: pulumi/actions@v5
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
# PRが閉じられた(マージまたはクローズ)場合の処理
- name: Destroy Ephemeral Environment on PR Close
if: github.event.action == ‘closed’
run: |
pulumi stack select pr-${{ github.event.pull_request.number }} –non-interactive || exit 0
pulumi destroy –yes –non-interactive
pulumi stack rm pr-${{ github.event.pull_request.number }} –yes –non-interactive
# PRがオープン、または更新された場合の処理
- name: Up Ephemeral Environment on PR Open/Sync
if: github.event.action != ‘closed’
run: |
STACK_NAME=”pr-${{ github.event.pull_request.number }}”
# スタックが存在しない場合は新規作成、存在する場合は選択
pulumi stack select ${STACK_NAME} –non-interactive || pulumi stack init ${STACK_NAME} –non-interactive
# インフラのデプロイ実行
pulumi up –yes –non-interactive
この設計の美しさと強靭さ(SRE的解説)
1. 完全なステート管理の分離:
`pr-${{ github.event.pull_request.number }}` という規則的なスタック名を使うことで、PRごとに独立したステート(状態ファイル)がPulumi Cloud(またはS3等のバックエンド)に保持されます。これにより、他のPRと干渉することが物理的に不可能です。
2. ゼロトラストなクリーンアップ:
`github.event.action == ‘closed’` を検知した瞬間に、`pulumi destroy` と `pulumi stack rm` が走ります。開発者がボタンを押し忘れても、PRを閉じさえすれば、AWSの請求書からその環境は綺麗さっぱり消え去ります。
3. OIDCによるセキュアな認証:
AWSの長寿命なアクセスキー(Access Key)をGitHubに保存する必要はありません。OIDC(OpenID Connect)を使うことで、GitHub Actionsから一時的なトークンを発行し、セキュアにAWSリソースを操作します。
—
おわりに
お疲れ様でした!
Pulumiを用いたエフェメラル環境の自動構築・自動破棄の全体像が見えてきたのではないでしょうか。
この仕組みを導入したチームでは、「ステージング環境の順番待ち」という無駄な時間が消え、レビューの質が劇的に跳ね上がります。コードを書いてPRを投げたら、数分後には自分専用の検証環境がURL付きで目の前に現れる——そんな未来を、ぜひあなたの現場でも形にしてみてください。
あなたのインフラライフが、よりモダンで、よりクリエイティブになることを心から応援しています!