12
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS LambdaでRustがGAになったので試してみる

12
Last updated at Posted at 2025-12-02

はじめに

2025年11月14日、AWS LambdaでRustのサポートがGA(General Availability)になりました。
これまでは「experimental」として扱われていましたが、今回の発表で正式にAWS SupportとLambda SLAの対象となりました。

この記事では、RustでLambda関数を作成してデプロイするまでの流れを実際に試してみます。

開発環境は以下の通りです。

  • M2 Mac
  • zsh
  • Rust 1.91.1

必要なツール

RustでLambda関数を開発するために、以下のツールを使用します。

Rust

まだRustをインストールしていない場合は、rustupを使ってインストールします。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Cargo Lambda

Cargo Lambdaは、RustでLambda関数をビルド・デプロイするためのCargoの拡張ツールです。
AWSも公式にこのツールの使用を推奨しています。

macOSの場合はHomebrewでインストールできます。

brew tap cargo-lambda/cargo-lambda
brew install cargo-lambda

インストール後、バージョンを確認しておきます。

$ cargo lambda --version
cargo-lambda 1.8.6 (345c38a 2025-07-18Z)

Lambda関数を作成する

プロジェクトの作成

cargo lambda newコマンドで新しいプロジェクトを作成します。

$ cargo lambda new hello-kane8n-cargo-lambda
> Is this function an HTTP function? No
> Event type that this function receives 
$

HTTP関数にするかどうかを聞かれますが、今回はシンプルな関数を作成するのでNoを選択します。
その後にイベントタイプも聞かれますが、今回は簡単なサンプルプログラムを実行するだけなので空のままEnterキーを押します。

作成されたプロジェクトの構成は以下の通りです。

$ tree hello-kane8n-cargo-lambda/
hello-kane8n-cargo-lambda/
├── Cargo.toml
├── README.md
└── src
    ├── generic_handler.rs
    └── main.rs

2 directories, 4 files

生成されたコードの確認

Cargo.tomlを確認してみます。

Cargo.toml
[package]
name = "hello-kane8n-cargo-lambda"
version = "0.1.0"
edition = "2021"

[dependencies]

lambda_runtime = "1.0.1"
serde = "1"
tokio = { version = "1", features = ["macros"] }

lambda_runtimeクレートがLambdaのランタイムを提供し、非同期処理にはtokioが使われています。

次にsrc/main.rsを確認します。

src/main.rs
use lambda_runtime::{run, service_fn, tracing, Error};
mod generic_handler;
use generic_handler::function_handler;

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing::init_default_subscriber();

    run(service_fn(function_handler)).await
}

main関数では、generic_handlerモジュールのfunction_handler関数をLambdaのエントリーポイントとして登録しています。

次にsrc/generic_handler.rsを確認します。

src/generic_handler.rs
use lambda_runtime::{Error, LambdaEvent};
use serde::{Deserialize, Serialize};

/// This is a made-up example. Incoming messages come into the runtime as unicode
/// strings in json format, which can map to any structure that implements `serde::Deserialize`
/// The runtime pays no attention to the contents of the incoming message payload.
#[derive(Deserialize)]
pub(crate) struct IncomingMessage {
    command: String,
}

/// This is a made-up example of what an outgoing message structure may look like.
/// There is no restriction on what it can be. The runtime requires responses
/// to be serialized into json. The runtime pays no attention
/// to the contents of the outgoing message payload.
#[derive(Serialize)]
pub(crate) struct OutgoingMessage {
    req_id: String,
    msg: String,
}

/// This is the main body for the function.
/// Write your code inside it.
/// There are some code example in the following URLs:
/// - https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples
/// - https://github.com/aws-samples/serverless-rust-demo/
pub(crate) async fn function_handler(event: LambdaEvent<IncomingMessage>) -> Result<OutgoingMessage, Error> {
    // Extract some useful info from the request
    let command = event.payload.command;

    // Prepare the outgoing message
    let resp = OutgoingMessage {
        req_id: event.context.request_id,
        msg: format!("Command {}.", command),
    };

    // Return `OutgoingMessage` (it will be serialized to JSON automatically by the runtime)
    Ok(resp)
}

