##はじめに
表題の通りです。
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という表示を見かけたからです。
Imageではソースをコンソール上からは見ることができない。
RustのZipをデプロイして、コンソールを確認してみました。
かなしい。
##おわりに
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で行こうと思います。