M1 Mac で Rust 製 Lambda + SAM をどうにかして使えるようにした話
きっかけ
新しいもの好きである私は、今年 Rust を始めました。 The Rust Programming Language は初めて高級言語を触る人にもわかりやすく、とても良かったです。
仕事で新たにチームにジョインした新卒メンバーに AWS について講義を行いましたが、久々にサーバーレスアーキテクチャをフル活用したアプリケーションを作りたくなり、せっかくならば最近学んだ Rust を使ってみようと思ったのがきっかけです。
やってみた
もともと他の開発で AWS CLI と SAM や Docker は入っていたので、 公式ドキュメント をベースに簡単なチュートリアルを進めようと思っていました。正直、実装も発生しないため 30 分程度あれば終わるだろうと思って始めていましたが、m1 Mac を使っていたがゆえに、思わぬ問題にぶつかりました。
問題
sam build
と sam deploy --guided
を使い、 Lambda が無事にデプロイされましたが CLI の Output に表示されたエンドポイントへアクセスするとなんとインターナルサーバーエラーが返されてしまいました。エラーを見る限り、要求している GLIBC のバージョンが合わないようでした。
/var/task/bootstrap: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /var/task/bootstrap)
Go でも前に似たようなエラーに遭遇しており、このときは GOOS=linux GOARCH=amd64
を使ってビルドすることで解決したものの、 cargo
にはこのようなオプションが自分で調べる限りは見つけられず、かなり困りました。
このような問題は割と前から認知されていたようで、 awslabs/aws-lambda-rust-runtime#17 でも議論されていました。
解決策
The alternative is to build on a container that matches the lambda runtime.
結局上で上げた issue で解決するのがワークアラウンドで、devcontainer で解決しました。(厳密には VS Code の拡張機能の方を使っています)
{
"name": "Rust",
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
"mounts": [
{
"source": "${localEnv:HOME}/.aws",
"target": "/home/vscode/.aws",
"type": "bind"
}
],
"features": {
"ghcr.io/audacioustux/devcontainers/aws-sam-cli:1": {},
"ghcr.io/devcontainers/features/nix:1": {
"packages": "nixpkgs.cargo-lambda",
"useAttributePath": true
},
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
}
}
Rust をベースイメージとし、 SAM CLI、 AWS CLI、 Docker in Docker と Nix による cargo-lambda
を使うことで、環境を構築しました。また、 .aws
ディレクトリをマウントすることで、 AWS の認証情報を共有しました。
これによって、一度この構成でビルドしたイメージをベースに必要なアプリケーションがプリインストールされた状態で開発ができるようになりました。
おわり
PS: もっといい方法があれば教えてください 🙇♂️
Discussion
--use-container
でビルド用コンテナ内でビルドさせることができるらしい 🤩