👻

RustでAWS Lambda関数を作る(WSL2編)

2021/03/25に公開

actix-webでWebアプリケーションを作成しようと思ったのですが、認証にOpenID Connect使ったりとか色々な要素を盛り込んでみようとするととたんに大変になってしまいました。

特にOpenID Connectの認証でreqwest使ってたりして非同期関係でTokio使われたりしてるとなんかよくわからないエラーで疲弊します(´・ω・`)
(たぶん非同期ランタイムが違うせいなのでしょうが・・・)

そんなわけですっきり行けるようにいっその事、APIサーバならAWSのAPI GatewayとLambdaだろと思ってAWS Lambda関数を作ってみることにしました。

前提

  • Windows OSでの開発をする
  • Rustの開発環境は準備済み前提
  • たぶんよそで出ている情報みたいなもん。
  • 初心者あるあるだと思うのでスゴイ情報は何もなし。

開発準備

Docker Desktop設定

設定ダイアログ

こんな感じにWSL2上でDockerを使えるように設定しておきます

Crossのインストール

Windowsで開発する場合、AWS Lambda用にクロスコンパイルします。
その為にCrossをインストールします。
今回はWSL2でクロスコンパイルするため、WSL2側にもRustをインストールしておきます。

インストール手順については割愛します(再検証するの面倒になりました・・・)

ソースコード

元ネタはRust Runtime for AWS Lambdaなのですがバージョンが古いせいかそのままでは動きませんでした。

lambda_runtimeのページも参照しながら適当改変しています。(動作も元ネタとちょっと違います)

Cargo.toml

[package]
name = "test-lambda"
version = "0.1.0"
authors = ["XXXXX <xxxxx@example.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambda_runtime = "0.3.0"
log = "0.4.14"
serde = "1.0.124"
serde_derive = "1.0.124"
serde_json = "1.0.64"
simple_logger = "1.11.0"
tokio = { version="1.4.0", features = ["full"] }

[[bin]]
name = "bootstrap"
path = "src/main.rs"

main.rs

use lambda_runtime::{handler_fn, Context, Error};
use log::LevelFilter;
use serde_derive::{Deserialize, Serialize};
use simple_logger::SimpleLogger;

#[derive(Deserialize, Clone)]
struct CustomEvent {
    #[serde(rename = "firstName")]
    first_name: String,
}

#[derive(Serialize, Clone)]
struct CustomOutput {
    message: String,
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    SimpleLogger::new()
        .with_level(LevelFilter::Info)
        .init()
        .unwrap();
    let func = handler_fn( move |e, c| {
        log::info!("lambda start");
        my_handler(e, c)
    });
    lambda_runtime::run(func).await?;


    Ok(())
}

async fn my_handler(e: CustomEvent, _: Context) -> Result<CustomOutput, Error> {
    if e.first_name == "" {
        Err(Error::from("空白は許しませんよ!"))
    } else {
        Ok(CustomOutput {
            message: format!("Hello, {}!", e.first_name),
        })
    }
}

ビルドとアップロード準備

WSL2側で作業をします。
Crossを使い x86_64-unknown-linux-musl をターゲットにしてビルドします。
その後、zipコマンドで圧縮します。このファイルをアップロードすることになります。

$ cross build --release --target x86_64-unknown-linux-musl
 ~省略~
   Compiling test-lambda v0.1.0 (/project)
    Finished release [optimized] target(s) in 3m 13s
$ cd target/x86_64-unknown-linux-musl/release/    
$ zip -j bootstrap.zip bootstrap
updating: bootstrap (deflated 70%)

今回は関係ないですが、OpenSSLなどはそのままではコンパイルできないので注意してください。
rusttlsが使用可能であればそちらを使うとコンパイルできるかもしれません。(未確認)

また、zipファイル化する際に、Windowsのエクスプローラーの右クリックメニューでZIPファイルにした場合、AWSのLambda関数として登録しても実行できませんでした。いまいち理由がわかりませんが・・・

AWSでLambda関数を作成

AWSでLambda関数を作成します。
ポイントは二つです

  • ランタイムの設定は「Amazon Linux 2でユーザー独自のブートストラップを提供する」を選択する
  • コードソースを先に作ったzipファイルでアップロードする

ランタイム設定

アップロード

あとは・・・

パラメータを設定してテストをすると下記のように問題なく実行できると思います。

Discussion