昆仑虚 - NextJS 项目如何进行部署?

引言

NextJS 是一个构建于 NodeJS 之上的一个 Web 开发框架。它基于 React 特性进行了一些列的扩展!! 在社区中也很是火热, 前段时间 「昆仑虚」 也终于完成了项目的迁移(React => NexJS)!!

那么接下来就是项目部署, NextJS 相比常规的前端部署还是有所区别的:

  • 常规的前端项目只是包含一些静态的资源文件, 只要起一个 Web 服务器, 然后把资源丢上去就行, 比如: Nginx
  • 但是对于 NextJS 项目是包含后端(Node)服务的, 当然官网 CI 工具其实也提供了相关 CI 命令, 正常只需要 Build 好后, 执行 start 命令即可, 但是我个人更希望能够使用 pm2 来运行, 基于 pm2 可以方便管理服务进程以及自带一套日志系统, 同时还希望能够通过 Docker 的方式来进行部署

一、架构

改造后 「昆仑虚」 整体部署希望如上图所示:

  • 所有服务(包括 Nginx) 都是一个 Docker 容器
  • Nginx 在中间只作为反向代理来使用
  • 当用户访问前端页面或后端接口时, 通过 Nginx 方向代理到对应的服务

当然本文只讲解 NextJS 服务部署的部分, 与此同时最后还会给出 Nginx 反向代理的配置, 至于后端服务的部署则不做讲解, 而且前后端服务都是独立的, 确失后端部分也是不影响 NextJS 部署流程...

二、修改 NextJS 配置文件

修改 NextJS 配置文件, 确保在 Build 时输出模式为 standalone, 关于 output 配置具体信息可查阅 next-config-js/output

diff 复制代码
// next.config.mjs
const nextConfig = {
+ output: 'standalone',
};
export default nextConfig;

三、Dockerfile 编写

这里我是参考了官方的一个 Demo, 基于官方模版做了简单的调整

项目根目录下创建 dockerfile 配置文件, 配置内容如下, 具体的介绍看注释:

sh 复制代码
# 使用 amd64 架构的 node 镜像作为基础镜像
FROM --platform=linux/amd64 node AS base

# 新增用户 & 用户组
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# 安装 pm2 和 pnpm
RUN npm install --global pm2 pnpm

# ------------------------- deps -----------------------------------
FROM base AS deps
WORKDIR /app

# 拷贝 package.json 和 pnpm-lock.yaml 文件, 并安装相关依赖
COPY package.json pnpm-lock.yaml* .npmrc ./
RUN pnpm i --frozen-lockfile

# ------------------------- builder -----------------------------------
FROM base AS builder
WORKDIR /app

# 拷贝上一步安装的依赖
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# 构建项目
RUN pnpm run build

# ------------------------- runner -----------------------------------
FROM base AS runner
WORKDIR /app

# 创建 ecosystem.config.js 文件, 用于 pm2 启动不想直接在项目里创建
COPY <<EOF /app/ecosystem.config.js
module.exports = {
  apps: [
    {
      name: 'klx-website',
      script: 'node server.js',
      watch: false,
  },
  ],
};
EOF

# 创建相关目录, 并设置权限
RUN mkdir pm2
RUN mkdir .next
ENV PM2_HOME /app/pm2
RUN chown nextjs:nodejs pm2
RUN chown nextjs:nodejs .next

# 复制运行服务所需要的产物, see: https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder /app/public ./public
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 HOSTNAME="0.0.0.0"

# 运行容器时, 启动 pm2
CMD pm2 start ecosystem.config.js --no-daemon

下面我们尝试构建下镜像, 如下命令所示:

sh 复制代码
# 后面一个 . 别漏了
docker build -t website:4.2.4 . 

在构建时这里遇到一个坑, 就是我的机器是 M2 芯片(ARM), 导致 Build 出来的镜像在 Ubuntu 上无法运行, 这里解决方案有挺多的, 具体可以看 Forcing docker to use linux/amd64 platform by default on macOS

  1. Build 时通过 --platform linux/amd64 参数指定平台, 例: docker build --platform linux/amd64 -t website:4.2.4
  2. 通过环境变量来修改 export DOCKER_DEFAULT_PLATFORM=linux/amd64
  3. Dockerfile 中, 在指定 form 时进行设置(本文使用的方案), 例: FROM --platform=linux/amd64 node
  4. Docker compose 中, 通过 platform: linux/amd64 字段来设置

四、阿里云私人镜像仓库