#[cfg(test)]
mod tests {
    use super::*;
    use lambda_runtime::{Context, LambdaEvent};

    #[tokio::test]
    async fn test_generic_handler() {
        let event = LambdaEvent::new(IncomingMessage { command: "test".to_string() }, Context::default());
        let response = function_handler(event).await.unwrap();
        assert_eq!(response.msg, "Command test.");
    }
}

このコードは、IncomingMessage構造体を受け取り、OutgoingMessage構造体を返すシンプルなLambda関数の例です。
テストコードも含まれています。

コードのカスタマイズ

せっかくなので少しカスタマイズして、挨拶を返す関数にしてみます。
src/generic_handler.rsfunction_handlerの内容を以下のように変更します。

src/generic_handler.rs
pub(crate) async fn function_handler(event: LambdaEvent<IncomingMessage>) -> Result<OutgoingMessage, Error> {
    // Extract some useful info from the request
    let command = event.payload.command;

    // Prepare the outgoing message
    let resp = OutgoingMessage {
        req_id: event.context.request_id,
        msg: format!("Hello!! Rust Lambda!! Command: {}.", command),
    };

    // Return `OutgoingMessage` (it will be serialized to JSON automatically by the runtime)
    Ok(resp)
}

ローカルでテストする

Cargo Lambdaにはローカルでテストするための機能が備わっています。

まず、別のターミナルでLambdaをローカルで起動します。

[~/hello-kane8n-cargo-lambda] $ cargo lambda watch
 INFO starting Runtime server runtime_addr=[::]:9000
 INFO starting lambda function function="_" manifest=Some("Cargo.toml") cmd=Exec { prog: "/Users/kane8n/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo", args: ["run", "--color", "auto", "--manifest-path", "Cargo.toml"] }
   Compiling hello-kane8n-cargo-lambda v0.1.0 (/Users/kane8n/hello-kane8n-cargo-lambda)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.67s
     Running `target/debug/hello-kane8n-cargo-lambda`

次に、別のターミナルからリクエストを送信してテストします。

$ cargo lambda invoke --data-ascii '{"command": "test"}'
{"req_id":"ef3f35c2-c811-4388-927b-084fb4ef29e3","msg":"Hello!! Rust Lambda!! Command: test."}

正しくレスポンスが返ってきました!

ビルドとデプロイ

ビルド

Lambda用にビルドするにはcargo lambda buildコマンドを使用します。
--releaseフラグを付けて最適化されたバイナリを生成します。

[~/hello-kane8n-cargo-lambda] $ cargo lambda build --release
▪▪▪▪▪ Target component installed                                                                                                                                                                                                                                                                                                                        
   Compiling proc-macro2 v1.0.103
~ 省略 ~
   Compiling hello-kane8n-cargo-lambda v0.1.0 (/Users/kane8n/hello-kane8n-cargo-lambda)
    Finished `release` profile [optimized] target(s) in 16.82s

ビルドが完了すると、target/lambda/hello-kane8n-cargo-lambda/にbootstrapファイルが生成されます。

[~/hello-kane8n-cargo-lambda] $ ll target/lambda/hello-kane8n-cargo-lambda 
total 3928
-rwxr-xr-x  1 kane8n  staff  2009096 12  2 15:13 bootstrap

バイナリサイズは約2MBです。

デプロイ

AWS Profileが設定されていれば、cargo lambda deployコマンドでデプロイできます。

[~/hello-kane8n-cargo-lambda] $ cargo lambda deploy
✅ function deployed successfully 🎉
🛠️  binary last compiled 6 minutes ago
🔍 arn: arn:aws:lambda:ap-northeast-1:111111111111:function:hello-kane8n-cargo-lambda
🎭 version: 1

