2026年6月、AWSがLambda MicroVMsをGAさせた。Lambdaの基盤であるFirecrackerをそのまま開発者に開放するようなサービスで、「VMレベルの隔離」「スナップショットからの高速起動」「suspend/resumeでメモリ・ディスク状態を保持」という、従来のステートレスなLambdaとはまるで性格の違う代物だ。東京リージョンが初期対応に入っていたので、GAから3週間足らずだが一通り触ってみた。
結論から書くと、起動2.5秒、suspend中に叩いても985msで自動復帰し、メモリ上のカウンタはちゃんと生き残っていた。本稿はそこに至るまでの構成判断とデバッグの記録である。
Lambda MicroVMsとは何か
仕組みはこうだ。アプリケーションコードとDockerfileをzipにしてS3に置き、create-microvm-image を呼ぶと、AWSがDockerfileを実行してアプリを起動した状態のFirecrackerスナップショットを取る。以後 run-microvm するたびに、そのスナップショットから復元されたMicroVMが数秒で立ち上がる。コールドブートではなく「初期化済みプロセスの復元」である点が肝だ。
- ARM64のみ。最大16 vCPU / 32GBメモリ / 32GBディスク、総実行時間8時間
- MicroVMごとに専用HTTPSエンドポイントが発行され、HTTP/2・gRPC・WebSocketに対応
- アイドル時はsuspendしてコンピュート課金が止まる(ストレージのみ)。着信で自動resume
- 想定用途はAIコード実行サンドボックス、ユーザーごとの開発環境、マルチテナントCI/CDなど
検証の設計
作ったのは「豪奢なHello, World」だ。ただの fmt.Println では検証にならないので、Goの標準ライブラリだけで小さなHTTPサーバを書き、金色のシマーアニメーション付きHTMLページと、いくつかのAPIを持たせた。
要となるのは /api/count である。呼ばれるたびにインメモリのカウンタを+1して返すだけのエンドポイントだが、これがsuspend/resume後も値が続けばメモリ状態保持の証明になるという証人役だ。
もうひとつの作法として、起動時に外部コネクションを張らない設計にした。スナップショットはアプリ初期化後に取られるため、初期化時に張ったコネクションや時刻依存の状態は復元後に腐る。先人の報告に従い、ゲストは接続レス・無状態初期化とした。
構成 — TerraformとSDKの分担、そしてトークン問題
全体構成は次のとおり。

