部署到 AWS Lambda
本指南介绍了如何避免在将使用 Prisma ORM 的项目部署到 AWS Lambda 时遇到的常见问题。
虽然部署到 AWS Lambda 不需要部署框架,但本指南涵盖了使用以下框架进行部署:
- AWS 无服务器应用程序模型 (SAM) 是 AWS 的一个开源框架,可用于创建无服务器应用程序。AWS SAM 包括 AWS SAM CLI,您可以使用它来构建、测试和部署您的应用程序。
- Serverless Framework 提供了一个 CLI,可帮助您进行工作流自动化和 AWS 资源配置。虽然 Prisma ORM 可以很好地与 Serverless Framework“开箱即用”一起使用,但您可以在项目中进行一些改进以确保顺利部署和性能。如果您使用的是
serverless-webpack
或serverless-bundle
库,则还需要进行额外的配置。 - SST 提供了工具,使开发人员可以轻松地定义、测试、调试和部署他们的应用程序。Prisma ORM 与 SST 协同工作良好,但必须进行配置,以便 SST 正确打包您的模式。
部署到 AWS Lambda 时的通用注意事项
本节介绍您需要对应用程序进行的更改,无论使用哪个框架。完成以下步骤后,请按照您所使用框架的步骤进行操作。
在 Prisma Schema 中定义二进制目标
根据 Node.js 的版本,您的 Prisma 模式应该在 generator
块中包含 rhel-openssl-1.0.x
或 rhel-openssl-3.0.x
- Node.js 16 和 18
- Node.js 20+
binaryTargets = ["native", "rhel-openssl-1.0.x"]
binaryTargets = ["native", "rhel-openssl-3.0.x"]
这是必要的,因为开发和部署中使用的运行时不同。添加 binaryTarget
以使兼容的 Prisma ORM 引擎文件可用。
具有 arm64 架构的 Lambda 函数
使用 arm64 架构(AWS Graviton2 处理器) 的 Lambda 函数必须使用 arm64
预编译引擎文件。
在 schema.prisma
文件的 generator
块中添加以下内容
binaryTargets = ["native", "linux-arm64-openssl-1.0.x"]
Prisma CLI 二进制目标
虽然我们不建议在 AWS Lambda 中运行迁移,但某些应用程序需要它。在这种情况下,您可以使用 PRISMA_CLI_BINARY_TARGETS 环境变量来确保 Prisma CLI 命令(包括 prisma migrate
)可以访问正确的模式引擎。
在 AWS lambda 的情况下,您需要添加以下环境变量
PRISMA_CLI_BINARY_TARGETS=native,rhel-openssl-1.0.x
prisma migrate
是 prisma
包中的一个命令。通常,此包被安装为开发依赖项。根据您的设置,您可能需要将此包安装为依赖项,以便它包含在上传到 Lambda 并执行的捆绑包或存档中。
连接池
通常,当您使用函数即服务 (FaaS) 环境与数据库交互时,每次函数调用都会导致与数据库的新连接。对于持续运行的 Node.js 服务器来说,这不是问题。因此,最好使用数据库连接池来提高性能。您可以使用 加速 来解决此问题。有关其他解决方案,请参阅 无服务器环境的连接管理指南。
使用 AWS SAM 部署
加载环境变量
AWS SAM 不直接支持从 .env
文件加载值。您需要使用 AWS 的一项服务来存储和检索这些参数。 本指南 提供了关于您的选择以及如何存储和检索参数、SSM、Secrets Manager 等中的值的出色概述。
加载所需文件
AWS SAM 使用 esbuild 来捆绑您的 TypeScript 代码。但是,esbuild API 没有完全公开,并且不支持 esbuild 插件。当在您的应用程序中使用 Prisma ORM 时,这会导致问题,因为某些文件(如 schema.prisma
)必须在运行时可用。
为了解决此问题,您需要在代码中直接引用所需文件,以便正确捆绑它们。在您的应用程序中,您可以在初始化 Prisma ORM 的地方添加以下几行代码。
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)
}
您还需要定义如何使用 esbuild 捆绑这些文件,方法是在 template.yaml
中的 Metadata.BuildProperties
中添加以下几行代码。
Loader:
- .prisma=file
- .so.node=file
AssetNames: '[name]'
这将确保 Prisma ORM 所需的文件包含在 AWS SAM 构建中。
使用 Serverless Framework 部署
通过 .env
文件加载环境变量
您的函数需要DATABASE_URL
环境变量来访问数据库。serverless-dotenv-plugin
插件允许您在部署中使用您的.env
文件。
首先,确保已安装该插件。
npm install -D serverless-dotenv-plugin
然后,在您的serverless.yml
文件中,将serverless-dotenv-plugin
添加到您的插件列表中。
plugins:
- serverless-dotenv-plugin
现在,您.env
文件中的环境变量将在打包或部署时自动加载。
serverless package
仅部署必需的文件
为了减少您的部署占用空间,您可以更新您的部署过程,只上传您的应用程序需要的文件。下面的 Serverless 配置文件serverless.yml
展示了一个package
模式,该模式仅包含与 Lambda 运行时相关的 Prisma ORM 引擎文件,并排除其他文件。这意味着当 Serverless Framework 打包您的应用程序以供上传时,它只包含一个引擎文件。这确保了打包的归档文件尽可能小。
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
引擎文件,如下所示
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
。您需要
- 使用
copy-webpack-plugin
复制您的schema.prisma
。 - 通过您的
serverless.yml
中的custom > webpack > packagerOptions > scripts
运行prisma generate
。 - 只打包正确的 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
中,确保您将externals
设置为nodeExternals()
,如下所示。
const nodeExternals = require('webpack-node-externals')
module.exports = {
// ... other configuration
externals: [nodeExternals()],
// ... other configuration
}
更新您webpack.config.js
文件中的plugins
属性,以包含copy-webpack-plugin
。
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
,如下所示。
custom:
webpack:
packagerOptions:
scripts:
- prisma generate
这将确保在 webpack 捆绑您的代码后,根据您的模式生成 Prisma 客户端。如果没有此步骤,您的应用程序将无法运行。
最后,您将想要排除与 AWS Lambda 运行时不匹配的 Prisma ORM 查询引擎。通过添加以下脚本更新您的serverless.yml
,以确保最终打包的归档文件中只包含必需的查询引擎rhel-openssl-1.0.x
。
custom:
webpack:
packagerOptions:
scripts:
- prisma generate
-- find . -name "libquery_engine-*" -not -name "libquery_engine-rhel-openssl-*" | xargs rm
如果您要部署到使用 ARM64 架构的 Lambda 函数,您应该将find
命令更新为以下内容。
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
使用 SST 部署
使用环境变量
虽然 SST 支持.env
文件,但不建议。SST 建议使用Config
以安全的方式访问这些环境变量。
此处提供的 SST 指南此处提供是使用Config
入门的分步指南。假设您已创建一个名为DATABASE_URL
的新秘密,并且已将该秘密绑定到您的应用程序,您可以使用以下方法设置PrismaClient
。
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