Rustで書いたAWS Lambda関数を簡単にデプロイ&実行する

2022.06.09

Introduction

以前、こんな記事を書いたのですが、
Rustでlambdaやる場合、クロスコンパイルしてzipつくってアップロードしたりとけっこう手間でした。
(↑ではcdk使ってるのでさらに面倒)

いまそのあたりがどうなっているのか調べたところ、
Cargo-Lambdaが最も楽とのことだったので、使ってみました。
Cargp LambdaはCargoのサブコマンドとして提供され、
Rust on AWS Lambdaをやるのに便利なコマンドを使うことができるとのことです。

Environment

  • OS : MacOS 10.15.7
  • rust : 1.61.0

※AWS Lambdaが使えるAWSアカウントとロールは設定済みと仮定

Setup

内部でzigつかってるのでzigをインストール。  

% brew install zig

cargo-lambdaはHomebrewでインストール可能です。

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

Lambda用のaarch64-unknown-linux-gnuツールチェインをrustupでインストールしておきます。

% rustup target add aarch64-unknown-linux-gnu

Try

Cargo Lambdaはプロジェクトの作成から実行・デプロイまでのサブコマンドを提供してくれます。
まずはnewでRust Lambdaプロジェクトを作成。

Lambdaパッケージの作成

% cargo lambda new my-function-1
? Is this function an HTTP function? (y/N)
[type `yes` if the Lambda function is triggered by an API Gateway, Amazon Load Balancer(ALB), or a Lambda URL]

### "cargo lambda new --http FUNCTION_NAME "でも同じように作成可能です。  
### funtion urlはパブリックなので注意

my-function-1は私がつけたlambdaのパッケージ名です。
newコマンドによってAWS Lambda on Rustの雛形を作成します。
また、プロジェクト作成時に↑で聞かれているように、
function urlを有効化した状態でLambda関数を作成することもできます。
(今回はyesを入力)

HTTP functionを使用しない場合(質問にNoとした場合)、
Lambdaが受け取るイベントタイプを選択できます。

ちなみに、newコマンド実行時に--templateオプションを使えば、独自のテンプレート構造を使用できます。

ビルド

プロジェクト作成後、すぐにbuildできます。

% cd my-function-1
% cargo lambda build --output-format zip
warning: `my-function-1` (bin "my-function-1") generated 2 warnings
    Finished dev [unoptimized + debuginfo] target(s) in 0.47s

% ls target/lambda/my-function-1/
bootstrap     bootstrap.zip

--output-format zipをつけると、ビルド後に
zip(Lambdaパッケージとしてアップロード可能な形式)も作ってくれます。
リリースモードでビルドしたい場合は--releaseでOKです。

% cargo lambda build --output-format zip --release

Watchコマンドでローカル実行

watchコマンドは、以前startと呼ばれていたコマンドとのことです。
このコマンドを使うことで、ローカルでLambdaのエミュレータサーバを起動することができます。

% cargo lambda watch
INFO cargo_lambda_watch: invoke server listening on 127.0.0.1:9000

エミュレーターサーバではfunction urlがサポートされているので、
http://127.0.0.1:9000/lambda-url/<関数名>
でアクセスすることができます。

今回であれば下記のようにcurlを実行します。

% curl -L http://127.0.0.1:9000/lambda-url/my-function-1
Hello AWS Lambda HTTP request

invokeで関数の実行

エミュレータサーバを実行した状態で、cargo lambda invokeコマンドを使って
Lambdaを実行することもできます。

ここにある内容をapigw-request.jsonという名前で保存し、
data-exampleオプションをつかって実行します。

% cargo lambda invoke my-function-1 --data-example apigw-request
{"statusCode":200,"headers":{"content-type":"text/html"},
"multiValueHeaders":{"content-type":["text/html"]},"body":"Hello AWS Lambda HTTP request","isBase64Encoded":false}

※なぜjsonを指定しないと動かないか不明

ちなみに、function urlを使わないLambdaのinvokeであれば、
jsonファイルを用意しなくてもinvokeできました。

デプロイ

ローカルで動作確認できたらデプロイします。
cargo lambda deployコマンドを使って、
iam roleのarnを指定すればデプロイ可能です。

% cargo lambda deploy --enable-function-url my-function-1 --iam-role <iamロールのArn> 
🔍 function arn: arn:aws:lambda:XXXXXXXXXXXXXXXXXXX
function url: https://somethingurl.lambda-url.us-east-1.on.aws/

デプロイ完了時、function urlが生成されてます。
生成されたURLにブラウザでアクセスすることが可能です。
※publicなので注意

invokeコマンドで--remoteオプションを使えば、本番環境のLambdaを実行できます。

% cargo lambda invoke --remote my-function-1 --data-example apigw-request
{"statusCode":200,"headers":{"content-type":"text/html"},
"multiValueHeaders":{"content-type":["text/html"]},"body":"Hello AWS Lambda HTTP request","isBase64Encoded":false}

Summary

今回はCargo Lambdaを使ってみました。
以前よりAWS Lambda on Rustを使うのがだいぶ簡単になってますね。

AWS Lambda on Rust with CDKの場合でも
こんなのがあるので、
こちらも試してみたいところです。

References