構成を決める上でポイントが2つあった。
その1: TerraformはMicroVMを知らない。 terraform-provider-awsはまだLambda MicroVMsに対応していない(issue #48526)。そこで役割を割り切った。Terraformは変化しない土台(S3バケット、IAMロール、API Gateway、プロキシLambda)だけを持ち、MicroVMのライフサイクル(イメージ作成〜起動〜suspend〜破棄)はGo SDK(aws-sdk-go-v2/service/lambdamicrovms v1.0)で書いたドライバが受け持つ。
その2: 認証トークンは最長60分しか生きない。 MicroVMの専用エンドポイントは、毎リクエストに X-aws-proxy-auth ヘッダでJWEトークンを要求する。トークンは create-microvm-auth-token で発行するのだが、有効期限の上限が60分。つまりAPI Gatewayの静的なヘッダ注入では毎時死ぬ。そこで間に小さなプロキシLambdaを挟み、トークンを発行・キャッシュしてリクエストに付け替える構成にした。転送先のMicroVM IDとエンドポイントはSSM Parameter Store経由で渡すので、MicroVMを作り直してもドライバがSSMを書き換えるだけで済み、プロキシの再デプロイは不要だ。
ちなみにMicroVMイメージ用のDockerfileは3行しかない。
FROM scratch
COPY guest /guest
CMD ["/guest"]
GoをARM64静的ビルドしてzipに同梱するので、FROM scratch で外部レジストリへの依存がゼロになる。OS層は --base-image-arn(AWS管理のAL2023ベースイメージ)が別途提供するので、コンテナ側は本当にバイナリだけでいい。イメージビルドは約2分44秒だった。
ハマったところ(デバッグ記録)
GA直後のサービスをSDKで叩くと、ドキュメントの行間で転ぶ。4つ記録しておく。
1. GetMicrovmImage は名前を受け付けない。 CLIの例では --image-identifier my-image-name と名前で通るように見えるが、SDKで名前を渡すと ValidationException: Invalid ARN format: gorgeous-hello で弾かれた。ARNを組み立てて渡す必要がある。
2. 同名イメージの再作成はConflictExceptionではない。 エラーハンドリングで Conflict を待ち構えていたら、実際に飛んできたのは ValidationException に “already exists” のメッセージだった。エラーコードではなくメッセージで判定する羽目になった。
3. トークンAPIの戻り値は文字列ではなくmap。 CreateMicrovmAuthToken のレスポンスの AuthToken フィールドは map[string]string で、キー X-aws-proxy-auth の値を取り出して使う。ヘッダ名ごと返してくる設計は珍しい。
4. IAMアクションのプレフィックスは lambda-microvms: ではなく lambda:。 CLIのコマンド名前空間は aws lambda-microvms なのに、IAMポリシーに書くアクションは lambda:CreateMicrovmAuthToken だ。サービスモデルの署名名がlambdaのままだからで、ここを間違えるとプロキシがAccessDeniedで沈黙する。
実測値
東京リージョン(ap-northeast-1)での実測。
| 項目 | 実測 |
|---|---|
| イメージビルド(zip 6MB、FROM scratch) | 約2分44秒 |
| RunMicrovm → RUNNING | 2.5秒 |
| 初回リクエスト(復元直後) | 838ms |
| ウォーム時(エンドポイント直叩き) | 56ms |
| suspend完了 | 3.3秒 |
| suspend中に着信 → 自動resume → 応答 | 985ms |
本題: suspendしてもカウンタは生きているか
検証のクライマックスである。手順はこうだ。
- API Gateway経由で
/api/countを叩き、カウンタを5まで進める - SDKから
SuspendMicrovmを呼ぶ。3.3秒でSUSPENDEDになったことをAPIで確認 - suspend中のMicroVMに向けて、API Gateway経由で
/api/countを叩く
結果、985msで {"counter":6} が返ってきた。リクエストが着信した瞬間に自動でresumeされ(idle policyの autoResumeEnabled)、メモリ上のカウンタは5を覚えたまま6を返した。状態確認するとRUNNINGに戻っている。プロセスからみれば、時間が止まって再開しただけだ。
もうひとつ面白い観察があった。ゲストが自己申告する boot_time が、MicroVMの起動時刻より前を指していたのだ。値はイメージビルドの実行時刻。つまりプロセスはイメージビルド時に一度だけ起動し、以後のMicroVMはすべて「起動済みの状態」から復元されている。RunMicrovm→RUNNINGが2.5秒で済む理由がこの数字に表れている。
コストの後始末
MicroVMは起動している間vCPU秒+メモリGB秒で課金される。検証の放置事故を防ぐため、二重の保険をかけた。idle policyで「10分無通信でsuspend、suspend 4時間で自動terminate」、さらに MaximumDurationInSeconds で最長4時間の強制終了。恒久リソース(API Gateway+Lambda+SSM+S3+IAM)は実質ゼロ円なので、消し忘れても財布は痛まない。
まとめ
- Lambda MicroVMsは「状態を持てるサーバレス」という新しいプリミティブだ。起動2.5秒・resume 1秒弱・suspend中はストレージ課金のみ、という数字は実用の域にある
- Terraformは未対応なので、土台をTerraform・ライフサイクルをSDKドライバと割り切る構成が現時点の正解
- 認証トークン上限60分の制約は、トークンを付け替えるプロキシLambdaで吸収できる
- GA直後のSDKには行間が多い。ARN必須、mapで返るトークン、
lambda:プレフィックス——この手の罠はログが全部教えてくれる
次はWebSocket/gRPCの疎通を試す予定だ。検証リポジトリは追って公開する。