こんにちは、ふくちです。
下記ハンズオンをしていて気づいたことがあるので備忘録的にまとめておきます。
Lambda MicroVMのイメージ構築時ライフサイクルフック
タイトルにはわかりやすくヘルスチェックポートと記載しましたが、正式に言えば「ライフサイクルフック」の「ポート」という設定項目の話です。
Lambda MicroVMを立ち上げるまでの流れを軽く説明しておくと、
- Lambda MicroVMのイメージを作成する
- イメージの検証を行う
- 実際にMicroVMを起動する
みたいな流れです。
この中のイメージ検証にフォーカスすると、下記のような流れになります。
- S3 から zip アーティファクトをダウンロードする
- zip 内の Dockerfile を実行して依存関係をインストールし、アプリケーションを起動する
- アプリケーションの /ready ライフサイクルフックを呼び出す(正常に起動したことを確認する)
- 初期化されたディスクとメモリの状態のスナップショットを取得する
- スナップショットを保存する。以降の MicroVM 起動はこのスナップショットから 1 秒未満で再開されます
という感じで実際にMicroVMを起動する準備が整っているかを確認するのがライフサイクルフックです。もう少し正確に言うと、イメージ構築時に動くライフサイクルフックです。
先程少し記載した通り/aws/lambda-microvms/runtime/v1/readyというフックを用い、イメージのビルド中にアプリケーションがENTRYPOINTまたはCMDを通じて起動した後に呼び出されます。アプリケーションのスナップショット作成準備が整ったことを通知してくれるようなものです。
ここで確認するポートはデフォルトだと9000っぽいのですが、ユーザー側でも自由に変更できますよ、という話です。
ちなみに公式ドキュメントを参照すると、イメージ構築時に動くフックと実際にMicroVMを操作する際に動くフックの2種類があるようです。上記で話したのは前者です。
後者の方は実際に起動・一時停止・再開・終了する際に諸々の確認で用いられるフックだそうです。
実際に設定するには
ということでイメージ構築時に動くライフサイクルフックを設定するのですが、アプリ側とLambda MicroVM側でそれぞれ設定箇所があります。
アプリ側は下記のように任意のポートを設定しておきます。ここでは9001としてみます。
ワークショップのPhase1で用いるコードをお借りしています。
<import/logger省略>
MICROVM_ID = None
# ── Application handler (port 8080) は関係ないので省略
<省略>
# ── ライフサイクルフックハンドラー (port 9001) ───────────────────────────────────────
class HookHandler(BaseHTTPRequestHandler):
"""ランタイムからのMicroVMライフサイクルフックコールバックを処理します"""
<中略>
def do_POST(self):
global MICROVM_ID
body = self.read_body()
<中略>
if self.path.endswith("/ready"):
# イメージのビルド中に呼び出されます
# これが200を返した後にスナップショットが取得されます
# このフックが実行される前に、アプリケーションが起動している必要があります
logger.info("/ready — アプリケーションが起動しました。スナップショットを取得します。")
self.send_json(200, {"status": "ready"})
<中略・他のライフサイクルフックも定義>
# ── Startup ───────────────────────────────────────────────────────────────────
def start_hook_server():
"""ライフサイクルフックサーバーをポート9000で起動"""
server = HTTPServer(("0.0.0.0", 9001), HookHandler)
logger.info("ライフサイクルフックサーバーがポート9001で起動しています")
server.serve_forever()
def main():
# ライフサイクルフックサーバーをバックグラウンドスレッドで起動する
threading.Thread(target=start_hook_server, daemon=True).start()
# アプリケーションサーバーをポート8080で起動する
server = HTTPServer(("0.0.0.0", 8080), AppHandler)
logger.info("アプリケーションサーバーがポート8080で起動しています")
server.serve_forever()
if __name__ == "__main__":
main()
こんな感じでフックサーバー起動時にポート9001を指定します。
そしてLambda MicroVMイメージを作成する際にポートを9001に設定します。
MicroVMを起動する際ではなく、イメージを作成する際に設定するのがポイントです。あと下限は1、上限は65535です。

ちなみに他にもライフサイクルフックがあるので気になる方は調べてみてください。/readyだけでなく、これらのフックも9001を用いることになります。

APIだとこの辺を確認してみてください。
ちなみにDockerfileにもEXPOSE 8080 9001みたいなのを書いていたりもしますが、これはどうやら単なるメタデータのようです。なのでここを9000にしても動くのは動きますが、実装との齟齬が出るので統一しておくのが良いでしょう。
このEXPOSE指示は実際にはポートを公開するものではありません。これは、イメージを作成する人とコンテナを実行する人の間で、どのポートを公開する予定なのかを示す一種のドキュメントとして機能します。
まとめ
AWS側の思想として、Lambda MicroVMはできる限り自由に使えるプレーンなAmazon Linuxをサーバーレスで用いることができるようにしてくれているようです。
やろうと思えばなんでもできそうなので、色んなユースケースを探ってみます!
ちなみにマインクラフトは動くらしいです。