服务器容器化部署 Next.js 应用的 Dockerfile 示例

status
Published
type
Post
slug
self-host-nextjs-app-in-docker-container
date
Oct 5, 2024
tags
Docker
Web
Note
summary
文章讨论了如何将 Next.js 应用容器化部署,文章说明了通过配置 next.config.js 中的 output: "standalone",可以在构建时生成一个仅包含生产所需文件的文件夹,从而简化 Docker 镜像的大小。提供了一个示例 Dockerfile,详细描述了如何构建和运行 Next.js 应用的 Docker 镜像,并介绍了使用 Docker Buildx 构建多平台镜像的步骤。最后,文章提到除了使用 Docker 进行容器化,还可以考虑开源替代方案,如 Coolify 和 Dokploy,以便更灵活地部署 Next.js 应用。

背景

Next.js 是一个用于构建全栈 Web 应用程序的 React 框架。你可以使用 React 组件来构建用户界面,而 Next.js 则提供额外的功能和优化。
在底层,Next.js 还抽象化并自动配置了 React 所需的工具,如打包、编译等。这使你能够专注于构建应用程序,而不必花时间在配置上。
无论你是个人开发者还是大型团队的一员,Next.js 都能帮助你构建交互式、动态且快速的 React 应用程序。
在一众 PaaS 平台中,目前 Next.js 项目部署的首选平台自然是其背后的公司—— Vercel 。对一般个人用户来说,Vercel 的免费额度已经足够使用,而且其整个操作管理体验,UI 交互都很不错。但在某些情况下我们可能还是会需要将 Next.js 项目部署到服务器(VPS)上,那就得考虑 Next.js 项目的容器化了。

Next.js 项目容器化

容器化(Docker)允许你在将你的应用在一致的环境中运行,并轻松地将其部署到任何服务器或云服务商。

Next.js output 可选配置

Next.js 可以在构建时自动创建一个 standalone 文件夹,只包含生产部署所需的文件,包括 node_modules 中的依赖文件。我们可以通过此特性使最终得到的 Docker 镜像尽可能小一些。
next.config.js 中启用它:
构建时会创建 .next/standalone 文件夹,其可以用于部署而无需额外的 node_modules。此外,构建后会得到一个最小的 server.js 文件,可以用它代替 next start 命令。默认情况下,构建时不会自动复制 public 或 .next/static 静态文件文件夹,因为这些文件夹理论上应由 CDN 处理,也可以手动将这些文件夹复制到 standalone/public 和 standalone/.next/static 文件夹中,之后 server.js 文件将接管对这些文件的访问。

Dockerfile 编写

在项目根目录下创建一个 Dockerfile

展开查看 未配置 Next.js output 时的 Dockerfile 示例
这个 Dockerfile 示例实现了通过多阶段构建机制来创建一个 Next.js 应用镜像。
第一阶段 (deps):
  • 基于 node:22-alpine 镜像,安装必要的依赖 libc6-compat
  • 设置工作目录为 /app
  • 复制 package.json 和 package-lock.json 文件。
  • 使用 npm install 安装项目依赖。
第二阶段 (runner):
  • 基于 node:22-alpine 镜像。
  • 设置工作目录为 /app
  • 创建非 root 用户 app 并切换到该用户,提高安全性。
  • 从第一阶段复制项目文件和 node_modules,避免重复安装依赖。
  • 执行 npm run build 构建 Next.js 应用。
  • 设置生产环境变量,包括 NODE_ENV 和 HOSTNAME
  • 暴露 3000 端口。
  • 使用 npm start 启动应用程序。
其中 多阶段构建将依赖安装和应用构建分离,减小最终镜像体积。使用 非 root 用户增强安全性。将Alpine Linux作为轻量级基础镜像,进一步减小镜像体积。
 

如下为配置了 output: "standalone" 后的 Dockerfile 示例:
 
与此同时在 Dockerfile 同级目录创建一个 .dockerignore 文件,以从 Docker 构建上下文中排除不必要的文件:
现在就能够使用 Docker 命令来构建和运行你的应用程序了:
在本地试运行 Docker 容器:
此时打开 http://localhost:3000,你应该会看到 Next.js 应用的主页。
 

构建多平台镜像

有时我们需要在本机构建其他平台架构的镜像,那就可以通过 使用 Docker Buildx 来构建多平台镜像。
以上述 Dockerfile 为例,我们需要调整其中的镜像指令,更改如下:
即在 FROM 指令中添加 --platform=$BUILDPLATFORM 参数,使 Docker Buildx 能识别目标平台并选择合适的镜像版本。
BUILDPLATFORM 是 Docker Buildx 提供的自动变量,用于表示当前构建的目标平台。
此时构建操作命令如下:
  • 初始化 Buildx:
    • 构建多平台镜像:
      • -push 参数会将构建好的镜像推送到镜像仓库。
    执行完命令会创建 amd64arm64 两种架构的镜像,并将它们作为一个多平台镜像推送到镜像仓库。
    在拉取镜像时,Docker 会根据运行平台自动选择合适的镜像版本。
     

    其他

    回到最开始,因为不部署在 Vercel 等 PaaS 上,那么除了利用 Docker 等容器化工具,还有没有其他方案呢。答案就是我们可以使用 Vercel 的开源替代品,比如下面这两个项目:
    仅个人角度出发,dokploy 的体验比 coolify 更好一点,coolify 的功能很多,但是其层级组织嵌套显得有点庞杂,整个 UI 显得很 Professional。还是 Dokploy 的操作来得直接一点。
    后续如果有空就把之前折腾的记录整理出来。(挖坑
     

    2024 © HK