📦

Dartの関数をServerless Frameworkとカスタムランタイムを使用してAWS Lambdaにデプロイする

2024/05/08に公開

始めに

サーバーレスのコンピューティングサービスとしてとても人気のあるAWS Lambdaからは公式にDartのランタイムは提供されていませんが、代わりにカスタムランタイムの仕組みを利用してDartで作成した関数をAWS Lambdaへデプロイすることができます。

AWS LambdaDartの関数をデプロイすることができれば、AWS Lambdaに登録したDartの関数をAmazon API Gatewayなどのサービスと連携してFlutterアプリでも活用することができ、その上コードベースもDartに統一することができ非常に便利です。

そこで、この記事では手短にDartの関数をAWS Lambdaへデプロイする方法を紹介します。

https://aws.amazon.com/lambda/

準備

この記事では作成したDart関数をAWS Lambdaへデプロイする際にServerless FrameworkDocker Desktopを使用します。インストールしていない方は以下のコマンドやリンクからインストールを完了させてください。

また、AWSのサービスを使用する関係からAWSアカウントやアクセストークンが必要になります。

AWSアカウント

https://aws.amazon.com/jp/

AWSの認証トークン

以下の記事で紹介されている方法でAWSの認証トークンを発行してください。

https://qiita.com/ozaki25/items/034f7f8e8ad69adceea7

認証トークンを発行できたら以下のように環境変数に設定します。

export AWS_ACCESS_KEY_ID=xxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx

Serverless Framework

brew install serverless

https://www.serverless.com/

Docker Desktop

https://www.docker.com/products/docker-desktop/

関数の実装と登録

ここからは実際にAWS LambdaへデプロイするDartの関数を実装していきます。

プロジェクト構成

今回は以下のような構成で進めていきます。Dockerfileserverless.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の依存性に追加してください。

https://pub.dev/packages/aws_lambda_dart_runtime_ns

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上で実行される関数を表しています。

FunctionHandlernameは関数(またはコマンド)が呼び出される際に必要な名前です。
また、この名前は後に紹介するserverless.ymlのfunctionsのコマンド定義と紐づいている必要があります。

FunctionHandleractionには関数(またはコマンド)の実際の振る舞いを定義します。今回の例では単純にHello, World!というメッセージを返しているだけですが、actionの中で必要なファイル操作やDB操作などの処理を行うことができます。

actionの中で返却が必要なInvocationResultは処理の結果を表すオブジェクトです。InvocationResultbodyには任意の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に作成したプログラムをデプロイするだけです。
以下のようにDockerfileserverless.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 --platform=linux/arm64 public.ecr.aws/lambda/provided:latest

COPY --from=build-image /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の名前は先に定義したFunctionHandlernameと一致させるようにしてください。

デプロイ

ここまで設定したら以下の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のコンソールからデプロイした関数を選択して、画面中央の「テスト」タブからテスト実行してみてください。

動作確認_0

以下のように実装した通りの値が返ってくれば成功です。

動作確認_1

参考

この記事で作成したプロジェクトは以下のリポジトリで公開しているので、とりあえず手っ取り早く動かしてみたい方はクローンかフォークをしてからAWS Lambdaにデプロイして遊んでみてください。

https://github.com/myConsciousness/sample-aws-lambda-with-dart-runtime

GitHubで編集を提案

Discussion