Dartの関数をServerless Frameworkとカスタムランタイムを使用してAWS Lambdaにデプロイする
始めに
サーバーレスのコンピューティングサービスとしてとても人気のあるAWS Lambdaからは公式にDartのランタイムは提供されていませんが、代わりにカスタムランタイムの仕組みを利用してDartで作成した関数をAWS Lambdaへデプロイすることができます。
AWS LambdaにDartの関数をデプロイすることができれば、AWS Lambdaに登録したDartの関数をAmazon API Gatewayなどのサービスと連携してFlutterアプリでも活用することができ、その上コードベースもDartに統一することができ非常に便利です。
そこで、この記事では手短にDartの関数をAWS Lambdaへデプロイする方法を紹介します。
準備
この記事では作成したDart関数をAWS Lambdaへデプロイする際にServerless FrameworkとDocker Desktopを使用します。インストールしていない方は以下のコマンドやリンクからインストールを完了させてください。
また、AWSのサービスを使用する関係からAWSアカウントやアクセストークンが必要になります。
AWSアカウント
AWSの認証トークン
以下の記事で紹介されている方法でAWSの認証トークンを発行してください。
認証トークンを発行できたら以下のように環境変数に設定します。
export AWS_ACCESS_KEY_ID=xxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
Serverless Framework
brew install serverless
Docker Desktop
関数の実装と登録
ここからは実際にAWS LambdaへデプロイするDartの関数を実装していきます。
プロジェクト構成
今回は以下のような構成で進めていきます。Dockerfile
とserverless.yml
については後ほど紹介します。
.
├── Dockerfile
├── LICENSE
├── analysis_options.yaml
├── lib
│ ├── functions.dart
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
└── serverless.yml
パッケージのインストール
AWS Lambdaへデプロイする際に必要になるDartのカスタムランタイムはaws_lambda_dart_runtime_nsを使用します。以下のコマンドか手動でpubspec.yamlの依存性に追加してください。
dart pub add aws_lambda_dart_runtime_ns
dart pub get
以下のようにdependenciesにaws_lambda_dart_runtime_ns
が追加されていれば成功です。
name: sample
environment:
sdk: ^3.3.4
dependencies:
aws_lambda_dart_runtime_ns: ^0.0.13
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
AWS Lambdaへデプロイする関数の作成
AWS Lambdaへデプロイする簡単な関数を作成してみます。
ひとまず関数が呼び出されたら単純にHello, World!
という文字列を返す簡単な処理にします。
import 'package:aws_lambda_dart_runtime_ns/aws_lambda_dart_runtime_ns.dart';
FunctionHandler get sayHelloWorld {
return FunctionHandler(
name: 'hello-world', // 関数のユニークな名前
action: (context, event) { // asyncをつけて非同期にもできる
// ここでファイルの読み書きやDB操作等のあれこれをする
return InvocationResult(
requestId: context.requestId,
body: {
'message': 'Hello, World!',
},
);
},
);
}
簡単に説明しておくとFunctionHandler
というオブジェクトがAWS Lambda上で実行される関数を表しています。
FunctionHandler
のname
は関数(またはコマンド)が呼び出される際に必要な名前です。
また、この名前は後に紹介するserverless.yml
のfunctionsのコマンド定義と紐づいている必要があります。
FunctionHandler
のaction
には関数(またはコマンド)の実際の振る舞いを定義します。今回の例では単純にHello, World!
というメッセージを返しているだけですが、action
の中で必要なファイル操作やDB操作などの処理を行うことができます。
action
の中で返却が必要なInvocationResult
は処理の結果を表すオブジェクトです。InvocationResult
のbody
には任意のJSONデータを設定することができます。
作成した関数をカスタムランタイムに登録
先ほど作成したsayHelloWorld
関数をカスタムランタイムに登録してみましょう。とても簡単です。
import 'package:aws_lambda_dart_runtime_ns/aws_lambda_dart_runtime_ns.dart';
import 'package:sample/functions.dart' as fn;
Future<void> main(List<String> args) async {
await invokeAwsLambdaRuntime([
fn.sayHelloWorld, // 関数の登録
]);
}
作成した関数をカスタムランタイムに登録する際にすることは、invokeAwsLambdaRuntime
関数を呼び出してその引数に登録したい関数を渡すだけです。
ここまででAWS Lambdaに登録したい関数の作成とカスタムランタイムに登録する工程が終わりました。
AWS Lambdaへデプロイ
ここまで来たらあとはAWS Lambdaに作成したプログラムをデプロイするだけです。
以下のようにDockerfile
とserverless.yml
を定義していきます。
Dockerfile
FROM arm64v8/dart:latest as build-image
WORKDIR /work
COPY ./ ./
RUN dart pub get
RUN dart compile exe ./lib/main.dart -o ./bootstrap
RUN chmod +x bootstrap
FROM public.ecr.aws/lambda/provided:latest
COPY /work/bootstrap /var/runtime/
CMD ["dummyHandler"]
もしDartのプログラムを置いているフォルダ構成が異なる場合は上記./lib/main.dart
の部分を修正してください。
serverless.yml
service: sample-app
provider:
name: aws
runtime: provided
timeout: 30
region: ap-northeast-1
architecture: arm64
ecr:
images:
appImage:
path: ./
platform: linux/arm64
functions:
hello-world:
image:
name: appImage
command:
- hello-world
リージョンにこだわりは特にないのでとりあえずap-northeast-1 (東京)
にします。
functions
の定義だけ注意が必要で、command
の名前は先に定義したFunctionHandler
のname
と一致させるようにしてください。
デプロイ
ここまで設定したら以下のServerless FrameworkのコマンドでAWS Lambdaへ作成した関数をデプロイすることができます。
sls deploy
以下のような結果になれば成功です。
sls deploy
Running "serverless" from node_modules
(node:6460) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Deploying sample-app to stage dev (ap-northeast-1)
✔ Service deployed to stack sample-app-dev (32s)
functions:
hello-world: sample-app-dev-hello-world
デプロイされた関数の動作確認
AWS Lambdaにデプロイされた関数がちゃんと動くのかさっそく確認してみましょう。
AWS Lambdaのコンソールからデプロイした関数を選択して、画面中央の「テスト」タブからテスト実行してみてください。
以下のように実装した通りの値が返ってくれば成功です。
参考
この記事で作成したプロジェクトは以下のリポジトリで公開しているので、とりあえず手っ取り早く動かしてみたい方はクローンかフォークをしてからAWS Lambdaにデプロイして遊んでみてください。
Discussion