メインコンテンツへスキップ

AWS Lambdaへのデプロイ

このガイドでは、Prisma ORMを使用するプロジェクトをAWS Lambdaにデプロイする際の一般的な問題を回避する方法を説明します。

AWS Lambdaへのデプロイにデプロイフレームワークは必須ではありませんが、このガイドでは以下のフレームワークでのデプロイについて説明します。

  • AWS Serverless Application Model (SAM)は、サーバーレスアプリケーションの作成に使用できるAWSのオープンソースフレームワークです。AWS SAMにはAWS SAM CLIが含まれており、これを使用してアプリケーションをビルド、テスト、デプロイできます。
  • Serverless Frameworkは、ワークフローの自動化とAWSリソースのプロビジョニングを支援するCLIを提供します。Prisma ORMはServerless Frameworkと「そのまま」うまく機能しますが、スムーズなデプロイとパフォーマンスを確保するためにプロジェクト内でいくつかの改善を行うことができます。また、serverless-webpackまたはserverless-bundleライブラリを使用している場合は、追加の設定が必要です。
  • SSTは、開発者がアプリケーションを定義、テスト、デバッグ、デプロイすることを容易にするツールを提供します。Prisma ORMはSSTとよく連携しますが、スキーマがSSTによって正しくパッケージ化されるように設定する必要があります。

AWS Lambdaへのデプロイに関する一般的な考慮事項

このセクションでは、フレームワークに関係なくアプリケーションに行う必要がある変更について説明します。これらの手順に従った後、使用しているフレームワークの手順に従ってください。

Prismaスキーマでバイナリターゲットを定義する

Node.jsのバージョンに応じて、Prismaスキーマのgeneratorブロックにrhel-openssl-1.0.xまたはrhel-openssl-3.0.xを含める必要があります

binaryTargets = ["native", "rhel-openssl-1.0.x"]

これは、開発環境とデプロイ環境で使用されるランタイムが異なるため必要です。binaryTargetを追加して、互換性のあるPrisma ORMエンジンファイルを利用可能にしてください。

arm64アーキテクチャのLambda関数

arm64アーキテクチャ (AWS Graviton2プロセッサ)を使用するLambda関数は、arm64プリコンパイル済みエンジンファイルを使用する必要があります。

schema.prismaファイルのgeneratorブロックに以下を追加します。

schema.prisma
binaryTargets = ["native", "linux-arm64-openssl-1.0.x"]

Prisma CLIバイナリターゲット

AWS Lambda内でマイグレーションを実行することは推奨されませんが、一部のアプリケーションでは必要になります。これらのケースでは、PRISMA_CLI_BINARY_TARGETS環境変数を使用して、prisma migrateを含むPrisma CLIコマンドが正しいスキーマエンジンにアクセスできるようにすることができます。

AWS Lambdaの場合、以下の環境変数を追加する必要があります。

.env
PRISMA_CLI_BINARY_TARGETS=native,rhel-openssl-1.0.x
情報

prisma migrateprismaパッケージ内のコマンドです。通常、このパッケージは開発依存関係としてインストールされます。セットアップによっては、Lambdaにアップロードされて実行されるバンドルまたはアーカイブに含めるために、このパッケージを代わりに依存関係としてインストールする必要がある場合があります。

コネクションプーリング

Function as a Service (FaaS) 環境では、各関数呼び出しは通常、新しいデータベース接続を作成します。継続的に実行されるNode.jsサーバーとは異なり、これらの接続は実行間で維持されません。サーバーレス環境でのパフォーマンスを向上させるには、各関数呼び出しごとに新しい接続を作成するのではなく、既存のデータベース接続を再利用するためにコネクションプーリングを実装します。

この問題を解決するために、コネクションプーリングにはAccelerateを使用するか、組み込みのコネクションプーリングを持つPrisma Postgresを使用できます。その他の解決策については、サーバーレス環境向けコネクション管理ガイドを参照してください。

AWS SAMによるデプロイ

環境変数の読み込み

AWS SAMは、.envファイルからの値の読み込みを直接サポートしていません。これらのパラメータを保存および取得するには、AWSのサービスを使用する必要があります。このガイドでは、オプションと、パラメータ、SSM、Secrets Managerなどに値を保存および取得する方法について詳しく説明しています。

必要なファイルの読み込み

AWS SAMはTypeScriptコードをバンドルするためにesbuildを使用します。しかし、esbuildの全APIは公開されておらず、esbuildプラグインはサポートされていません。これにより、特定のファイル(schema.prismaなど)が実行時に利用可能である必要があるため、アプリケーションでPrisma ORMを使用する際に問題が発生します。

これを回避するには、必要なファイルをコード内で直接参照して、正しくバンドルされるようにする必要があります。アプリケーションでは、Prisma ORMがインスタンス化される場所に以下の行を追加できます。

app.ts
import schema from './prisma/schema.prisma'
import x from './node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node'

if (process.env.NODE_ENV !== 'production') {
console.debug(schema, x)
}

Serverless Frameworkによるデプロイ

.envファイルを介した環境変数の読み込み

関数がデータベースにアクセスするには、DATABASE_URL環境変数が必要です。serverless-dotenv-pluginを使用すると、デプロイで.envファイルを使用できるようになります。

まず、プラグインがインストールされていることを確認してください

npm install -D serverless-dotenv-plugin

次に、serverless.ymlのプラグインリストにserverless-dotenv-pluginを追加します

serverless.yml
plugins:
- serverless-dotenv-plugin

これで、.envファイル内の環境変数がパッケージまたはデプロイ時に自動的にロードされます。

serverless package
表示CLI結果

必要なファイルのみをデプロイする

