RustでAWS Lambda Container Imageを1イメージで複数Functionデプロイできるのか?

この記事は Rust Advent Calendar 2021 19日目の記事です。

はじめに

こちらは、やってみたけどうまく行かなかった記事です。 以下について情報提供をお待ちしています。

  • Lambda Container Imageのローカル実行でメモリ使用量を確認できない?
  • Lambda Container Imageの bootstrap に引数は渡せない?

やりたかったこと

AWS Lambdaがコンテナイメージでの実行をサポートしてしばらくが経ちます。 RustでLambdaのコンテナイメージを作る場合、1つのイメージにつき1つのバイナリが必要そうでした。

Python等でLambda コンテナイメージを作る場合は、1つのイメージに複数のhandlerを含め、CMDで実行するものを変更できました。これと同様のことがRustでもできるのではないでしょうか?

1つのイメージに複数のhandlerを含めたときに気になるのが、バイナリサイズや実行時間への影響です。今回はこれらをローカル実行にて確認してみたいと思います(思っていました)。

実験内容

以下3種類のLambda用バイナリを作ります。

  1. simple-hello: {"message": "Hello, World!"} を返すだけのシンプルなLambda
  2. simple-regex: 入力の date が、文字列で YYYY-MM-DD の形になっているか確認するLambda
  3. cli-mixed: 上記2つのLambda handlerをCLI引数で実行し分けるLambda

これらについて、以下を(ローカルで)確認します。

  • バイナリサイズ
  • イメージサイズ(バイナリサイズの大小の他、ベースイメージとのサイズ比も気になるところかと思います)
  • 初回起動時、2回目以降起動時の実行時間
  • 使用メモリ量

実験

作成したコード

GitHubに配置しました。

github.com

ビルド

以下のようにそれぞれビルドします。

cargo build --release --target x86_64-unknown-linux-musl
docker build -t simple-hello -f Dockerfile-simple-hello .
docker build -t simple-regex -f Dockerfile-simple-regex .
docker build -t cli-mixed -f Dockerfile-cli-mixed .

バイナリサイズ

ls で普通に確認します。

s -lh  target/x86_64-unknown-linux-musl/release/
合計 21M
drwxr-xr-x 15 vraisamis vraisamis 4.0K 12月 18 21:14 build
-rwxr-xr-x  2 vraisamis vraisamis 7.7M 12月 18 21:14 cli-mixed
-rw-r--r--  1 vraisamis vraisamis  162 12月 18 20:50 cli-mixed.d
drwxr-xr-x  2 vraisamis vraisamis  20K 12月 18 21:14 deps
drwxr-xr-x  2 vraisamis vraisamis 4.0K 12月 18 20:49 examples
drwxr-xr-x  2 vraisamis vraisamis 4.0K 12月 18 20:49 incremental
-rwxr-xr-x  2 vraisamis vraisamis 5.6M 12月 18 20:50 simple-hello
-rw-r--r--  1 vraisamis vraisamis  168 12月 18 20:50 simple-hello.d
-rwxr-xr-x  2 vraisamis vraisamis 7.1M 12月 18 20:53 simple-regex
-rw-r--r--  1 vraisamis vraisamis  168 12月 18 20:50 simple-regex.d
  • simple-hello は5.6MBです
  • simpleregex は7.1MBです。このプログラムは、simple-helloにregexを足しただけのものなので、差分はそのライブラリ分と言えるでしょう。
  • cli-mixed は7.7MBです。このプログラムは、上記2つを組み合わせ、CLI引数パースライブラリを入れたもので、これが差分と言えるでしょう。

バイナリサイズについてですが、以下記事で言及されているサイズとも大きく違いません。おかしいところはないと言えるでしょう。

zenn.dev

また、cli-mixed での増分は0.6MBほどで、CLIパースライブラリ( clap 3)を入れることによる影響は小さいものと考えて良さそうです。

イメージサイズ

docker images
REPOSITORY                       TAG       IMAGE ID       CREATED         SIZE
cli-mixed                        latest    a1edde0b912e   25 hours ago    312MB
simple-regex                     latest    140072c9464d   26 hours ago    311MB
simple-hello                     latest    5e7d492f9742   27 hours ago    310MB
public.ecr.aws/lambda/provided   al2       606c70acc7a0   36 hours ago    304MB

上記の通り、ベースのイメージは300MBほどあります。最小のLambdaであれば、イメージサイズに比べて十分小さく、デプロイ速度等への影響は出にくいものと考えられます。

