You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker构建NextJS应用Postgres连接拒绝问题求助

问题分析与解决方案

核心问题

  • 单独执行docker build时,NextJS构建静态页面阶段触发ECONNREFUSED (errno: -111)错误,但docker-compose up --build可正常运行
  • 删除主页中调用getPayload()/payload.find()的组件后能完成构建,但部署到Vercel后,客户端子页正常,服务端子页、管理子页及部分应用请求返回500错误

根本原因

单独docker build是孤立的构建环境,没有启动PostgreSQL服务。而NextJS静态生成(SSG)阶段会执行服务端代码,调用getPayload()时会尝试连接数据库,此时数据库未运行就会触发连接拒绝。docker-compose会先启动健康的PostgreSQL服务再执行构建/启动服务,所以能正常连接。

解决方案

1. 构建阶段规避数据库连接(推荐)

修改NextJS构建逻辑,静态生成时用模拟数据或离线快照,不直接连数据库:

  • 在next.config.js中添加环境变量区分构建/运行环境:
    module.exports = {
      env: {
        IS_BUILDING: process.env.NODE_ENV === 'production' && process.env.BUILD_STAGE === 'true',
      },
    };
    
  • 在使用getPayload()的组件中判断环境,返回模拟数据:
    export async function getStaticProps() {
      if (process.env.IS_BUILDING) {
        // 构建阶段返回模拟数据,跳过数据库连接
        return {
          props: {
            data: [{ id: 1, title: '占位数据' }],
          },
        };
      }
      // 运行环境正常连接数据库
      const payload = await getPayload();
      const data = await payload.find({ collection: 'posts' });
      return { props: { data } };
    }
    
  • 构建时传入环境变量:
    docker build --build-arg BUILD_STAGE=true .
    

2. 构建阶段临时启动数据库(适合必须连库的场景)

修改应用Dockerfile,在builder阶段临时启动PostgreSQL:

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules 
COPY package.json pnpm-lock.yaml* ./
COPY . .

# 安装并临时启动PostgreSQL
RUN apk add --no-cache postgresql
RUN mkdir -p /run/postgresql && chown postgres:postgres /run/postgresql
RUN su postgres -c "initdb -D /var/lib/postgresql/data"
RUN su postgres -c "pg_ctl start -D /var/lib/postgresql/data"
# 等待数据库就绪
RUN su postgres -c "pg_isready -U postgres -h localhost"

# 执行构建
RUN \
  if [ -f yarn.lock ]; then yarn run build; \
  elif [ -f package-lock.json ]; then npm run build; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
  else echo "Lockfile not found." && exit 1; \
  fi

# 构建完成后停止数据库
RUN su postgres -c "pg_ctl stop -D /var/lib/postgresql/data"

构建时指定临时数据库地址:

docker build --build-arg DATABASE_URI=postgres://postgres@localhost/postgres .

3. Vercel部署修复

Vercel上的500错误是因为运行环境未正确配置Payload连接:

  • 在Vercel项目环境变量中添加DATABASE_URI,注意不能用postgres主机名,要填数据库的公网地址
  • 检查pages/api/[...payload].ts的初始化逻辑是否正确:
    import { getPayload } from 'payload';
    import config from '../../payload.config';
    
    export default async function handler(req, res) {
      const payload = await getPayload({
        config,
        req,
      });
      await payload.init({
        config,
        req,
      });
      return payload.express(req, res);
    }
    

原配置格式化

docker-compose.yml

version: '3'
services:
  postgres:
    build: 
      context: postgres
    restart: always
    env_file:
      - .env
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5434:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  payload:
    image: node:18-alpine
    working_dir: /home/node/app
    env_file:
      - .env
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    ports:
      - "3000:3000"
    command: >
      sh -c "corepack enable &&
             corepack prepare pnpm@latest --activate &&
             pnpm install &&
             pnpm dev"

volumes:
  pgdata:
  node_modules:
  data:

postgres/Dockerfile

FROM postgres:latest

RUN cd /var/lib/postgresql/ && \
    openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem && \
    openssl rsa -in privkey.pem -passin pass:abcd -out server.key && \
    openssl req -x509 -in server.req -text -key server.key -out server.crt && \
    chmod 600 server.key && \
    chown postgres:postgres server.key

CMD ["postgres", "-c", "ssl=on", "-c", "ssl_cert_file=/var/lib/postgresql/server.crt", "-c", "ssl_key_file=/var/lib/postgresql/server.key" ]

应用Dockerfile

FROM node:18-alpine AS base

FROM base AS deps

RUN apk add --no-cache libc6-compat
WORKDIR /app

RUN apk add --no-cache postgresql-client

RUN corepack enable && corepack prepare pnpm@latest --activate
COPY package.json pnpm-lock.yaml* ./
RUN pnpm install --frozen-lockfile

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules 
COPY package.json pnpm-lock.yaml* ./
COPY . .

RUN \
  if [ -f yarn.lock ]; then yarn run build; \
  elif [ -f package-lock.json ]; then npm run build; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
  else echo "Lockfile not found." && exit 1; \
  fi

FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED 1

RUN apk add --no-cache postgresql-client

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

RUN mkdir .next
RUN chown nextjs:nodejs .next

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD HOSTNAME="0.0.0.0" node server.js

内容的提问来源于stack exchange,提问作者user30565566

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:27:06