Next.js部署

1,860 阅读8分钟

Next部署方式

Vercel 部署

Vercel 是 Next.js 的创建者和维护者,旨在增强 Next.js 体验。
Vercel 部署 Next.js 是无需配置开箱即用 上手成本极低,个人开发者提供了永久免费部署方案,自动CI/CD,并在全球范围内提供额外的可扩展性、可用性和性能增强。
(PS:国内访问可能不稳定🙄,多应用需要充钱变强,建议面向国外网站使用

注册|登陆 Vercel官网

然后点击右上角的 Log in(个人无需创建一个新账号,Vercel支持github、gitlab、BitBucket登陆) image.png 选择 github 登陆过程中可能需要验证(此步骤如果访问不了,建议科学上网) image.png

关联 github 仓库

点击 Add new 按钮,选择 Project 新建一个项目 image.png 选择 github 中需要部署的仓库,点击 Import image.png Vercel默认只会读取Public的仓库,如果你的项目是private需要配置 image.png

Vercel 部署

配置你项目的名称、框架、部署路径、Build设置、环境变量,一般我们用默认配置就足够了,然后点击下面的 Deploy,Vercel就会开始部署你的项目(PS:一般来说像.env. 这样的文件我们是不会上传到git仓库中的,Vercel中我们在部署时 Environment Variables 配置数据库、域名等*) image.png 部署成功后 Vercel 会跳转到这个页面,并会显示你项目中的首页 image.png

Vercel 仪表盘

我们可以在项目的仪表盘中管理

  • Repository => 对应 github 仓库
  • usage => 项目使用情况:网路请求量、数据缓存等
  • Domains => 域名(Vercel会自动给你分配随机域名,你可以更换自己的域名)
  • Visit => 查看项目网址
  • Build Logs => 打包日志
  • Runtime Logs => 运行日志
  • Instant Rollback => 回滚选项 image.png

Vercel cli 管理你的项目

如果你想通过shell来操作 Vercel 部署项目可以使用 vercel cli npm i -g vercel
在终端运行以下命令 vercel login 按提示输入你的邮箱地址,登录你的邮箱,点击 Vercel 发送的确认邮件中的链接。

Vercel cli 常用命令

  • 部署 vercel deploy
  • 启动本地服务器 vercel dev
  • 查看所有命令 vercel help
  • 查看部署历史 vercel ls
  • 管理环境变量 vercel env
  • 删除项目 vercel rm [id]
  • 登陆 vercel login
  • 注销 vercel logout
  • 重新部署 vercel redeploy [url]
  • 回滚 vercel rollback [url]
  • 查看部署详情 vercel inspect [deployment-url]
  • 查看实时日志 vercel logs [deployment-url]

PM2 部署

首页你得有一台安装 Linux 系统的服务器(PS:推荐使用 Ubuntu , Centos 安装 Node 18以上版本底层依赖需要升级很多坑),笔者这里使用的是阿里云服务器,与Vercel托管平台相比,阿里云、腾讯云等第三方云服务器能完成绝大部分的部署需求,自由度更高。

为什么使用PM2?

Next.js 直接在云服务器上跑npm run start会有什么问题?

  • 云服务器重启 Next.js 不会自动重启
  • Next.js 运行中报错并不会记录日志
  • Next.js 运行异常退出并不会重启
  • 无法监控 Next.js 应用 CPU、内存使用情况

PM2是一个用于管理和保持Node.js应用状态的进程管理器。它可以用于部署和监控你的Node.js应用程序,PM2可以完美解决上面这些问题。

PM2 使用

安装 PM2(默认已经安装好 Node.js 环境)

npm install pm2@latest -g

查看 PM2 版本

pm2 -v

image.png
如果显示版本号证明安装成功

PM2 部署 Next.js

进入你的应用程序目录

cd project-name

Next.js 打包

// 如果 build 过程中内存占用太大,建议设置 Node 最大使用内存
// npm run build: cross-env NODE_OPTIONS=--max-old-space-size=512 next build
npm run build

PM2 启动 Next.js

// 当前目录下 npm run start 方式在启动,-n "nextjs" 命名一个 nextjs 应用名称
pm2 start npm -n "nextjs" -- run start

查看启动的应用

pm2 ls or list

image.png 重启应用程序

pm2 restart nextjs

停止应用程序

pm2 stop nextjs

删除应用程序

pm2 delete nextjs

服务器重启后使 PM2 自动启动

pm2 startup

仪表盘查看 PM2 CPU、内存使用

pm2 monit

Docker部署

安装docker,安装完成后docker version

image.png 可以看到 Docker Client 和 Docker Server 都启动了说明 Docker 安装成功

Dockerfile 配置

在我们 Next.js 项目根目录下新建 Dockerfile(docker build 默认启动文件名称)、.dockerignore 文件。
Dockerfile为Docker提供了构建项目时的一些配置信息,包括端口号、环境变量、包管理工具等,docker build 时,会先解析 .dockerignore,把该忽略的文件忽略掉,然后把剩余文件打包发送给 docker daemon 作为上下文来构建产生镜像。

Next.js 官方推荐 Dockerfile 配置复制下来
  • 使用 node alpine 镜像, 使得镜像体积大幅减小
  • 使用多阶段构建,充分利用每一层缓存
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1

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

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

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

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

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
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

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js

这些指令的含义如下:

  • FROM:基于一个基础镜像来修改
  • WORKDIR:指定当前工作目录
  • COPY:把容器外的内容复制到容器内
  • EXPOSE:声明当前容器要访问的网络端口,比如这里起服务会用到 8080
  • RUN:在容器内执行命令
  • CMD:容器启动的时候执行的命令
  • ENV:当前环境变量
  • USER:将容器的默认用户从Root切换到自定义用户

next.config.mjs 配置

const nextConfig = {
    //docker 部署开启 standalone 模式
    output: 'standalone',
    //停止使用严格模式重复调用函数2次
    reactStrictMode: false,
    // 服务器不同请求头会报错
    experimental: {
        serverActions: {
          allowedOrigins: ['xxx.com'],
        },
        {
          //指定分配cpu 防止 build cpu 占用过高
          workerThreads: false,
          cpus: 1,
          webpackBuildWorker: true,
         }
      },
      // build 阶段禁止 ts 类型检查
    typescript: {
      ignoreBuildErrors: true,
    },
    eslint: {
      // build 阶段禁止 eslint
      ignoreDuringBuilds: true,
    },
}

Dockerfile 调整
由于我们直接使用的是 pnpm 和一些其他配置将官方默认配置修改下

FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat

WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json pnpm-lock.yaml  ./

RUN npm config set registry https://registry.npmmirror.com/

RUN npm install -g pnpm

RUN pnpm install


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1
# RUN ulimit  -n 4096 -u 3000
# 限制 Node 在服务器上最大内存
# ENV NODE_OPTIONS="--max-old-space-size=512"
# prisma 生成 client 如果没有 prisma 下面一行可以直接执行 npm run build
RUN npm run db:gen && npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

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

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

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
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

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js

在当前项目目录下构建镜像

 // -t 指定制作的镜像名称<br>
 // .不能省略,表示将读取当前目录下的Dockerfile文件中的配置来构建镜像
 docker build -t nextjs .

(PS:如果云服务器 build 过程中云主机卡死建议本地构建完,推送到阿里云的容器镜像服务,云服务器在拉取镜像)
查看 Docker 所有镜像

docker images

image.png 构建完成后启动容器

// -d 则让容器守护态运行
// -p:端口映射,宿主机(服务器)
//  --restart=always 开机自动重启
docker run -d --restart=always -p 3002:3002 nextjs

查看 Docker 启动的容器

docker ps

image.png 到此我们就可以通过 域名或者ip地址:3002 访问我们的 Next.js 项目了