LambdaのContainer Image Supportでサブコマンド経由で呼ぶ方法

2020/12、Lambdaに待望のコンテナイメージサポートが追加されました。これにより、すでにECSなどでコンテナベースのデプロイをしている場合は既存のイメービルドの仕組みを流用できるようになりました。

同時にローカル環境でLambda関数をAPI経由で実行可能にするThe Lambda Runtime Interface Emulator (“RIE”)も公開されました。

実はDockerfileのCMDでサブコマンドを指定してLambda関数を呼び出す場合、RIEとAWS実環境で挙動が異なることがわかりました。

今回は両方で動く方法を実装して https://github.com/nabeken/go-lambda-subcommands-example に公開しています。

どういうこと

イメージサイズを小さく保つため、Goで複数のコマンド(e.g. APIやworker)を書く時はシングルバイナリにして、実際のコマンドはサブコマンドとして実装することが多いです。

例:

prj-main がビルドされたバイナリで、実際のコマンドは引数で指定。

これをLambdaのContainer Image Supportで行なう場合は DockerfileCMD ["prj-main", "api"] のように指定しますが、RIEではこれが動きません。

推測ですが、RIEは従来のLambda関数のパッケージングもサポートする関係上、 _HANDLER 環境引数に指定されたバイナリを実行しようとします。この値はファイル名であることを期待しているため、引数が渡せません。

上のサンプルプロジェクトに含まれる entrypoint.sh_lambda_main はオリジナルの引数をファイルへ退避しながらruntimeを実行するentrypoint、Lambdaのruntimeがhandlerを実行する時にそれを復元するshimで構成されています。

すでにECSで運用しているコンテナイメージがあるなら、上記のような動きをするファイルを仕込み、Lambdaの設定でentrypointを変更すればECSとLambdaで共用できるイメージが出来上がります。どうぞお試しあれ。