Lambda MicroVMsのIdle Policy(自動サスペンド・レジューム・ターミネート)を検証してみた
はじめに
2026年6月22日、AWS Lambda MicroVMsが発表されました。
Lambda MicroVMsは、VM分離された実行環境と最大8時間の状態保持を提供する機能です。一方で、MicroVMが起動している間はベースラインの課金が発生します。
そこで重要になるのが、アイドル時の自動ライフサイクル管理を行う idlePolicy です。idlePolicy は RunMicrovm API の lifecycleManagement 配下で指定する設定で、アイドル状態のMicroVMを自動でサスペンドし、一定時間後にターミネートできます。また、設定によってはリクエスト着信時に自動レジュームさせることもできます。
idlePolicy は、主に以下の3つのパラメータで構成されます。
| パラメータ | 説明 | 設定例 |
|---|---|---|
maxIdleDurationSeconds |
最後のリクエスト完了から自動サスペンドまでの秒数 | 60 |
suspendedDurationSeconds |
サスペンドから自動ターミネートまでの秒数 | 120 |
autoResumeEnabled |
サスペンド中にリクエストが来た場合に自動レジュームするか | true / false |
状態遷移は以下のとおりです。
RUNNING ──(idle超過)──► SUSPENDED ──(suspended超過)──► TERMINATED
▲ │
└──(autoResume+リクエスト)─┘
本記事では、maxIdleDurationSeconds、suspendedDurationSeconds、autoResumeEnabled の3パラメータについて、実際のステータス遷移やレジューム時間を計測して挙動を確認します。
検証環境
アプリケーション
状態確認に特化したシンプルなFlaskアプリを用意しました。同一アプリをgunicornで8080/9000の2ポートに提供し、フック設定側で9000番を指定しています。
GET /status— 内部状態(起動時刻、uptime、リクエスト数、イベントログ)POST /aws/lambda-microvms/runtime/v1/run|suspend|resume— ライフサイクルフック通知を記録
app.py(全文)
import time, logging, sys
from flask import Flask, jsonify, request
app = Flask(__name__)
logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
state = {"boot_time": time.time(), "request_count": 0, "last_request": None, "events": []}
def record(event):
state["events"].append({"event": event, "time": time.strftime("%Y-%m-%dT%H:%M:%S%z")})
print(f"[HOOK] {event} at {state['events'][-1]['time']}", flush=True)
@app.before_request
def count():
state["request_count"] += 1
state["last_request"] = time.strftime("%Y-%m-%dT%H:%M:%S%z")
# --- Main API (port 8080) ---
@app.route("/status")
def status():
return jsonify(boot_time=time.strftime("%Y-%m-%dT%H:%M:%S%z", time.localtime(state["boot_time"])),
uptime_seconds=round(time.time() - state["boot_time"], 1),
request_count=state["request_count"],
last_request=state["last_request"],
events=state["events"])
@app.route("/time")
def get_time():
return jsonify(now=time.strftime("%Y-%m-%dT%H:%M:%S%z"), epoch=time.time())
@app.route("/")
def index():
return jsonify(status="ok", uptime=round(time.time() - state["boot_time"], 1))
# --- Hooks (runtime API paths) ---
@app.route("/aws/lambda-microvms/runtime/v1/ready", methods=["GET", "POST"])
def ready():
record("ready")
return jsonify(status="ready"), 200
@app.route("/aws/lambda-microvms/runtime/v1/run", methods=["GET", "POST"])
def run():
state["boot_time"] = time.time()
record("run")
return jsonify(status="running"), 200
@app.route("/aws/lambda-microvms/runtime/v1/suspend", methods=["GET", "POST"])
def suspend():
record("suspend")
return jsonify(status="suspending"), 200
@app.route("/aws/lambda-microvms/runtime/v1/resume", methods=["GET", "POST"])
def resume():
record("resume")
return jsonify(status="resumed"), 200
Dockerfile
FROM public.ecr.aws/lambda/microvms:al2023-minimal
RUN dnf install -y python3.11 python3.11-pip && dnf clean all && \
ln -sf /usr/bin/python3.11 /usr/bin/python3 && \
ln -sf /usr/bin/pip3.11 /usr/bin/pip3
WORKDIR /app
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8080 9000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8080", "--bind", "0.0.0.0:9000", "--workers", "1", "--preload", "--access-logfile", "-", "--log-level", "debug"]
MicroVM 起動設定
aws lambda run-microvm \
--image-arn arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:idle-policy-test \
--lifecycle-management '{
"idlePolicy": {
"maxIdleDurationSeconds": 60,
"suspendedDurationSeconds": 120,
"autoResumeEnabled": true
}
}'
計測方法
get-microvmを10秒間隔でポーリングし、ステータス遷移のタイミングを観測(最大±10秒の観測誤差を含む)- 自動レジュームのレイテンシは
curlのtime_totalで計測
検証1: 自動サスペンド
maxIdleDurationSeconds=60 を設定し、起動後にリクエストを一切送らず放置しました。
結果
起動から約60秒後にRUNNING → SUSPENDEDへの遷移を検出しました。
| 経過時間 | ステータス |
|---|---|
| 0s | RUNNING |
| 30s | RUNNING |
| 60s | SUSPENDED |
設定値どおり60秒で遷移が発生しました(10秒間隔ポーリングのため、50〜60秒の間に遷移)。
検証2: アイドルタイマーリセット
同一設定(maxIdleDurationSeconds=60)で、30秒間隔でリクエストを送り続けました。
結果
30秒間隔で5回(計150秒間)リクエストを送信した結果:
[0s] リクエスト → RUNNING
[30s] リクエスト → RUNNING
[60s] リクエスト → RUNNING ← 直近リクエストによりアイドルタイマーがリセットされRUNNING維持
[90s] リクエスト → RUNNING
[120s] リクエスト → RUNNING
[150s] リクエスト停止
[210s] → SUSPENDED ← 停止から約60秒後
maxIdleDurationSeconds=60 の起算起点は最後のリクエスト完了時点のため、リクエストのたびにアイドルタイマーがリセットされ、RUNNINGが維持されました。リクエスト停止後は、改めて約60秒でサスペンドされました。
検証3: 自動レジューム
結果
SUSPENDED状態のMicroVMにリクエストを送信し、3回計測した結果:
| 試行 | curl time_total |
|---|---|
| 1回目 | 2.618s |
| 2回目 | 2.613s |
| 3回目 | 2.610s |
今回の3回の計測ではばらつき8ms以内に収まりました。この条件では、クライアント側のタイムアウトを5秒程度に設定しておけばレジューム完了まで待てる結果でした。
今回確認した範囲では、レジューム後もアプリのメモリ上の状態(リクエストカウンタ、イベントログ)が保持されていました。
$ curl https://xxxxx.lambda-url.ap-northeast-1.on.aws/status
{
"boot_time": "2026-06-24T01:15:00+0900",
"uptime_seconds": 312.5,
"request_count": 8,
"events": [
{"event": "ready", "time": "2026-06-24T01:14:55+0900"},
{"event": "run", "time": "2026-06-24T01:15:00+0900"},
{"event": "suspend", "time": "2026-06-24T01:16:00+0900"},
{"event": "resume", "time": "2026-06-24T01:18:35+0900"}
]
}
request_count がサスペンド前の値を引き継ぎ、events 配列にもサスペンド前のイベントが残っています。メモリ上のプロセス状態がサスペンド前から引き継がれており、状態が保存・復元される挙動が確認できます。
検証4: 自動ターミネート
SUSPENDED状態のまま放置し、suspendedDurationSeconds=120 の自動ターミネートを確認しました。
結果
SUSPENDEDを検出してから約116秒後にTERMINATEDへの遷移を検出しました。
| 経過時間(SUSPENDED後) | ステータス |
|---|---|
| 0s | SUSPENDED |
| 60s | SUSPENDED |
| 116s | TERMINATED |
設定値120秒とほぼ一致しています。TERMINATEDになったMicroVMに対するリクエストはエラーとなり、以降は復帰できません。
検証5: autoResumeEnabled=false
autoResumeEnabled=false で新しいMicroVMを起動し、SUSPENDED状態でのリクエスト挙動を確認しました。
結果
SUSPENDED状態のMicroVMにリクエストを送信したところ、HTTP 502 (Bad Gateway) が即座に返却されました。
$ curl -o /dev/null -s -w "%{http_code} %{time_total}s\n" https://xxxxx.lambda-url.ap-northeast-1.on.aws/status
502 0.058s
タイムアウトではなく即時に502が返り、MicroVMはSUSPENDEDのまま自動レジュームは発生しませんでした。
手動で resume-microvm を実行したところ、ステータスがRUNNINGに復帰し、リクエストが正常に処理されることを確認しました。
$ aws lambda resume-microvm --microvm-id microvm-xxxxx
$ curl https://xxxxx.lambda-url.ap-northeast-1.on.aws/status
{"boot_time":"2026-06-24T01:30:00+0900","request_count":5,...}
注意事項・Tips
フックパスは full path が必要だった
今回の構成では、フック設定で短縮パス(/ready、/run 等)を指定してもフック呼び出しが成功せず、以下のfull pathを指定する必要がありました。
/aws/lambda-microvms/runtime/v1/ready
/aws/lambda-microvms/runtime/v1/run
/aws/lambda-microvms/runtime/v1/suspend
/aws/lambda-microvms/runtime/v1/resume
フックポートへの接続挙動
gunicornのアクセスログを確認したところ、フックポート(9000番)に対してまずTLS接続を試行し、失敗後にプレーンHTTPで接続される挙動を観測しました。アプリ側でTLS対応していなくても動作します。
ただし、TLS接続リトライ分の遅延が加わる可能性もあります。
readyフック必須
run / suspend / resume フックを使う場合、ready フックも合わせて設定する必要があります。ready フックなしではMicroVMイメージのビルドが完了しません。
まとめ
今回の検証では、Lambda MicroVMsの idlePolicy により、自動サスペンド・自動ターミネートがおおむね設定値に沿って動作することを確認できました。自動レジュームも、3回の計測では約2.6秒で復帰し、大きなばらつきは見られませんでした。
idlePolicy は、「使っていない間は止めて、リクエストが来たら復帰する」というコスト最適化パターンを、業務ロジックの変更なく実現できる仕組みです。採用時は、サスペンド状態からの初回リクエストで発生するレジューム時間をユーザー体験として許容できるかが判断ポイントになります。今回の検証条件では約2.6秒だったため、これを許容しにくい場合は、maxIdleDurationSeconds を大きくしてRUNNING状態を維持する、または定期的にリクエストを送ってアイドルタイマーをリセットする構成が代替手段になります。
参考リンク