デプロイが完了したら、AWSコンソールまたはAWS CLIからテストできます。

[~/hello-kane8n-cargo-lambda] $ aws lambda invoke --function-name hello-kane8n-cargo-lambda --payload '{"command": "test"}' --cli-binary-format raw-in-base64-out output.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
[~/hello-kane8n-cargo-lambda] $ 
[~/hello-kane8n-cargo-lambda] $ cat output.json          
{"req_id":"d5bd93a6-a305-4ebc-b702-7fc6fa1c2305","msg":"Hello!! Rust Lambda!! Command: test."}%

実際にAWSコンソール上ではどう見えるかも確認してみます。

関数が作成されてる
AWSコンソール上のLambda関数の見え方

explorerを確認する感じだと、zipファイルとしてアップロードされているようです。
ランタイムは Amazon Linux 2023 になっています。

実際に試してみて、Cargo Lambdaを使うと非常にスムーズにRustのLambda関数を開発・デプロイできることが分かりました。
ここからは筆者がRustがGAになったという記事を見て、気になった点について書いていきます。

Container Imageを使う場合との違い

今回紹介した方法は、Cargo Lambdaを使ってzipファイルとしてデプロイする方法です。
一方で、Rustの実行バイナリを含んだContainer Imageを使ってLambdaをデプロイする方法もあります。

両者の比較

項目 zip(Cargo Lambda) Container Image
デプロイサイズ 小さい(数MB程度) 大きい(数十MB〜数百MB)
コールドスタート 速い 遅い傾向
カスタマイズ性 Lambda環境に依存 OSレベルからカスタマイズ可能
ローカルテスト Cargo Lambdaで簡単 Dockerで実行可能
依存ライブラリ パッケージ同梱またはLayer経由で追加可能(展開後250MB制限あり) 自由に追加可能(10GB制限)
ビルドパイプライン シンプル Dockerfileの管理が必要

どちらを選ぶべきか

  • zip(Cargo Lambda)がおすすめの場合

    • 依存関係がシンプルなLambda関数
    • コールドスタートを最小限にしたい場合
    • シンプルなCI/CDパイプラインを維持したい場合
  • Container Imageがおすすめの場合

    • 特定のシステムライブラリやツールが必要な場合
    • 既存のDockerベースのワークフローがある場合
    • Lambda以外の環境でも同じイメージを使いたい場合

Container ImageでのRust実行とSLAについて

LambdaでContainer Imageを使ってRustを実行すること自体は、以前から可能でした。

以前のContainer Image方式の位置づけ

Container Imageを使ったカスタムランタイム実行は、Lambdaサービスの可用性(99.95%)についてはSLAの対象でした。
ただし、Lambdaサービスとしての可用性は保証されていたものの、Rustランタイム自体の動作に関するAWSサポートは受けられませんでした。

つまり、以前は以下のような状況でした。

  • Lambdaサービスの可用性:SLA対象
  • Rustランタイムの動作:「experimental」としてAWSサポート対象外
  • 問題発生時のサポート:Lambdaサービス側の問題のみ対応可能

今回のGAで変わったこと

2025年11月のGA発表により、Rustランタイム自体がAWS Supportの対象となりました。

これにより以下が変わりました。

  • lambda_runtimeクレートを使用したRust Lambda関数の動作がAWSサポートの対象に
  • 問題発生時にAWSサポートによる対応が受けられる
  • Rustランタイム起因の問題もサポートチケットで対応可能

重要な点として、このサポートはlambda_runtimeクレートを使用した実装に対して適用されます。
Container Imageを使う場合でも、lambda_runtimeクレートを使って正しく実装されていれば、同様にサポートの対象となります。

CI/CDについて

ここまでの手順ではローカル環境からデプロイしましたが、実際のプロジェクトではCI/CDパイプラインを構築することが多いでしょう。
ここではGitHub Actionsを使ったCI/CDの例を紹介します。

