部署到 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 正确打包你的 schema。
部署到 AWS Lambda 时的一般注意事项
本节涵盖了无论使用何种框架,你都需要对应用程序进行的更改。在完成这些步骤后,请遵循你的框架对应的步骤。
在 Prisma Schema 中定义二进制目标
根据 Node.js 版本,你的 Prisma schema 的 `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`)能够访问正确的 schema 引擎。
对于 AWS Lambda,你需要添加以下环境变量
PRISMA_CLI_BINARY_TARGETS=native,rhel-openssl-1.0.x
`prisma migrate` 是 `prisma` 包中的一个命令。通常,此包作为开发依赖项安装。根据你的设置,你可能需要将其作为生产依赖项安装,以便它包含在上传到 Lambda 并执行的捆绑包或归档文件中。
连接池
在函数即服务 (FaaS) 环境中,每次函数调用通常都会创建一个新的数据库连接。与持续运行的 Node.js 服务器不同,这些连接在执行之间不会保持。为了在无服务器环境中获得更好的性能,请实现连接池以重用现有数据库连接,而不是为每个函数调用创建新连接。
你可以使用 Accelerate 进行连接池,或使用内置连接池的 Prisma Postgres 来解决此问题。有关其他解决方案,请参阅无服务器环境的连接管理指南。
使用 AWS SAM 部署
加载环境变量
AWS SAM 不直接支持从 `.env` 文件加载值。你必须使用 AWS 的服务之一来存储和检索这些参数。本指南 提供了关于你的选项以及如何在 Parameters、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)
}
使用 Serverless Framework 部署
通过 `.env` 文件加载环境变量
你的函数将需要 `DATABASE_URL` 环境变量来访问数据库。`serverless-dotenv-plugin` 将允许你在部署中使用 `.env` 文件。
首先,确保插件已安装
npm install -D serverless-dotenv-plugin
然后,将 `serverless-dotenv-plugin` 添加到 `serverless.yml` 的插件列表中
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` 文件存在,以确保查询根据你的 schema 进行编码和解码。在大多数情况下,打包器默认不会包含此文件,这将导致你的应用程序无法运行。
根据你的应用程序的打包方式,你可能需要将 schema 复制到 `./` 以外的位置。使用 `serverless package` 命令在本地打包你的代码,以便你可以查看 schema 应该放在哪里。
有关其他配置,请参阅 Serverless Webpack 文档。
3. 更新 `serverless.yml`
在你的 `serverless.yml` 文件中,确保 `custom > webpack` 块在 `packagerOptions > scripts` 下包含 `prisma generate`,如下所示:
custom:
webpack:
packagerOptions:
scripts:
- prisma generate
这将确保在 webpack 打包你的代码后,Prisma Client 根据你的 schema 生成。没有此步骤,你的应用程序将无法运行。
最后,你将需要排除与 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 输出将显示 schema 正在通过 `copy-webpack-plugin` 移动。
serverless package
使用 SST 部署
使用环境变量
尽管 SST 支持 `.env` 文件,但不推荐使用它。SST 建议使用 `Config` 以安全的方式访问这些环境变量。
此处提供的 SST 指南 是一个关于 `Config` 入门的逐步指南。假设你已经创建了一个名为 `DATABASE_URL` 的新 secret,并且已经将该 secret 绑定到你的应用程序,你可以按如下方式设置 `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