はじめに
re:Invent 2023のセッション“Rustifying” serverless: Boost AWS Lambda performance with Rust (COM306) で紹介されていたサンプルアプリケーションをビルド&デプロイしてみました。
関連資料
当該セッションのビデオは以下から参照できます。
またセッション後に公開された以下のブログでも解説されています。
“Rustifying” Serverless: Boost AWS Lambda performance with Rust
今回扱うコードは以下のリポジトリにあります。
fun-with-serverless/rustifying-serverless
環境
この記事の手順は手元のMac Book Pro(M2) で試しました。
> uname -moprsv
Darwin 23.2.0 Darwin Kernel Version 23.2.0: Wed Nov 15 21:59:33 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T8112 arm64 arm
> docker -v
Docker version 24.0.5, build v24.0.5
> colima version
colima version 0.6.7
git commit: ba1be00
# colimaの設定
cpu: 4
disk: 60
memory: 8
arch: x86_64
runtime: docker
vmType: vz
rosetta: true
後述しますがx86アーキテクチャ向けにクロスビルドが必要になる関係でApple silicon上ではrosettaを有効にしておくことをおすすめします。
この記事でやること
この記事では以下の作業を行います。
- Dev Containerのビルド
- Python ネイティブモジュール(whlファイル)のビルド
- Lambda拡張のビルド&デプロイ
- AWS SAMアプリケーションのビルド&デプロイ
ビルドターゲット
上記のうち Python ネイティブモジュール(whlファイル)のビルドは実際は次の2段階になります。
- Rustのコードをネイティブ実行ファイルへビルドする
- Pythonのモジュールファイルを作る
上記のいずれもx86 Linuxをターゲットとして作業する必要があります。Apple silicon上でこれを実現するためにいろいろと試した結果、Rosettaを使った上で--platform=linux/amd64
を指定してビルドしたDevContainerのイメージを使うのが一番簡単でした。
早見表
上記のすべてに関連するファイルやコマンドの早見表です。
やること | 対象のファイル | 成果物 | コマンド |
---|---|---|---|
Dockerfileの変更(platformの指定) | .devcontainer/Dockerfile | 開発環境のコンテナイメージ | VSCodeのパレットで「Dev Containers: Rebuild Container」を実行する |
Rustの開発ツールをpoetryでインストールする | N/A | N/A | poetry install --only=rust-dev-tools |
Pythonネイティブモジュール(whl)をビルドする | s3-ops-rust-lib/ | .rust-lib/s3_ops_rust-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | poe build-lib |
Lambdaエクステンションをビルド&デプロイする | analytics-extension/ | Lambda エクステンションがAWS上に作成される ARNの例: arn:aws:lambda:ap-northeast-1:12345678:layer:analytics-extension:1 |
poe build-and-deploy-extension |
AWS SAM テンプレートのエクステンションのARNを書き換える | s3-admin-app/template.yml | s3-admin-app/template.yml | ファイルの以下を書き換え Globals -> Function -> Layers |
AWS SAM でアプリケーションをデプロイする | s3-admin-app | AWSリソース(API Gateway、DynamoDB、Lambda関数) | poe build-and-deploy-app |
環境構築
イメージビルド
早速やっていきます。サンプルのリポジトリにはDev Containerの設定が含まれています。
前述の通りDockerfileのFROM
にプラットフォームを指定します。
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/rust:latest
VSCodeだとパレットから「Dev Containers: Rebuild Container」を実行するとコンテナのビルドが行えます(・・・とても時間がかかります)
AWSクレデンシャル
AWSリソースを作成するのでクレデンシャルが必要です。 私はaws-vaultで一時クレデンシャルを設定する環境変数を生成、シェルスクリプト化してシェルにロードしました。
追加のツール
コンテナがビルドできたらpoetでRustのツールをインストールします。
poetry install --only=rust-dev-tools
Pythonモジュールのビルド
準備できたのでビルドしていきます。Python モジュールをビルドするには以下のコマンドを実行します。poeはpoetryにタスクランナー機能を追加するプラグインです。
poe build-lib
完了すると以下のパスにwhlファイルが作成されます。
.rust-lib/s3_ops_rust-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
CPUアーキテクチャとOS名がx86、Linuxになっていることを確認します。
Lambda 拡張のビルド
次はLambda拡張です。
poe build-and-deploy-extension
次のようにARNが出力されるのでメモしておきます。
"vscode ➜ /workspaces/rustifying-serverless (main) $ poe build-and-deploy-extension
Poe => cargo lambda build --manifest-path analytics-extension/Cargo.toml --extension --release
Finished release [optimized] target(s) in 0.39s
Poe => cargo lambda deploy --manifest-path analytics-extension/Cargo.toml --extension
🔍 extension arn: arn:aws:lambda:ap-northeast-1:1234567890000:layer:analytics-extension:7"
Appのビルド&デプロイ
いよいよアプリケーションをビルド&デプロイします。 まずはSAMテンプレートを書き換えます。template.yamlの以下の部分に先ほどのエクステンションのARNを指定します。
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Manage your S3 buckets
Globals:
Function:
Timeout: 10
Layers:
- arn:aws:lambda:ap-northeast-1:1234567890000:layer:analytics-extension:7
Environment:
Variables:
ANALYTICS_SQS_URL: !Ref AnalyticsSQS
以下のコマンドを実行するとSAM CLIによるデプロイが開始されます。
poe build-and-deploy-app
以下のリソースが作成されています。
- Lambda関数 × 5
- DynamoDBテーブル
s3-admin-UsersTable-*
- API Gateway × 2
API Gateway 2つあるけど?
API Gatewayが2つ作成されていますが、それぞれ以下のような構成になっています。
- API Gateway 1(Prd, Stage)
- GET /buckets-rust
- GET /get-bucket
- API Gateway 2 (Prd, Stage)
- GET /buckets/python
動作確認
ユーザーの作成
Authorizerが参照するユーザーテーブル s3-admin-UsersTable-*
に検証用のユーザーを追加します。
今回の以下のようなレコードを追加します。
{
"user": {
"S": "user"
},
"password": {
"S": "password"
}
}
APIの実行
作成したユーザー名とパスワードを指定します。
curl -s -uuser:password https://myapi.execute-api.ap-northeast-1.amazonaws.com/Prod/buckets-rust | jq .
[
[
"aws-athena-query-results-1234567890000-ap-northeast-1",
"ap-northeast-1"
],
[
"cloudtrail-ap-southeast-1-1234567890000",
"ap-southeast-1"
]
]
実行時間の比較
簡単にPythonとRustの実行時間を比較してみます。
Python
time curl -s -uuser:password https://xxx.execute-api.ap-northeast-1.amazonaws.com/Stage/buckets-python -o /dev/null
________________________________________________________
Executed in 2.87 secs fish external
usr time 17.37 millis 0.14 millis 17.23 millis
sys time 13.31 millis 1.80 millis 11.52 millis
Rust
time curl -s -o /dev/null -uuser:password https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/buckets-rust
________________________________________________________
Executed in 919.64 millis fish external
usr time 27.33 millis 11.87 millis 15.46 millis
sys time 15.10 millis 3.89 millis 11.21 millis
まとめ
COM306のサンプルアプリをビルド&デプロイしてみました。