TOP

Rust (axum) で作った API をコンテナ Lambda としてデプロイする

皆さんはRustで作ったAPIをどのようにデプロイしていますか?

シングルバイナリとしてデプロイすることも考えられますが、今回はあえてDockerコンテナを使い、簡単にLambdaにデプロイできることを確かめていきます。

使用技術 : Lambda Web Adapter

今回の肝となるのはLambda Web Adapterです。

これは、Dockerコンテナ上に作られたHTTP APIであれば何でも、Dockerfileに1行追加するだけでLambdaにデプロイできるようになるという技術です(LaravelをLambdaにデプロイした例もあります)。

これを使うことで、Lambdaのhandlerを意識しなくて良くなるため、Lambda以外のサーバー(ECSなど)への可搬性も格段に上がります。

もちろん、ローカルでの開発形態も変える必要がないため、導入コストが非常に低いです。

環境構築

全体像はこちらのリポジトリで確認できます。

以下では主なファイルについて見ていきます。

Cargo.toml

こちらはaxumのドキュメントをもとに作成しています。

[package]
name = "axum-lambda-deploy-sample"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.5"
tokio = { version = "1.40.0", features = ["full"] }
tower = "0.5.1"

main.rs

こちらもaxumのサンプルをもとに作成しています。

一点異なるのは、ポートを8080にしているところです。これはLambda Web Adapterがデフォルトでこのポートを要求するためです。

use axum::{routing::get, Router};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(|| async { "Hello, World!" }));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

Dockerfile

ここではマルチステージビルドを活用してイメージを作成していきます。

FROM rust:1.81.0-bookworm as builder
WORKDIR /app

COPY Cargo.toml Cargo.lock /app/
RUN mkdir src
RUN echo "fn main() {}" > src/main.rs
RUN cargo build --release
RUN rm -r src

COPY src /app/src
RUN cargo build --release

FROM gcr.io/distroless/cc-debian12
COPY --from=builder /app/target/release/axum-lambda-deploy-sample /app/
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
CMD ["/app/axum-lambda-deploy-sample"]

1つ目のイメージはRustの公式イメージで、こちらでリリースビルドを行います。

2つ目のイメージgcr.io/distroless/cc-debian12は、Googleが提供している超軽量イメージdistrolessです。

最後から2行目に

COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter

とありますが、ここでLambda Web Adapterを有効化しています。とても簡単ですね…!

Lambda にデプロイ

Docker イメージの準備

まずECRにaxum-lambda-deploy-sampleという名前のリポジトリを作成します。

ECRのリポジトリ

そして、コンソール画面でプッシュコマンドを確認し、上から順に実行します(実行にはAWSの認証情報も必要です)。

プッシュコマンド

なお、docker buildのときに以下のエラーが出ることがあります。

------
 > FROM public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4:
------
failed to load cache key: unexpected status code [manifests 0.8.4]: 403 Forbidden

その場合は、

aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws

を実行して再度やり直してください。

イメージがプッシュできていれば成功です。

ECRにプッシュされたイメージ

Lambda 関数の作成

次にLambda関数を作成していきます。

コンテナイメージを選択し、関数名はaxum-lambda-deploy-sample、コンテナイメージURIは上で作成したものを選択します。

ここでアーキテクチャはビルドしたマシンと同じものを選択してください。私はM1 Macなのでarm64としています。あるいはイメージビルド時に

docker build --platform linux/amd64 -t axum-lambda-deploy-sample .

とすると(ビルド時間はかなり伸びますが)x86_64でビルドできます。

コンテナLambdaの設定

関数を作成したら、次に関数URLを作成します。

以下の画面の関数URLを作成を押し、次の画面で認証タイプはNONEを選択し保存します。

関数URLの画面

API の実行

関数URLが発行されたら、これをブラウザやcurlで確認してみましょう。

うまくHello, World!と表示されましたか?

作成された関数URL

ハローワールド