GitHub Actionsでのデプロイ

GitHub Actionsでは、Cargo Lambdaを使ってビルドとデプロイを自動化できます。

以下は.github/workflows/deploy.ymlの例です。

.github/workflows/deploy.yml
name: Deploy Lambda

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Install Zig
        uses: mlugg/setup-zig@v1
        with:
          version: 0.13.0

      - name: Install Cargo Lambda
        uses: jaxxstorm/action-install-gh-release@v1
        with:
          repo: cargo-lambda/cargo-lambda
          platform: linux
          arch: x86_64

      - name: Build
        run: cargo lambda build --release

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Deploy
        run: cargo lambda deploy

このワークフローでは以下のことを行っています。

  1. Rustのセットアップ
  2. Zigのインストール(Cargo Lambdaがクロスコンパイルに使用)
  3. Cargo Lambdaのインストール
  4. Lambda関数のビルド
  5. AWS認証情報の設定
  6. Lambda関数のデプロイ

AWS認証情報はGitHubのSecretsにAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを設定しておく必要があります。
より安全な方法としては、OIDC(OpenID Connect)を使ってIAMロールを引き受ける方法もあります。

既存のCloudFormation管理環境との統合

多くのプロジェクトでは、既にLambda関数をCloudFormationやSAMで管理しており、Container ImageをビルドしてECRにプッシュする運用が確立されていることがあります。

このような環境でCargo Lambdaを採用する場合、Cargo Lambdaはビルドのみを行い、デプロイはCloudFormationに任せる構成にする必要があります。
つまり、既存のECRベースのビルドパイプラインとは別に、Cargo Lambda用のビルドパイプラインを構築することになります。

以下は、Cargo Lambdaでビルドしたzipファイルをs3にアップロードし、CloudFormationでデプロイするワークフローの例です。

.github/workflows/deploy.yml
name: Build and Deploy via CloudFormation

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Install Zig
        uses: mlugg/setup-zig@v1
        with:
          version: 0.13.0

      - name: Install Cargo Lambda
        uses: jaxxstorm/action-install-gh-release@v1
        with:
          repo: cargo-lambda/cargo-lambda
          platform: linux
          arch: x86_64

      - name: Build
        run: cargo lambda build --release --output-format zip

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Upload to S3
        run: |
          aws s3 cp target/lambda/hello-kane8n-cargo-lambda/bootstrap.zip \
            s3://my-lambda-bucket/hello-kane8n-cargo-lambda/${{ github.sha }}.zip

      - name: Deploy CloudFormation
        run: |
          aws cloudformation deploy \
            --template-file template.yaml \
            --stack-name my-lambda-stack \
            --parameter-overrides LambdaCodeVersion=${{ github.sha }}

CloudFormationテンプレートでは、S3からzipファイルを参照します。

template.yaml
Parameters:
  LambdaCodeVersion:
    Type: String

Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: hello-kane8n-cargo-lambda
      Runtime: provided.al2023
      Handler: bootstrap
      Code:
        S3Bucket: my-lambda-bucket
        S3Key: !Sub "hello-kane8n-cargo-lambda/${LambdaCodeVersion}.zip"
      # ... その他の設定

既存のContainer Image + ECR方式と比較すると、S3バケットの管理が追加で必要になりますが、デプロイサイズが小さくなりコールドスタートの改善が期待できます。

まとめ

AWS LambdaでRustが正式にサポートされたことで、高パフォーマンスで安全なサーバーレス関数をRustで開発できるようになりました。
Cargo Lambdaを使えば、開発からデプロイまでスムーズに行うことができます。

特に以下のような場面でRust Lambdaは威力を発揮するでしょう。

  • 高速な処理が求められる場面
  • メモリ効率が重要な場面
  • 型安全性を重視したい場面

ぜひRustでのLambda開発を試してみてください!

参考

12
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?