はじめに

表題の通りです。
SAM CLIからカスタムランタイムを使ってLambdaをデプロイの設定情報を作っていたのですが、ImageとZipどちらがいいのかわからずどちらも試しました。
今後どちらも選択的に使えるようにまとめておきます。

Zip

構成

lambda_rust
  ├──.aws-sam
  ├──samconfig.yaml
  ├──stock_data
  |  ├──Cargo.lock
  |  ├──Cargo.toml
  |  ├──Makefile
  |  └──src/main.rs
  └──template.yaml

設定

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample rust application for Lambda

Resources:
  HelloRustFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloRust
      Role: arn:aws:iam::{Lambdaを実行するロール}
      PackageType: Zip
      CodeUri: ./stock_data
      Runtime: provided.al2 # Amazon Linux 2
      Handler: bootstrap.is.real.handler
    Metadata:
      BuildMethod: makefile
build-HelloRustFunction:
    cargo build --release --target x86_64-unknown-linux-musl

    # バイナリをbootstrapにして、Artifacts Directoryに格納する
    # Current Artifacts Directory : /workspace/stock_data/.aws-sam/build/HelloRustFunction
    cp ./target/x86_64-unknown-linux-musl/release/hello /workspace/stock_data/.aws-sam/build/HelloRustFunction/bootstrap
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "{ストック名}"
s3_bucket = "{デプロイする先のS3バケット名}"
region = "ap-northeast-1"
confirm_changeset = false
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
[package]
name = "stock_data"
version = "0.1.0"
authors = ["***** <****@****>"]
edition = "2018"

[dependencies]
lambda_runtime = "0.4"
lambda_http = "0.4.0"
serde_json = "1.0.59"
tokio = "1.11.0"

[[bin]]
name = "hello"
path = "src/main.rs"
use lambda_runtime::{handler_fn, Context, Error};
use serde_json::{json, Value};

// エントリポイント
// Lambda特有のものを集約させる
#[tokio::main]
async fn main() -> Result<(), Error> {
    let func = handler_fn(my_handler);
    lambda_runtime::run(func).await?;
    Ok(())
}

async fn my_handler(event: Value, _: Context) -> Result<Value, Error> {
    let first_name = event["firstName"].as_str().unwrap_or("world");

    Ok(json!({ "message": format!("Hello, {}!", first_name) }))
}

#[cfg(test)]
mod tests {
    use super::*;

    //async関数は#[test]では使用できない
    //#[test]
    #[tokio::test]
    async fn my_handler_response() -> Result<(), Error> {
        let event = json!({
            "firstName": "AWS Lambda on Rust"
        });
        let json = json!({
            "message": "Hello, AWS Lambda on Rust!",
        });
        let response = my_handler(event, Context::default()).await?;
        assert_eq!(response, json);
        Ok(())
    }
}

参考情報

AWS公式ブログがRust Runtime for AWSで書いています。makefileは使われていません。

こちらの資料、長いですが、219ページ目あたりからの方がブログより参考になりそう

かなり参考にさせていただきました。makefileを利用し、かつ複数関数のデプロイが行われています。

Image

構成

lambda_rust
  ├──.aws-sam
  ├──samconfig.yaml
  ├──stock_data
  |  ├──Cargo.lock
  |  ├──Cargo.toml
  |  ├──Dockerfile # Zipとの相違点
  |  └──src/main.rs
  └──template.yaml

設定

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample rust application for Lambda

Resources:
  HelloRustFunctionImage:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloRustImage
      Role: arn:aws:iam::{Lambdaを実行するロール}
      MemorySize: 512
      CodeUri: ./stock_data             # Zipとの相違点
      PackageType: Image                   # Zipとの相違点
      #Runtime: provided.al2      # Zipとの相違点
      #Handler: bootstrap.is.real.handler # Zipとの相違点
    Metadata:
      Dockerfile: Dockerfile           # Zipとの相違点
      DockerContext: ./stock_data # Zipとの相違点
      DockerTag: v1                             # Zipとの相違点
FROM rust:latest as build-image

WORKDIR /rust/stock_data
COPY src/ /rust/stock_data/src/
COPY Cargo.toml Cargo.lock /rust/stock_data/

RUN rustup update && \
    rustup target add x86_64-unknown-linux-musl
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM public.ecr.aws/lambda/provided:al2

# 実行ファイルを起動するようにするため、ファイル名を "bootstrap" に変更する
COPY  --from=build-image /rust/stock_data/target/x86_64-unknown-linux-musl/release/hello ${LAMBDA_RUNTIME_DIR}/bootstrap

# カスタムランタイムはハンドラ名利用しないため、適当な文字列を指定する。
CMD [ "lambda-handler" ]
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "{ストック名}"
s3_bucket = "{デプロイする先のS3バケット名}"
image_repository = "{ImageをpushするECRのリポジトリ}" # Zipとの相違点
region = "ap-northeast-1"
confirm_changeset = false
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
# Zipと相違ないため略
// Zipと相違ないため略

参考情報

情報収集していて、Lambda+Rust+Imageでのデプロイは少ないように感じました。

一番参考にしたのは、AWS Toolkit for Visual Studio Codeのgo-imageのテンプレートでした。
VS CodeでコマンドではなくToolkitを使ってLambda関数を作成するとテンプレートとしてサンプルのhelloworldが生成されます。以下はそのテンプレートのgithubソースです。ビルドファイルをアップする必要があるRustにおいて、同じくビルドファイルを作成するGolangのtemplate.yamlやDockerfile書き方は非常に参考になりました。

プログラムビルドとビルドファイルを埋め込んだImageの作成を分けられていますが、RustでImageデプロイしている貴重な情報。

Lambdaのカスタムランタイム イメージの構成や環境変数まわりの確認に利用

余談

実は、これを試す前はDockerfileでかけるImageの方がデプロイ環境が把握しやすいのでImage派でした。
Zipを試してみたきっかけは、コンソールでソースが見れるのはZipという表示を見かけたからです。

スクリーンショット 2021-09-09 14.28.53.png
スクリーンショット 2021-09-09 14.29.23.png

おわりに

Zipでやりたかったコンソール上でのソースコードは見れませんでしたが、今後もZipで進めようと思います。
理由としては、Imageの場合(私の手順の場合)、Cargo build用にコンテナを立ちあげてデプロイする手順がありますが、私はVSCodeからコンテナに接続しその中でSAMを入れています。SAM実行にてさらにコンテナの中でコンテナが起動してCargo buildし、さらにもう一つコンテナを立ち上げてビルドファイルをコピーするという、SAMを実行しているコンテナと合わせて4つ同時にコンテナが起動します。実行時MacBookAirが数回死にました。
また、Zip手順ではsam buildを実行するとSAMを入れている環境、つまり私の場合だと開発環境のコンテナ内でCargo buildが行われますが、Imageでは、「SAM実行にてさらにコンテナの中でコンテナが起動してCargo build」の手順と完全に同じ事をしているに、コンテナが1つ余計に立ち上がるというデメリットしかないです。
もちろんその部分をMakefileに移し、最終的なビルドファイルの処理だけを切り替えればこれらのデメリットは無くなると思いますが、あまりにPCが死に過ぎてもうImageを試す気になれないのでZipで行こうと思います。
もう少しカスタムランタイム の中に持ち込みたい素材が増えてきたら変わってくる気がしますが、それまではZipで行こうと思います。

广告
将在 10 秒后关闭
bannerAds