Next.js + Docker 部署最佳实践


本文总阅读量

最近在处理 Next.js 项目的发布流程,实际场景是在本地完成开发后,将代码同步到 Linux 服务器并构建 Docker 镜像。中间踩了一些配置上的坑,也优化了一下构建流程,顺手记录一下这套最佳实践清单。

nextjs_docker_deployment_rsync_best_practice.jpeg

1. 代码增量同步

在本地开发完成后,我习惯用 rsync 将代码增量同步至服务器。只要配置好 SSH 免密登录,一行命令就能搞定发布:

# --dry-run: 也就是“演习”模式,拿不准 excludes 规则时可以先加上这个参数看看会删哪些文件
# 注意:源路径 /mnt/d/... 需根据本地使用的 Shell 环境(如 Git Bash 或 WSL 挂载路径)进行调整
rsync -avP \
	--delete \
	--exclude-from='rsync.ignore' \
	/mnt/d/Project/* xxxx@xxxx:~/data/

这里有个细节需要注意:在 rsync.ignore 里排除文件夹时,务必带上后缀 /。 比如想排除本地的构建缓存和依赖,要写 .next/node_modules/,避免将本地环境的产物同步到服务器,导致环境不兼容。

2. Next.js 项目配置避坑

为了配合服务器端的 Docker 部署,next.config.js 里有几个关键点需要调整。

首先是 Standalone 模式。这是后续 Docker 镜像“瘦身”的前置关键步骤。开启此选项后,Next.js 会自动分析依赖关系,只打包生产环境实际运行所需的必要文件:

module.exports = {
  output: 'standalone',
  // ... 其他配置
}

另外遇到过两个小问题:

  1. UUID 兼容性:原生 crypto.randomUUID API 受浏览器安全策略限制,如果项目部署后是通过 IP 地址(而非 HTTPS 或 localhost)访问,浏览器会报错,导致依赖该方法的组件交互直接失效。建议直接引入第三方 uuid 库来替代,兼容性更稳妥。
  2. pnpm postinstall:如果使用了 pnpm install --ignore-scriptspackage.json 里的 postinstall 钩子虽然当下不执行,但别担心,下次运行 pnpm build 时 PNPM 会自动把这些漏掉的脚本补回来。

3. 生产级 Dockerfile 模板

最后贴一下优化后的 Dockerfile。这是一个多阶段构建脚本,基于 node:22-slim

这个配置主要包含三个核心亮点:

  1. 构建加速:利用 BuildKit 的挂载缓存特性(--mount=type=cache),复用 pnpm store,大幅提升服务器端的反复构建速度。
  2. 多阶段构建:清晰分离环境预设、依赖安装、构建打包和最终运行环境。
  3. 极简体积:配合前文开启的 Standalone 模式,在最终阶段只拷贝 .next/standalone 及必要的静态资源。这使得最终镜像体积大幅减小,不再包含开发依赖和冗余文件。
# ==========================================
# Stage 1: Base (环境预设)
# ==========================================
FROM node:22-slim AS base

ENV NEXT_TELEMETRY_DISABLED 1
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"

# 启用 corepack 以支持 pnpm
RUN corepack enable

WORKDIR /app

# ==========================================
# Stage 2: Deps (依赖安装)
# ==========================================
FROM base AS deps

COPY package.json pnpm-lock.yaml ./
# 挂载 pnpm store 缓存,加速后续构建
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --ignore-scripts

# ==========================================
# Stage 3: Builder (项目构建)
# ==========================================
FROM base AS builder

COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build

# ==========================================
# Stage 4: Runner (生产运行)
# ==========================================
FROM base AS runner

ENV NODE_ENV production
ENV PORT 3000

# 安全起见,新建用户运行,不要用 root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# 只拷贝 Standalone 及其依赖资源,体积大幅减小
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

CMD ["node", "server.js"]

在服务器构建时,通常建议不使用缓存强制拉取最新层(视情况而定),或者使用 docker build --pull=false . 利用本地缓存加速。这套流程目前跑下来比较顺滑,既保证了发布效率,也兼顾了线上镜像的体积和安全性。


本站总访问量