デプロイのフットプリントを減らすために、アプリケーションが必要とするファイルのみをアップロードするようにデプロイプロセスを更新できます。以下のServerless設定ファイルserverless.ymlは、Lambdaランタイムに関連するPrisma ORMエンジンファイルのみを含み、それ以外を除外するpackageパターンを示しています。これにより、Serverless Frameworkがアップロードのためにアプリをパッケージ化する際に、1つのエンジンファイルのみが含まれるようになります。これにより、パッケージ化されたアーカイブが可能な限り小さくなります。

serverless.yml
package:
patterns:
- '!node_modules/.prisma/client/libquery_engine-*'
- 'node_modules/.prisma/client/libquery_engine-rhel-*'
- '!node_modules/prisma/libquery_engine-*'
- '!node_modules/@prisma/engines/**'
- '!node_modules/.cache/prisma/**' # only required for Windows

ARM64アーキテクチャのLambda関数にデプロイする場合、Serverless設定ファイルを以下のように更新してarm64エンジンファイルをパッケージ化する必要があります。

serverless.yml
package:
patterns:
- '!node_modules/.prisma/client/libquery_engine-*'
- 'node_modules/.prisma/client/libquery_engine-linux-arm64-*'
- '!node_modules/prisma/libquery_engine-*'
- '!node_modules/@prisma/engines/**'

serverless-webpackを使用する場合は、以下のserverless webpackによるデプロイを参照してください。

serverless-webpackによるデプロイ

serverless-webpackを使用する場合、schema.prismaが適切にバンドルされるように追加の設定が必要です。以下の操作が必要です。

  1. copy-webpack-pluginschema.prismaをコピーします。
  2. serverless.ymlcustom > webpack > packagerOptions > scriptsを通じてprisma generateを実行します。
  3. 正しいPrisma ORMエンジンファイルのみをパッケージ化することで、40MB以上の容量を節約できます。

1. webpack固有の依存関係をインストールする

まず、以下のwebpack依存関係がインストールされていることを確認してください

npm install --save-dev webpack webpack-node-externals copy-webpack-plugin serverless-webpack

2. webpack.config.jsを更新する

webpack.config.jsで、以下のようにexternalsnodeExternals()に設定してください

webpack.config.js
const nodeExternals = require('webpack-node-externals')

module.exports = {
// ... other configuration
externals: [nodeExternals()],
// ... other configuration
}

webpack.config.jsファイルのpluginsプロパティを更新して、copy-webpack-pluginを含めます

webpack.config.js
const nodeExternals = require('webpack-node-externals')
const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
// ... other configuration
externals: [nodeExternals()],
plugins: [
new CopyPlugin({
patterns: [
{ from: './node_modules/.prisma/client/schema.prisma', to: './' }, // you may need to change `to` here.
],
}),
],
// ... other configuration
}

このプラグインを使用すると、schema.prismaファイルをバンドルされたコードにコピーできます。Prisma ORMは、クエリがスキーマに従ってエンコードおよびデコードされることを保証するために、schema.prismaが存在することを必要とします。ほとんどの場合、バンドラーはこのファイルをデフォルトで含まないため、アプリケーションは実行に失敗します。

情報

アプリケーションのバンドル方法によっては、スキーマを./以外の場所にコピーする必要がある場合があります。serverless packageコマンドを使用してコードをローカルでパッケージ化し、スキーマをどこに配置すべきか確認してください。

追加の設定については、Serverless Webpackのドキュメントを参照してください。

3. serverless.ymlを更新する

serverless.ymlファイルで、custom > webpackブロックにpackagerOptions > scriptsの下に以下のようにprisma generateがあることを確認してください。

serverless.yml
custom:
webpack:
packagerOptions:
scripts:
- prisma generate

これにより、webpackがコードをバンドルした後、Prisma Clientがスキーマに従って生成されることが保証されます。この手順がないと、アプリは実行に失敗します。

最後に、AWS Lambdaランタイムと一致しないPrisma ORMクエリエンジンを除外します。serverless.ymlを以下のスクリプトを追加して更新し、必要なクエリエンジンであるrhel-openssl-1.0.xのみが最終パッケージアーカイブに含まれるようにします。

serverless.yml
custom:
webpack:
packagerOptions:
scripts:
- prisma generate
-- find . -name "libquery_engine-*" -not -name "libquery_engine-rhel-openssl-*" | xargs rm

ARM64アーキテクチャのLambda関数にデプロイする場合、findコマンドを以下のように更新する必要があります。

serverless.yml
custom:
webpack:
packagerOptions:
scripts:
- prisma generate
-- find . -name "libquery_engine-*" -not -name "libquery_engine-arm64-openssl-*" | xargs rm

4. まとめ

これで、アプリケーションを再パッケージ化して再デプロイできます。これを行うには、serverless deployを実行します。Webpackの出力には、copy-webpack-pluginによってスキーマが移動されたことが表示されます。

serverless package
表示CLI結果

SSTによるデプロイ

環境変数の操作

SSTは.envファイルをサポートしていますが、推奨されません。SSTは、これらの環境変数に安全な方法でアクセスするためにConfigを使用することを推奨しています。

Configの入門には、こちらのSSTガイドがステップバイステップで説明しています。DATABASE_URLという新しいシークレットを作成し、そのシークレットをアプリにバインドしていると仮定すると、以下のようにPrismaClientを設定できます。

prisma.ts
import { PrismaClient } from '@prisma/client'
import { Config } from 'sst/node/config'

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma =
globalForPrisma.prisma ||
new PrismaClient({
datasourceUrl: Config.DATABASE_URL,
})

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

export default prisma
© . All rights reserved.