在 NestJS 中使用 Prisma 7、Docker 和 Docker Compose 的完整指南

发布: (2026年2月1日 GMT+8 23:56)
10 分钟阅读
原文: Dev.to

Source: Dev.to

如果你曾尝试在 Docker 中运行 Prisma,却陷入了毫无头绪的连接错误,那么本文适合你。

现代后端应用通常依赖 PrismaTypeORMMongoose 等 ORM 来访问数据库,并配合 Docker 以实现一致的开发环境。虽然每个工具单独使用都很出色,但将 Prisma 与 Docker 结合——尤其是与容器化的数据库一起使用——却出乎意料地棘手。

TL;DR – 我花了近两天时间调试 Prisma 为什么无法连接运行在 Docker 中的 PostgreSQL 数据库。本指南将带你一步步完成设置,介绍常见陷阱以及在容器化环境中运行迁移的最佳实践。

📋 前置条件

  • NestJS 的基本了解
  • DockerDocker‑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 foundunsupported platform使用带有旧 Rust 引擎的 Alpine 镜像升级到 Prisma 7(无 Rust)或切换到非 Alpine 基础镜像
迁移持续失败迁移运行时数据库尚未就绪使用 Docker 健康检查 + 在 depends_on 中使用 condition: service_healthy
TypeScript 编译变慢类型定义过多(Prisma 7 之前)升级到 Prisma 7 —— 定义更少,构建更快

回顾

  1. 设置 NestJS 并添加 Prisma。
  2. 创建一个 Docker 化的 PostgreSQL 服务并带有健康检查。
  3. 配置 Prisma 客户端 使用 Docker 网络主机。
  4. 运行迁移 (npx prisma migrate dev) 在启动服务器之前。
  5. 使用轻量级 Node 镜像对 NestJS 应用进行 Docker 化
  6. 使用 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 文件可防止仅在某个环境中出现的错误。
  • 可扩展的工作流 – 相同的配置可在本地开发和生产环境中使用。

如果本指南对您有帮助,欢迎 点赞、评论或分享
查看完整示例仓库:

🔗 https://github.com/idongesit98/DockerProject

Back to Blog

相关文章

阅读更多 »