実行時間・使用メモリ量

いずれも以下のようにしてローカル実行します。

docker run --rm -p 9000:8080 simple-hello

# 別terminalで
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"date": "2014-01-01"}'

# docker runしたほうのterminalに以下が表示される
START RequestId: 4965b0b0-8129-427d-9551-292b0391e4dd Version: $LATEST
END RequestId: 4965b0b0-8129-427d-9551-292b0391e4dd
REPORT RequestId: 4965b0b0-8129-427d-9551-292b0391e4dd  Init Duration: 0.35 ms  Duration: 5.25 ms       Billed Duration: 6 ms
Memory Size: 3008 MB     Max Memory Used: 3008 MB

実行(できなかった)

cli-mixed は以下の通り実行できませんでした。

docker run --rm -p 9000:8080 cli-mixed hello
time="2021-12-19T14:25:39.891" level=info msg="exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)"
time="2021-12-19T14:25:43.398" level=info msg="extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory"
time="2021-12-19T14:25:43.398" level=warning msg="Cannot list external agents" error="open /opt/extensions: no such file or directory"
START RequestId: 8410dbfa-8b8a-43a1-80a4-91f3b48fee35 Version: $LATEST
cli-mixed

USAGE:
    bootstrap <SUBCOMMAND>

OPTIONS:
    -h, --help    Print help information

SUBCOMMANDS:
    hello
    help     Print this message or the help of the given subcommand(s)
    reg
time="2021-12-19T14:25:43.402" level=warning msg="First fatal error stored in appctx: Runtime.ExitError"
time="2021-12-19T14:25:43.402" level=warning msg="Process 16(bootstrap) exited: Runtime exited with error: exit status 2"
time="2021-12-19T14:25:43.402" level=error msg="Init failed" InvokeID= error="Runtime exited with error: exit status 2"
time="2021-12-19T14:25:43.402" level=warning msg="Reset initiated: ReserveFail"
time="2021-12-19T14:25:43.402" level=warning msg="Cannot list external agents" error="open /opt/extensions: no such file or directory"
cli-mixed

USAGE:
    bootstrap <SUBCOMMAND>

OPTIONS:
    -h, --help    Print help information

SUBCOMMANDS:
    hello
    help     Print this message or the help of the given subcommand(s)
    reg
END RequestId: 5739ea46-a317-4581-b9c8-dc073f0e7b1f
REPORT RequestId: 5739ea46-a317-4581-b9c8-dc073f0e7b1f  Init Duration: 0.23 ms  Duration: 8.27 ms       Billed Duration: 9 ms
Memory Size: 3008 MB     Max Memory Used: 3008 MB

初回実行時間・メモリ使用量

いずれも10回実行した結果です。 (最小)~(平均)±(分散)~(最大) で表記します。

プログラム Init Duration [ms] Duration [ms] Memory Size [MB] Max Memory Used [MB]
simple-hello 0.18~0.33±0.10~0.49 3.76~4.52±0.47~5.25 3008 3008
simple-regex 0.19~0.31±0.06~0.40 4.60~5.17±0.51~6.15 3008 3008
  • どちらも実行時間としては大きな差はないです。大きなプログラムではないのでそれはそうです
  • 初回実行時のみ、simple-regex正規表現パターンをコンパイルするので、その分だけ遅くなっているようです
  • 主に比較したかった cli-mixed について比較できていないのが残念です
  • メモリ使用量が3GBくらいになっていますが、そんなにつかうはずがありません。確認方法に問題があると思われます

2回目以降の実行時間・メモリ使用量

いずれも10回実行した結果です。

プログラム Duration [ms] Memory Size [MB] Max Memory Used [MB]
simple-hello 1.24~1.35±0.10~1.54 3008 3008
simple-regex 1.03~1.28±0.17~1.67 3008 3008
  • これも実行時間に差がほぼありません
  • 初期化時間がない分、より速くなっています
  • simple-regex が2回目以降パターンがコンパイル済みであるため、もともとあった差がよりなくなっています(平均で見るとちょっと速い)
  • メモリ使用量が3GBくらいになっていますが、そんなにつかうはずがありません。確認方法に問題があると思われます

まとめ

  • 今回の実験では、目的の cli-mixed について調査完了できませんでした。 実行方法について情報をお待ちしています
  • 実行時間に関しては、初回から10msを切る結果で、かなり高速といえるでしょう
  • Lambda Container Imageのローカル実行はかなり簡単で、開発サイクルを回しやすいと感じました