前言
在 Next.js 项目中,官网提供多种部署方式,使用 Docker 部署 Next.js 项目只是其中一部分,同时也是部署项目必须掌握的一部分,因此我们参照官方提供的方法尝试使用 Docker 部署 Next.js 项目。
服务器配置
准备服务器
使用 Docker 部署 Next.js 项目,首先肯定是需要一台服务器,以阿里云服务器为例,其他云服务器同理。
如果你没有云服务器,对于新用户而言,都是可以在官网找到对应的优惠活动的。
进入到购买页面后按照自身的需求选择付费类型和地域,网络及可用区默认就行。如果是优惠活动,付费类型一般都是默认包年包月的。
接下来就是选择要创建的实例和镜像,对于新用户而言实例一般都是 2 核 2G,而镜像可以选择 Ubuntu,下面的登录凭证可以选择自定义密码,最后一定要记录好登录名和登录密码。
配置安全组
当我们购买完服务器之后,云服务器官网就会帮我们创建实例,创建完成后就可以使用,在使用之前还需要为程序配置安全组,可根据自身的业务需求配置。
登录服务器
阿里云控制台提供远程连接,我们可以点击远程连接输入正确的用户名和密码就可以登录到云服务器。
安装 Docker
新创建的云服务器肯定是没有 Git 和 Node 环境以及 Docker 的,因此我们需要安装它们。
安装 Git
首先,在终端命令行输入 sudo apt update
更新系统的软件包列表到最新版本。
然后,继续在终端命令行输入 sudo apt install git
安装 Git。
最后,在终端命令行输入 git --version
能打印出版本号说明安装成功。
安装 Docker
首先,在终端命令行输入以下命令安装 Docker 的一些依赖项。
sudo apt install apt-transport-https ca-certificates curl software-properties-common
然后,继续在终端命令行输入 sudo apt-get update
来更新软件包索引。
其次,在终端命令行输入 apt-get install docker.io
安装 Docker。
最后,在终端命令行输入 docker -v
出现版本号说明 Docker 安装成功。
安装 Node 环境
安装 Node 环境我推荐使用 Volta,关于 Volta 的更多使用方式,你可以参考官网的介绍,或者阅读《如何高效地管理npm源和Node版本?》这篇文章。
首先,在云服务器的终端命令行输入 curl https://get.volta.sh | bash
安装 Volta 管理工具。
然后,继续在命令行终端输入 source .bashrc
这样才能使 Volta 命令全局生效。
其次,在终端命令行输入 volta
打印如下信息,说明 Volta 安装成功。
最后,使用 Volta 安装 Node,在终端命令行输入 volta install node
不指定安装版本,默认安装的是最新版的 Node。
当然你也可以安装指定版本的 Node。
Docker 测试部署
在正式部署项目之前,我们可以参照 Next.js 官网给我们提供的关于 Docker Image 这一部分的内容进行部署测试,其中首先要克隆一个示例 Demo。
首先,在终端命令行输入 npx create-next-app --example with-docker nextjs-docker
,这时候就会在根目录创建一个 nextjs-docker
文件夹的项目。
然后,在 nextjs-docker
文件夹下的终端命令行输入 docker build -t nextjs-docker .
来构建 Docker 镜像,切记是在项目文件夹中输入命令。
docker build -t nextjs-docker .
这一行命令,其中-t
表示用于给构建的镜像指定一个名字和标签,而最后的.
表示构建的上下文是当前目录,也就是说,Docker 会打包这个目录下的所有文件和子目录,不包括.dockerignore
文件中指定的文件或目录。
运行完上述命令后,如果提示成功,则表示 Docker 镜像构建成功。
最后,在项目文件夹终端命令行输入 docker run -p 3000:3000 nextjs-docker
。
在浏览器中输入服务器的公网 IP 和端口号,查看是否运行成功。
从上述的结果来看,使用 Docker 部署测试项目成功,说明 Docker 没有问题,接下来就可以部署正式项目。
Docker 正式部署
使用 Docker 部署正式项目和上述的测试部署步骤是一样的,主要是为验证 Docker 是否可以部署成功,既然可以部署成功,那么我们就直接效仿上述的部署步骤。
首先,需要把上述例子中的 Dockerfile
文件拷贝到自己的项目根目录中,其中的内容为:
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 .npmrc 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
## 参考这里本地运行的报错信息截图 https://github.com/huashui-ai/project-wiki/issues/16
RUN npx prisma generate
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
可以根据自己的业务需求自定义 Dockerfile 文件的内容,如端口号,默认为 3000。
然后,把上述代码中的 .dockerignore
文件拷贝到自己的项目根目录中,其中的内容为:
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
其次,在 next.config.js
文件中新增如下内容:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone'
}
export default nextConfig
最后,执行命令:
-
docker build -t 自己的项目文件夹名称 .
-
docker run -p 3000:3000 自己的项目文件夹名称
总结
通过上述分析可知,几行命令就可以使用 Docker 部署 Next.js 项目。
除了使用 Docker 部署项目,还可以使用 Vercel 部署项目,但是因为网络的原因,国内访问 Vercel 服务器会受到限制,因此在国内很少使用 Vercel。
还有一种方式就是采用常规的方法,直接使用 Node.js Server 启动项目,使用 PM2 管理 Node.js 进程,可实现负载均衡,性能监控等功能。