arm64 Cargo Lambda で reqwest
内容
タイトルの通り arm64 の cargo lambda から reqwest で http リクエストをする。
Rust の Lambda を arm64 で作ろうとしたら reqwest が上手く動かない、そもそもビルドが通らないなどに出くわす。その解決手段とサンプルを記す。
本記事で述べること
CDK を使って Cargo Lambda の zip デプロイ
Cargo Lambda のデプロイ方法は ECR からコンテナイメージをデプロイする方法と bootstrap.zip
をデプロイする方法があるがここでは後者の zip をデプロイする方法で説明する。
ffmpeg を使いたいなど何か dnf (パッケージマネージャー)でパッケージを追加したいとかでなければ zip でいい。
arm64 (aarch64) でビルド
Lambda は x86
より arm64
のほうが安い。
昨今の arm64
の実績を踏まえると x86
しか提供されていないライブラリなどを使いたいなどでない限りは arm64
を使うのも悪くないだろう。
2025年2月現在 の us-east-1 の Lambda のコスト
Architecture | Duration ($/GB-second) | Detail |
---|---|---|
x86 | 0.0000166667 | (First 6 Billion GB-seconds / month) |
arm | 0.0000133334 | (First 7.5 Billion GB-seconds / month) |
- AWS Lambda pricing
- Selecting and configuring an instruction set architecture for your Lambda function
musl ビルド
少し軽量。プログラムを静的にリンクすることでシステムの glibc
に依存しなくなる。
Lambda では musl
を使うことを推奨されていたはず。
"GLIBC_x.xx not found" などのエラーに悩まされなくなる。
x86 でクロスコンパイル
流石に arm64 ビルドのために arm マシンを用意するのも面倒なので Docker で x86 からクロスコンパイルできるように。
手順
Rust
cargo add
cargo lambda 用のクレートと reqwest と JSON 系のクレートを入れる。
cargo add lambda_http
cargo add reqwest --features=json
cargo add serde --features=derive
cargo add serde_json
cargo add tokio --features=macros
cargo add openssl
OpenSSL のクレートを入れる。 OpenSSL の features で vendored
を設定するとビルドターゲットでいい感じに OpenSSL をビルドしてくれる。 musl ビルドをするのでいれておく。
cargo add openssl --features=vendored
main.rs
cargo lambda と reqwest するサンプルコード
GET リクエストして取得した JSON を Lambda のレスポンスに入れて返す。一応シリアライズしている。
次を参考
ビルド環境
Dockerfile を用意した。cargo lambda のビルドをするために cargo-lambda はもちろん、 Zig なども入れる必要がある。
また openssl クレートをビルドするために perl や gcc が必要なのでその辺も apt-get で準備している。
arm のためのクロスコンパイルのために aarch64-unknown-linux-musl
のターゲットも取得する。
ビルドのコマンド Docker内で cargo lambda を実行している。
出力される zip ファイルは "target/lambda/app/bootstrap.zip" に出力される。
CDK
あとは CDK で Lambda を作成する。 runtime
は Rust のようなバイナリの場合 lambda.Runtime.PROVIDED_AL2
を指定。 architecture
で lambda.Architecture.ARM_64
を指定する。
サンプルでは Lambda を API Gateway に紐づけている。
デプロイに成功すると
Outputs:
cargo-lambda-stack.cargolambdaapigatewayEndpoint00000000 = https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/main/
というように コマンドライン上にも設定した API Gateway の endpoint が表示される。AWS Console でも確認はできる。
API Gateway > API > "cargo-lambda-api-gateway (サンプル通りなら)" > ステージ(右側のペイン) > main > / > GET
root に lambda を紐づけているので
curl https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/main/
とするだけでアクセスできるはず。正常に動いていれば ソースコードのコメントにあるような JSON が返ってくるはず。
ちなみに API Gateway に curl して
{"message":"Missing Authentication Token"}
と返ってきたならエンドポイントが違っているかもしれない。
まとめ
Rust で高速・省メモリなプログラムを書き、arm64 で高速・省コストな Lambda を動かす。
至高の Lambda を作ってしまった。
Discussion