Serverless FrameworkでAWS Lambdaファンクションをデプロイする(Rust版)

AWS LambdaのCustom Runtimesにより、様々な言語でLambdaファンクションを実装できるようになりました。個人的にはRustを使っていきたいと思っています(趣味です)。

RustでLambdaファンクションを実装するにあたり、Lambdaファンクションのデプロイの仕組みを整えておきたいところ。私の普段使いのデプロイツールはapexなのですが、apexは現時点でCustom Runtimesのデプロイには対応していません。このため、別のやり方としてServerless Frameworkを試してみました。

今回のエントリーではServerless Frameworkを使ってRustのLambdaファンクションをデプロイする方法をご紹介します。

目次

検証環境

  • macOS:Mojave(v10.14.2)
  • Rust:v1.31.0
  • Node.js:v11.6.0
  • npm:v6.5.0
  • AWS CLI:v1.16.80
  • Serverless Framework :v1.35.1
  • Docker Desktop Community:v2.0.0.0-mac81 DockerはRustプログラムのコンパイルで使用します。

前提

Serverless FrameworkのRustプラグインが公開されているのでこれを利用します。

テンプレートもいくつか用意されています。

今回はこれらのテンプレートを参考に、一から必要な設定ファイル等を作成していきます。

Lambdaファンクションは、DynamoDBからGetItemでデータを取得するサンプルプログラムを用意します。サンプルデータは以下のAWS公式ドキュメントのチュートリアルに付属のもの(moviedata.json)を利用します(※本ブログ記事ではDynamoDBのテーブル作成とデータロードについては触れません。必要に応じてチュートリアルの手順を参考にテーブル作成&データをロードしてください)。

新規プロジェクト(Rustのパッケージ)作成

はじめにcargo newで新規のRustプロジェクト(Rustのパッケージ)を作成します。

cargo new dynamodb-getitem-sample --bin

Cargo.tomlmain.rsが作成されます。

.
├── Cargo.toml
└── src
    └── main.rs

Serverless FrameworkとRustプラグインのインストール

プロジェクトディレクトリに、以下のようにpackage.jsonを作成します。

{
  "devDependencies": {
    "serverless": "1.35.1",
    "serverless-rust": "0.2.0"
  }
}

npm installserverlessserverless-rustをインストールします。

$ npm install

この時点でディレクトリ構成は以下のようになります。

.
├── Cargo.toml
├── node_modules
├── package-lock.json
├── package.json
└── src
    └── main.rs

Lambdaファンクションの作成

DynamoDBからGetItemでデータを取得するサンプルプログラムです。Rust用のAWS SDK(非公式)であるrusotoを使ってDynamoDBにアクセスします。

Cargo.tomlは以下のように設定します。Custom Runtimesを使用する場合、バイナリをbootstrapという名前にする必要がありますが、このあたりはServerless FrameworkのRustプラグインがよしなにやってくれるため、Cargo.tomlでバイナリ名を明示的に指定する必要はありません。

[package]
name = "dynamodb-getitem-sample"
version = "0.1.0"
authors = ["Yutaka Yawata"]
edition = "2018"

[dependencies]
lambda_runtime = "0.1"
log = "0.4.6"
env_logger = "0.6.0"
rusoto_core = "0.36.0"
rusoto_dynamodb = "0.36.0"
serde = "1.0.84"
serde_derive = "1.0.84"
serde_json = "1.0.34"
serde_dynamodb = { git = "https://github.com/mockersf/serde_dynamodb.git", rev = "79e3dd7765574dce64a283a3ffb32f45079100b4" }

Rustプログラムのコンパイル

今回利用するServerless FrameworkのRustプラグインでは、Dockerを使ってRustプログラムをコンパイルする作りになっています。このため、手元のMac上ではクロスコンパイルの環境を整える必要はありません。

ちなみにこのDockerイメージはlambci/docker-lambdatをベースにしています。

Serverless Frameworkの設定(serverless.yml)

新規にserverless.ymlを作成し、以下のように設定します。シンプルに1つのLambdaファンクションをデプロイする設定です。Lambdaファンクションに割り当てるIAMロールには、DynamoDBのGetItem権限を追加します。

service: serverlss-rust-sample
provider:
  name: aws
  runtime: rust
  memorySize: 128
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "dynamodb:GetItem"
      Resource:
        - "arn:aws:dynamodb:ap-northeast-1:*:table/Movies"
package:
  individually: true

plugins:
  - serverless-rust

functions:
  dynamodb-getitem-sample:
    handler: dynamodb-getitem-sample

runtimeにはrustを、pluginsserverless-rustを指定します。functionshandlerには、いずれもRustのパッケージ名(ここではdynamodb-getitem-sample)を指定します。

AWSのクレデンシャル

以下を参考に設定します。基本的にはAWS CLIのそれと同じものが使えますので、Serverless Framework用の特別な設定は不要です。

Lambdaファンクションのデプロイ

serverless deployを実行すると、Rustプログラムのコンパイル 〜 Lambdaファンクションのデプロイが実行されます。

$ AWS_PROFILE=development npx serverless deploy -conceal
Serverless: Building native Rust dynamodb-getitem-sample func...
    Finished release [optimized] target(s) in 4.87s                                                                                                                                                       
  adding: bootstrap (deflated 61%)
Serverless: Packaging service...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (2.34 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: serverless-rust-sample
stage: dev
region: ap-northeast-1
stack: serverless-rust-sample-dev
api keys:
  None
endpoints:
  None
functions:
  dynamodb-getitem-sample: serverless-rust-sample-dev-dynamodb-getitem-sample
layers:
  None

Lambdaファンクションの実行

serverless invokeでLambdaファンクションを実行してみます。

$ AWS_PROFILE=development npx serverless invoke -f dynamodb-getitem-sample
{
    "year": 2013,
    "title": "Rush",
    "info": {
        "plot": "A re-creation of the merciless 1970s rivalry between Formula One rivals James Hunt and Niki Lauda.",
        "rating": 8.3
    }
}

まとめ

Serverless FrameworkとそのRustプラグインを利用することで、シングルコマンドでRustプログラムのコンパイル 〜 Lambdaファンクションのデプロイまでを実行することができます。とても便利ですね。これからRust on AWS Lambdaをいろいろ試していきたいと思います。