Docker 部署 Next.js
Next.js 的 Docker 部署很有代表性,因为它涉及构建过程(Build)和运行过程(Run)。
通过本章,学会
生产环境级别的部署,我们将使用 Docker 的多阶段构建 (Multi-stage Build) 技术。这能让你的最终镜像体积非常小(通常从 1GB+ 缩减到 100MB 左右)。
准备工作:Next.js 项目配置
在开始写 Dockerfile 之前,我们需要对 Next.js 项目做一个微小的配置调整,以大幅优化 Docker 镜像大小。
修改 next.config.js (或 next.config.mjs)
需要开启
standalone模式。这告诉Next.js在构建时,自动分析并只打包实际用到的文件。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone", // <--- 加上这一行关键配置
};
export default nextConfig;1.创建 .dockerignore 文件
这一步很重要!我们不希望把本地庞大的 node_modules 文件夹或者 .git 文件夹复制到 Docker 镜像里,这会拖慢构建速度。
在项目根目录下新建 .dockerignore 文件
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.git
.next2.编写 Dockerfile
在项目根目录下新建 Dockerfile。我们将把构建过程分为三个阶段
- 依赖安装 (deps)
- 代码构建 (builder)
- 最终运行 (runner)
请直接复制以下代码:
# ---------------------------------------------------
# 1. 依赖阶段:只用来安装依赖
# ---------------------------------------------------
FROM node:18-alpine AS deps
WORKDIR /app
# 复制 package.json 和 lock 文件
COPY package.json package-lock.json ./
# 安装依赖 (使用 ci 命令比 install 更快更稳定)
RUN npm ci
# ---------------------------------------------------
# 2. 构建阶段:编译 Next.js 代码
# ---------------------------------------------------
FROM node:18-alpine AS builder
WORKDIR /app
# 从上一个阶段(deps)拷贝 node_modules
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 开始构建 (这会生成 .next 文件夹)
RUN npm run build
# ---------------------------------------------------
# 3. 运行阶段:最终的生产镜像
# ---------------------------------------------------
FROM node:18-alpine AS runner
WORKDIR /app
# 设置环境变量为生产模式
ENV NODE_ENV=production
# 创建一个非 root 用户是为了安全 (可选,但推荐)
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 把构建产物里的 public 文件夹拷过来 (图片等静态资源)
COPY --from=builder /app/public ./public
# 关键步骤:只拷贝 standalone 构建出来的核心文件
# 这部分文件非常小,不包含多余的开发依赖
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 切换用户
USER nextjs
# 暴露端口
EXPOSE 3000
# 启动命令 (注意:standalone 模式下,启动入口是 server.js)
CMD ["node", "server.js"]3.构建并运行
- 构建镜像
给这个镜像取名叫 my-next-app
docker build -t my-next-app .❗注意:第一次构建可能需要几分钟,因为要下载 Node.js 基础镜像并安装依赖。
- 运行容器
把本机的 3000 端口映射到容器的 3000 端口
docker run -p 3000:3000 my-next-app- 验证
打开浏览器访问 http://localhost:3000。 你应该能看到你的 Next.js 页面正在运行!
Q&A
为什么不直接把代码拷进去运行 npm run start?
- 体积差异巨大:
- 普通写法:镜像可能 > 1GB (包含了数万个开发依赖文件)。
- 这种写法:镜像可能只有 120MB 左右。
安全性: 生产环境镜像里没有源码,只有编译后的产物。
缓存优化: 如果你只改了代码没改 package.json,Docker 会自动跳过“安装依赖”这一步,构建速度飞快。
拓展
使用 pnpm or yarn
默认情况下使用 RUN npm ci 如果使用 pnpm or yarn
pnpm
# 先开启 corepack (Node 16/18+ 自带) 激活corepack 默认不激活
RUN corepack enable
# 好处
# Corepack 无需手动安装:“自动档” 你不需要再运行 npm install -g yarn 或 pnpm。激活 Corepack 后,这些命令会自动可用。
#版本锁定(最重要): Corepack 会读取你项目 package.json 中的 packageManager 字段。
#如果你的 package.json 写着 "packageManager": "yarn@3.2.0"。
#当你运行 yarn install 时,Corepack 会自动下载并使用 Yarn 3.2.0,而不是你本地可能安装的 Yarn 1.x。
#这保证了团队所有成员和 CI/CD 环境使用的包管理器版本完全一致,避免了“我这边能跑,你那边报错”的问题。
# 复制 pnpm.lock
COPY package.json pnpm-lock.yaml ./
# 使用 pnpm 安装依赖
RUN pnpm install --frozen-lockfileyarn
RUN corepack enable
# 复制 yarn.lock
COPY package.json yarn.lock ./
# 使用 yarn 安装依赖
RUN yarn install --frozen-lockfile注意:后面的步骤中,如果遇到 npm run build 也可以改成 yarn build,但通常 npm run 也能兼容调用脚本。
关于 --frozen-lockfile
“环境一致性”
npm install: 宽容。 如果package.json里写了 "react": "^18.0.0",而package-lock.json里锁定了 18.2.0。npm ci: 全称 Clean Install,它是严厉的。它只看package-lock.json
Yarn 和 pnpm 的设计哲学稍微不同它们没有专门搞一个 ci 命令,而是通过给 install 命令加参数来实现相同的“严厉模式”。 这就是 --frozen-lockfile 的含义。
注: 在 Yarn 2+ (Berry) 版本中,这个参数改名为 --immutable,意思是一样的:不可变。
总结对比表
| 包管理器 | 本地开发用 (宽容) | Docker/生产环境用 (严厉) | 作用 |
|---|---|---|---|
| npm | npm install | npm ci | 必须有 lock 文件,死板,速度快 |
| Yarn | yarn install | yarn install --frozen-lockfile | 冻结 lock 文件,禁止更新 |
| pnpm | pnpm install | pnpm install --frozen-lockfile | 同上 |