这里还需要整个私人的镜像仓库, 构建好的镜像需要上传到上面, 然后在 docker compose 中进行引用。我这里使用的是阿里的服务, 下面将简单演示下:

  1. 在阿里云搜索「镜像容器服务」
  1. 我这里用的是免费版的



  1. 先创建一个命令空间
  1. 创建镜像仓库
  1. 这里我选择本地仓库
  1. 创建完成后, 进入详情页会有具体的仓库信息, 以及相关使用介绍(怎么登录、怎么推送、怎么拉取...)

五、上传镜像

大部分命令上面最后一张图其实已经给出了, 下面只是走个流程

  1. 重新构建镜像
sh 复制代码
docker build -t registry.cn-hangzhou.aliyuncs.com/kunlunxu/website:4.2.4 .
  1. 登录阿里云 Docker Registry
sh 复制代码
# username 换成自己的用户名
docker login --username=13*********@163.com registry.cn-hangzhou.aliyuncs.com
  1. 镜像推送
sh 复制代码
docker push registry.cn-hangzhou.aliyuncs.com/kunlunxu/website:4.2.4
  1. 推送完成, 在阿里云镜像版本列表中, 就能够看到推送的镜像了

六、Docker compose 编写

这里我希望通过 Docker compose 来管理我的容器(重启啥的比较方便)

项目根目录下创建 docker-compose.yml 配置文件, 具体内容如下, 相关描述看注释

yml 复制代码
version: '3'
services:
  website:
    image: registry.cn-hangzhou.aliyuncs.com/kunlunxu/website:4.2.4 # 镜像地址
    container_name: klx-website # 容器名称
    ports:
      - 3000:3000 # 端口映射
    environment:
      - TZ=Asia/Shanghai # 时区
    logging: # 日志配置
      driver: "json-file"
      options:
        max-size: "100k"
        max-file: "20"

七、部署 NexJS 项目

  1. 登录你的服务器, 拉取最新的代码! 这一步取决于你自己的部署方式, 我这里是直接在服务器把仓库代码给拉下来了, 当然你也可以直接在服务器创建一个 Docker compose 配文件)

  2. 执行 Docker compose 命令启动项目即可

sh 复制代码
docker compose up -d
  1. 运行成功

八、Nginx 配置

下面是 Nginx 方向代理相关的一些配置, http://172.17.8.146 是我服务器内网地址

diff 复制代码
    # HTTPS 设置
    server {
        listen 443 ssl;
        server_name www.kunlunxu.cc;#换成你的域名
        ssl_certificate /etc/nginx/ssl.pem;#证书文件
        ssl_certificate_key /etc/nginx/ssl.key;#秘钥文件
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers  ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers   on;

        # 前端代理配置
        location / {
            proxy_pass http://172.17.8.146:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        # API 代理配置
        location /api/ {
            proxy_pass http://172.17.8.146:4000; # 代理到 API 服务器
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
}

九、TODO

到处 NextJS 部署流程大体就是如此了, 但是这里的一切都是需要手动参与的, 包括:

  • Build 镜像前, 需要手动修改 .env.local 中的必要的环境变量
  • 需要手动在本地 Build
  • Build 完成后需要手动修改 docker-compose.yml 上镜像版本号, 并提交代码
  • 最后还需要登录到服务器, 拉取最新代码后, 拉取最新镜像后, 停止并删除相关镜像后, 重启服务

总之一切都是那么的麻烦, 后续则需要将这些流程全部简化掉...

十、参考

相关推荐
_Kayo_44 分钟前
CSS BFC
前端·css
二哈喇子!2 小时前
Vue3 组合式API
前端·javascript·vue.js
归辞...3 小时前
「iOS」————NSOperation
macos·ios·cocoa
二哈喇子!3 小时前
Vue 组件化开发
前端·javascript·vue.js
chxii4 小时前
2.9 插槽
前端·javascript·vue.js
姑苏洛言4 小时前
扫码点餐小程序产品需求分析与功能梳理
前端·javascript·后端
Freedom风间4 小时前
前端必学-完美组件封装原则
前端·javascript·设计模式
江城开朗的豌豆4 小时前
React表单控制秘籍:受控组件这样玩就对了!
前端·javascript·react.js
一枚前端小能手5 小时前
📋 代码片段管理大师 - 5个让你的代码复用率翻倍的管理技巧
前端·javascript
国家不保护废物5 小时前
Web Worker 多线程魔法:告别卡顿,轻松实现图片压缩!😎
前端·javascript·面试