在 NestJS 中使用 Prisma 7、Docker 和 Docker Compose 的完整指南
Source: Dev.to
如果你曾尝试在 Docker 中运行 Prisma,却陷入了毫无头绪的连接错误,那么本文适合你。
现代后端应用通常依赖 Prisma、TypeORM 或 Mongoose 等 ORM 来访问数据库,并配合 Docker 以实现一致的开发环境。虽然每个工具单独使用都很出色,但将 Prisma 与 Docker 结合——尤其是与容器化的数据库一起使用——却出乎意料地棘手。
TL;DR – 我花了近两天时间调试 Prisma 为什么无法连接运行在 Docker 中的 PostgreSQL 数据库。本指南将带你一步步完成设置,介绍常见陷阱以及在容器化环境中运行迁移的最佳实践。
📋 前置条件
- 对 NestJS 的基本了解
- 对 Docker 和 Docker‑Compose 的基本理解
- 已安装并运行 Docker Desktop
- 一个代码编辑器(例如 VS Code)
什么是 Prisma?
Prisma 是一个开源的 ORM(对象关系映射器),通过将表映射到 JavaScript/TypeScript 对象来简化数据库操作。你无需编写原始 SQL,而是使用类型安全的 API 与数据库交互。
// Raw SQL
SELECT * FROM users WHERE email = 'john@example.com';
// Prisma
const user = await prisma.user.findUnique({
where: { email: 'john@example.com' },
});
优势
- 提升可读性
- 减少运行时错误
- 提供出色的 TypeScript 支持
Prisma 7 亮点(适用于 Docker)
| 特性 | 为何对 Docker 重要 |
|---|---|
| Rust‑free client engine | 更少的二进制兼容性问题,尤其是在 Alpine 镜像中 |
| Fewer type definitions | 更快的 TypeScript 编译,提升编辑器性能 |
| Modern JavaScript support | 与更新的 Node.js 运行时保持一致 |
| Cleaner developer experience | 配置更简洁,边缘情况错误更少 |
最低要求
- Node.js 20.19.0+
- TypeScript 5.4.0+
为什么选择 Docker?
Docker 将你的应用及其依赖打包进容器,确保在任何地方运行时都保持一致。
好处
- 跨团队的一致环境
- 更快的上手
- 更容易的部署与扩展
- 减少 “在我的机器上可以运行” 的问题
NestJS 概览
NestJS 是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。它使用 TypeScript 编写,并支持:
- 面向对象编程(OOP)
- 函数式编程(FP)
- 函数式响应式编程(FRP)
底层默认使用 Express(如果你更喜欢,也可以使用 Fastify)。
全局安装 NestJS CLI
npm install -g @nestjs/cli
创建新项目
nest new backend
脚手架会生成:
- TypeScript 配置
- 项目结构
- 核心依赖
根据需要生成控制器/服务:
nest g controller users
nest g service users
为 NestJS 项目添加 Prisma
1️⃣ 安装 Prisma 包
# Development dependencies
npm install prisma @types/pg --save-dev
# Runtime dependencies
npm install @prisma/client @prisma/adapter-pg pg dotenv
2️⃣ 初始化 Prisma
npx prisma init
创建一个 prisma/ 目录,其中包含 schema.prisma 和 .env 文件。
3️⃣ 配置 Prisma 客户端生成器(Prisma 7)
在 prisma/schema.prisma(或单独的 prisma.config.ts)中添加:
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
moduleFormat = "cjs"
}
4️⃣ 创建 NestJS Prisma 模块和服务
nest g module prisma
nest g service prisma
src/prisma/prisma.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from 'src/generated/prisma/client';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
constructor() {
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
});
super({ adapter, log: ['query', 'info', 'warn', 'error'] });
}
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
该服务:
- 创建
prisma/目录并生成schema.prisma- 添加
.env文件(如果缺失)- 生成
prisma.config.ts(Prisma 7 中的新特性)
Docker 化 PostgreSQL(独立容器)
提示: 在继续之前,请确保 Docker Desktop 正在运行。
1️⃣ 在项目根目录创建 docker-compose.yml
services:
postgres:
image: postgres:15
restart: always
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: backend
ports:
- "5432:5432"
networks:
- prisma-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
interval: 5s
timeout: 2s
retries: 20
volumes:
- postgres_data:/var/lib/postgresql/data
logging:
options:
max-size: "10m"
max-file: "3"
networks:
prisma-network:
volumes:
postgres_data:
2️⃣ 启动数据库
docker compose up -d
3️⃣ 设置连接字符串
添加到 .env(或替换已有的 DATABASE_URL):
DATABASE_URL="postgresql://postgres:backend@localhost:5432/postgres?schema=public"
注意: 如果
localhost在你的机器上不可用,请使用127.0.0.1。
4️⃣ 运行首次迁移并生成客户端
npx prisma migrate dev --name initial-migration
npx prisma generate
5️⃣ 启动 NestJS 应用并打开 Prisma Studio
npm run start # or npm run dev
npx prisma studio
现在你应该能看到一个由 Prisma 支持、运行在 Docker 化 PostgreSQL 实例上的 NestJS API。
为 NestJS 服务器构建 Docker 镜像
在项目根目录创建 Dockerfile。Prisma 7 支持基于 Alpine 和 Slim 的镜像。
示例 Dockerfile(Alpine)
# Use the LTS Alpine image (lightweight)
FROM node:lts-alpine
# Set working directory
WORKDIR /usr/src/app
# Install production dependencies
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# Copy source code
COPY . .
# Run DB migrations then start the server
CMD ["sh", "-c", "npm run db:deploy && npm run dev"]
可选基础镜像
node:lts-slim– 稍大但更稳定node:lts– 完整的基于 Debian 的镜像
将 Server 添加到 docker‑compose.yml
在现有文件中扩展一个 server 服务,使用 Dockerfile 构建。
services:
postgres:
# ... (same as before)
server:
build:
context: .
dockerfile: Dockerfile
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: "postgresql://postgres:backend@postgres:5432/postgres?schema=public"
ports:
- "3000:3000"
networks:
- prisma-network
command: ["sh", "-c", "npm run db:deploy && npm run start:prod"]
关键点
depends_on确保在 NestJS 应用启动之前,数据库已健康。DATABASE_URL指向 Docker 网络中的 服务名称(postgres),而不是localhost。
启动所有服务
docker compose up -d
在 http://localhost:3000 访问 NestJS API,若已暴露,则在 http://localhost:5555 访问 Prisma Studio。
常见陷阱及如何避免
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
PrismaClientInitializationError: Unable to connect to database | 主机错误(使用 localhost 而不是服务名) | 在 Docker 中运行时,在 DATABASE_URL 中使用 postgres(服务名) |
binary not found 或 unsupported platform | 使用带有旧 Rust 引擎的 Alpine 镜像 | 升级到 Prisma 7(无 Rust)或切换到非 Alpine 基础镜像 |
| 迁移持续失败 | 迁移运行时数据库尚未就绪 | 使用 Docker 健康检查 + 在 depends_on 中使用 condition: service_healthy |
| TypeScript 编译变慢 | 类型定义过多(Prisma 7 之前) | 升级到 Prisma 7 —— 定义更少,构建更快 |
回顾
- 设置 NestJS 并添加 Prisma。
- 创建一个 Docker 化的 PostgreSQL 服务并带有健康检查。
- 配置 Prisma 客户端 使用 Docker 网络主机。
- 运行迁移 (
npx prisma migrate dev) 在启动服务器之前。 - 使用轻量级 Node 镜像对 NestJS 应用进行 Docker 化。
- 使用
docker‑compose.yml将所有内容组合起来并启动。
现在,你拥有一个可复现的、以容器为先的开发环境,Prisma 7、Docker 和 NestJS 能够无缝协作。祝编码愉快! 🚀
Docker Compose 设置
services:
app:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
stdin_open: true
tty: true
depends_on:
postgres_db:
condition: service_healthy
env_file:
- .env.prod
networks:
- prisma-network
networks:
prisma-network:
name: prisma-network
环境文件
为每个环境创建两个独立的文件:
.env.dev.env.prod
两者都应包含数据库连接字符串:
DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres?schema=public"
运行容器
-
分离模式(日志减少)
docker compose up --build -d -
完整日志
docker compose up --build
提示: 添加
-d标志可让容器在分离模式下运行,从而抑制大部分日志输出。
常见陷阱与解决方案
| 问题 | 解决方案 |
|---|---|
在 Docker 中,localhost 指的是容器本身。 | 改用 Docker 服务名称:postgres_db:5432。 |
| 容器可能在 PostgreSQL 准备好之前启动。 | 在运行迁移之前添加等待脚本或使用 Docker 健康检查。 |
| Prisma Client 未在容器内生成,导致崩溃。 | 在 Docker 构建步骤中运行 npx prisma generate。 |
| 旧版 Prisma 在 Alpine 镜像上会出现问题。 | 升级到 Prisma 7 —— 其无 Rust 的客户端引擎大幅降低了此问题。 |
为什么在 Docker 与 Docker‑Compose 中使用 Prisma 7?
- 可靠的迁移 – 健康检查确保数据库在执行迁移前已准备就绪。
- 环境无关 – 分离的
.env文件可防止仅在某个环境中出现的错误。 - 可扩展的工作流 – 相同的配置可在本地开发和生产环境中使用。
如果本指南对您有帮助,欢迎 点赞、评论或分享。
查看完整示例仓库: