Docker+Next.js+Spring boot+Github actions实现CI/CD
发表于
浏览量1072
评论数1
Docker compose+Next.js+Spring boot+Prisma+Github actions实现CI/CD
其实主要是记录自己部署博客系统的流程,也是自己慢慢摸索出来的,踩的坑数不胜数,也仅供参考📑
使用
Next.js
,主要是用于SEO,因此不要问我为什么还要用Spring Boot
,问就是懒,后端服务是现成的,所以并没有打算用Next.js
完全重写后端服务,但瞎搞了个对象关系映射框架Prisma
和NextAuth.js实现了鉴权功能,搭配了Dcoker
使用了其容器编排功能,再使用Github Actions
,从推送代码后,就完全交由其,从打包,制作镜像,上传镜像,拉取镜像,重新部署......不再需要自己手动了,帮助节省了很多在部署和维护项目上的时间。
Docker compose
说Docker compose
(容器编排技术以下简称compose)之前,你可能需要先了解一下 Docker ,它是一个软件平台,让您可以快速构建、测试和部署应用程序。Docker 将软件打包成名为container(容器)
的标准化单元,这些单元具有运行软件所需的所有功能,包括库、系统工具、代码和运行时。使用 Docker
,您可以将应用程序快速部署和扩展到任何环境中。而compose
是用于定义和运行多容器 Docker
应用程序的工具。通过 compose
您可以使用yml
文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 yml
文件配置中创建并启动所有服务。
可能说的很抽象,有个很形象的比喻:在一个酒馆里,酒就是镜像,酒杯就是容器,而负责管理这些酒杯的就是compose了
。
大致了解这些,接下来才好理解,以下是我的compose
配置文件,一共定义了MySQL
、Redis
、Web-api(Spring boot 后端应用)
、Web-v4(Next.js 应用)
四个服务:
# 指定 Docker Compose 文件的版本,根据自己安装的docker版本而定
version: "3"
# 定义一个自定义的网络kasuie,用于连接这些服务,网络类型为 bridge (Docker 默认的网络模式)
networks:
kasuie:
driver: bridge
services:
database: # 定义一个 MySQL 服务
image: mysql:5.7.36 # 指定镜像及版本,如果镜像在本地不存在,会尝试去拉取这个镜像
container_name: mysql # 指定容器的名称为 mysql
ports: # 宿主端口:容器端口 格式,这里将容器的 3306 端口映射到宿主机(所在服务器)的 3306 端口,可映射多个端口
- "3306:3306"
environment: # 设置容器的环境变量,包括时区、MySQL root 用户的访问权限和密码
- TZ=Asia/Shanghai
- MYSQL_ROOT_HOST=%
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
volumes: # 挂载宿主机上的文件或目录到容器内,包括 MySQL 配置文件和数据目录,避免重启数据丢失
- /etc/my.cnf:/etc/my.cnf
- /var/lib/mysql/:/var/lib/mysql/
- /home/mysql/initdb.sql:/docker-entrypoint-initdb.d
restart: always # 设置容器总是在退出时重新启动
command: # 指定运行容器时执行的命令,配置 MySQL 服务的一些参数
- mysqld
- --default-storage-engine=InnoDB
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --explicit_defaults_for_timestamp
networks: # 将容器连接到 kasuie 网络
- kasuie
redis: # 定义一个 Redis 服务,相同字段解释同上
image: redis:7.0.4
container_name: redis
environment:
TZ: Asia/Shanghai
command: redis-server --save 600 1000 --requirepass ${REDIS_PASSWORD} --port ${REDIS_PORT}
restart: always
volumes:
- /usr/local/docker/redis:/data #数据文件挂载
- /usr/local/docker/redis/redis.conf:/etc/redis/redis.conf #配置文件挂载
networks:
- kasuie
web-api: # 定义一个 web-api 服务
image: ${APITAG:-default} # 使用镜像由变量 `${APITAG}` 指定,不指定默认为default
restart: always
container_name: web-api
environment: # 设置容器的环境变量,包括 MySQL 和 Redis 的连接信息
MYSQL_URL: ${MYSQL_URL}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_PASSWORD: ${REDIS_PASSWORD}
TZ: Asia/Shanghai
ports:
- "8001:8001"
networks:
- kasuie
depends_on: # 定义此服务依赖于其他服务(database 和 redis),确保在启动此服务之前启动这两个服务
- database
- redis
web-v4:
image: ${IMAGETAG:-default}
restart: always
container_name: web-v4
ports:
- "3001:3000"
networks:
- kasuie
在配置文件同目录下有.env
的环境变量配置文件:
MYSQL_ROOT_PASSWORD=your_mysql_password
MYSQL_URL=your_mysql_url
REDIS_PASSWORD=your_mysql_password
REDIS_PORT=your_redis_port
REDIS_HOST=redis
第一次需要手动在服务器启动一下,compose
的启动命令: docker-compose up -d
,-d
表示在后台启动,当然这里有点不一样的是,不能直接全部启动,观察一下上面的变量是否缺少了些什么?
注意:
docker-compose up -d
命令是找的当前目录下docker-compose.yml
文件,请注意配置文件名,如果不是这个文件名,你可以通过-f
指定配置文件,例如docker-compose -f /root/myfile.yml up -d
细心一点你会发现,在环境变量文件中,只有mysql
和redis
相关的,但compose
配置文件中还存在${IMAGETAG}
和${APITAG}
两个关于镜像的变量,这是没有提到并缺少的,所以直接运行启动命令是不会成功的。而之所以这样写是因为web-api
和web-v4
这两个的镜像是我自己的维护的服务,也就是我的博客整个系统,会经常更新,每一次通过Github actions
推送代码都会自动打包一个唯一的镜像并推送到镜像仓库,然后这两个变量会在Github actions
的工作流程中使用到,后续会详细讲这个部分。
简略一点来说,这样写是为了每一次都拉取自己最新维护的镜像版本,然后第一次启动因为你两个服务的镜像仓库都是空的,自然不能全部运行(如果你仓库有,可以手动通过export
设置这里的变量后,就可以启动),其中mysql
和redis
是官方镜像,所以可以启动,第一次只启动它们就可以了,运行:
docker-compose up -d database redis
到这里compose
这部分手动需要我们操作的这部分就算是完成了.
Github actions
然后要实现CI/CD
,就必须要说说Github actions了,它是Github
一种持续集成和持续交付 (CI/CD) 平台,可用于自动执行生成、测试和部署管道,像什么检入检出代码、运行测试打包、登录远程服务器,发布到第三方服务等等,Github
把这些操作就称为 actions
,如果你需要某个 action
,不必自己写复杂的脚本,直接引用他人写好的action
即可,你可以在Github
提供的官方市场找到,整个持续集成过程,就变成了一个 actions 的组合,而最终会形成一个workflow
(工作流程),那么项目如何使用呢?
Github actions
的工作流程在项目根目录下的 .github/workflows
目录中定义,这些定义文件叫做workflow
文件,可以有多个工作流程文件,每个工作流程都可以执行不同的任务集,采用 yaml
格式,文件名可以任意的,但是后缀必须是.yml
,这样才能识别到。
Next.js中的Workflows
例如,我的Next.js项目,在 .github/workflows/actions.yml
目录新建名为actions.yml
的文件,代码如下:
name: Web-v4 Docker Image CI # workflow 的名,可省略,默认为当前 workflow 的文件名
on: # 指定触发 workflow 的条件,这里是指定代码push的时候,可为数组,指定多个条件:[push, pull_request],push或者pull_request都可以触发
push:
branches: [pro-docker] # 指定workflow工作的分支,可以填多个
workflow_dispatch: # 可在Github actions面板手动触发workflow
# 一个workflow由执行的一项或多项job(任务)
# 一个job包含一个或多个setp(步骤),steps字段指定每个job的运行步骤
jobs:
build-and-push: # 指定这个job名为build-and-push,Github actions面板流程图会显示这个名称
runs-on: ubuntu-latest # 指定运行在最新版ubuntu系统中
steps:
- name: Set state # 指定这个setp名为Set state,job面板详情会显示
run: | # 执行某个shell命令或脚本
echo "DOCKER_NAMESPACE=kasuie" >> $GITHUB_ENV # 设置一些变量并存储在 GitHub actions 的环境变量中,以便在后续步骤中可以使用
echo "IMAGE_NAME=image-web-v4" >> $GITHUB_ENV
echo "IMAGE_TAG=registry.cn-hangzhou.aliyuncs.com/kasuie/web-v4:${{github.sha}}" >> $GITHUB_ENV
- name: Checkout # 使用actions/checkout@v4检出代码
uses: actions/checkout@v4
- name: Login to Ali Docker
uses: aliyun/acr-login@v1 # 因为我用的是阿里云的镜像服务,所以使用了阿里云的aliyun/acr-login@v1登陆阿里云docker仓库
with:
login-server: ${{secrets.ALI_DOCKER_REGISTRY}}
username: ${{secrets.ALI_DOCKER_USERNAME}}
password: ${{secrets.ALI_DOCKER_PASSWORD}}
- name: Build and push Docker Image
uses: docker/build-push-action@v5 # 使用docker/build-push-action@v5构建docker镜像,并上传到阿里云镜像仓库
with:
file: ./Dockerfile # 放在根目录下的Dockerfile文件,后面会讲,包含一组用于在 Docker 容器中自动执行的指令,指定构建自定义Docker镜像的步骤
push: true # 是否自动推送
tags: ${{env.IMAGE_TAG}} # 镜像的tag
pull-and-restart: # 指定这个job名为pull-and-restart
needs: build-and-push # 指定当前任务的依赖关系,即运行顺序,这里是这个job必须等待 build-and-push 成功完成才执行
runs-on: ubuntu-latest
steps:
- name: Set state
run: |
echo "DOCKER_NAMESPACE=kasuie" >> $GITHUB_ENV
echo "IMAGE_NAME=image-web-v4" >> $GITHUB_ENV
echo "IMAGE_TAG=********/****/****:${{github.sha}}" >> $GITHUB_ENV
- name: Login Server and Start
uses: appleboy/ssh-action@master # 使用appleboy/ssh-action@master登录远程服务器并重启服务
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USERNAME }}
key: ${{ secrets.PRIVATE_KEY }}
script: | # shell命令,这里是服务器上拉取镜像,删除旧版本镜像,以及重启对应容器服务
cd /usr/local/web/
docker login -u=${{secrets.ALI_DOCKER_USERNAME}} -p=${{secrets.ALI_DOCKER_PASSWORD}} ${{secrets.ALI_DOCKER_REGISTRY}}
docker-compose stop web-v4 && docker-compose rm web-v4
docker image rm $(docker image ls *镜像仓库地址* -q) || echo "删除镜像异常"
export IMAGETAG=${{env.IMAGE_TAG}}
docker-compose up -d web-v4
可以看到最后的shell
命令,使用export
设置了环境变量IMAGETAG
,也就是在上文compose
配置文件提到的环境变量,可以看到它是取的${{env.IMAGE_TAG}}
,而IMAGE_TAG
又是我每一次的运行工作流程都会写入到环境变量的echo "IMAGE_TAG=********/****/****:${{github.sha}}" >> $GITHUB_ENV
,其中的${{github.sha}}
是github对于每一次commit(提交)
生成的唯一标识,这样就可以把最新的镜像通过action
在服务器进行拉取和重新部署。
而其他例如${{secrets.ALI_DOCKER_REGISTRY}}
,${{secrets.REMOTE_HOST}}
等等是GitHub actions
工作流程的变量,这里是把镜像仓库信息和服务器信息设置成变量,你可以在对应仓库的Settings
面板新增:
需要注意的是PRIVATE_KEY
,它是你服务器的SSH私钥,是你登录服务器的凭证,第一次需要你在服务上面生成,首选运行ssh-keygen
,根据自己情况选择,最后在~/.ssh/
目录里面生成如下文件:
id_rsa
是私钥文件,id_rsa.pub
是公钥文件,然后~/.ssh/
目录下依次运行:
cat id_rsa.pub >> authorized_keys # 复制一份公钥到authorized_keys中
chmod -R 700 ~/.ssh # 修改文件权限
chmod -R 640 authorized_keys # 修改文件权限
若文件或目录不存在,可以自己创建,最后执行cat id_rsa
获得私钥内容,这就是这里需要填写的PRIVATE_KEY
以上workflow
配置文件中基本每一个命令我都注释了,虽然并不是特别复杂,但以此可大致的窥得全貌,然后就是Spring boot
中。
Spring Boot中的Workflows
和Next.js
相比,Spring boot
中除构建环节不一样,其他步骤几乎一样,以下是具体的actions.yml
的文件:
name: Web2 Docker Image CI
on:
push:
branches: [master]
workflow_dispatch:
jobs:
build-and-push:
runs-on: ubuntu-latest
name: Running and compile
steps:
- name: Set state
run: |
echo "IMAGE_TAG=${{secrets.DOCKER_REPOSITORY}}:${{github.sha}}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Login to Ali Docker
uses: aliyun/acr-login@v1
with:
login-server: ${{secrets.ALI_DOCKER_REGISTRY}}
username: ${{secrets.ALI_DOCKER_USERNAME}}
password: ${{secrets.ALI_DOCKER_PASSWORD}}
- name: Build and push Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{env.IMAGE_TAG}}
pull-and-restart:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Set state
run: |
echo "IMAGE_TAG=${{secrets.DOCKER_REPOSITORY}}:${{github.sha}}" >> $GITHUB_ENV
- name: Login Server and Start
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USERNAME }}
key: ${{ secrets.PRIVATE_KEY }}
script: |
cd /usr/local/web/
docker login -u=${{secrets.ALI_DOCKER_USERNAME}} -p=${{secrets.ALI_DOCKER_PASSWORD}} ${{secrets.ALI_DOCKER_REGISTRY}}
docker-compose stop web-api && docker-compose rm web-api
docker image rm $(docker image ls *镜像仓库地址* -q) || echo "删除镜像异常"
export APITAG=${{env.IMAGE_TAG}}
docker-compose up -d web-api
可以看到几乎和Next.js中的步骤一样,所以不再过多做说明,不同的地方在Dockerfile
文件中,所以下面就讲讲构建镜像了。
构建镜像
Dockerfile
是用于构建 Docker 镜像的文本文件,其中包含了一系列的指令和配置,用于定义容器镜像的构建规则和运行环境,通过它,你可以定义容器的内容、配置和运行时行为,使得容器的构建和部署过程变得自动化和可重复(当然你可以不使用容器部署,就不用这么麻烦,只需要在compose
文件将build
产物放到服务器,执行node server.js
就可以了)。
Next.js构建镜像
以下是我的Dockerfile
文件:
# 指定基础镜像为Node.js 18 版本的 Alpine Linux 并命名为base,以后可以通过这个名称引用。
FROM node:18-alpine AS base
# 从上一阶段的 base 镜像继续构建,创建一个新的镜像阶段,命名为 deps。
FROM base AS deps
# 安装 Alpine Linux 上的一个软件包libc6-compat,用于兼容性
RUN apk add --no-cache libc6-compat
# 指定工作目录为 /web-v4
WORKDIR /web-v4
# 将本地的 package.json、yarn.lock、package-lock.json、pnpm-lock.yaml 文件以及 /prisma`目录复制到容器中的 /web-v4 目录
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
COPY /prisma ./
# 安装依赖,sharp 是一个用于处理图像的库,我这里貌似配置不当,生成环境sharp老是报错,这里可以忽略掉关于它的命令,不安装也不会导致失败,只是nextjs应用的图形处理无法使用,然后,使用 npm ci`安装依赖,如果安装失败,则删除 node_modules 目录并退出构建
RUN set -eux; \
npm i sharp \
npm ci || { rm -rf node_modules; exit 1; };
# 如果你使用想要兼容其他包管理工具,以下可作参考
# RUN npm i sharp
# RUN \
# if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
# elif [ -f package-lock.json ]; then npm ci; \
# elif [ -f pnpm-lock.yaml ]; then npm install -g pnpm && pnpm i --frozen-lockfile; \
# else echo "Lockfile not found." && exit 1; \
# fi
#
# 从 base 镜像创建一个新的构建阶段,命名为 builder
FROM base AS builder
#指定工作目录
WORKDIR /web-v4
# 从之前的 deps 阶段复制依赖到当前阶段,然后将当前目录中的所有文件复制到容器的 /web-v4 目录
COPY --from=deps /web-v4/node_modules ./node_modules
COPY --from=deps /root/.npm /root/.npm
COPY . .
#开始构建
RUN npm run build
# 从 base 镜像创建一个新的运行阶段,命名为 runner
FROM base AS runner
WORKDIR /web-v4
# 添加一个系统用户组和用户,用于运行应用程序
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 创建 .next 目录,并设置所有者为新创建的用户和用户组
RUN mkdir .next
RUN chown nextjs:nodejs .next
# 设置环境变量 NODE_ENV 为 production,表示应用程序运行在生产环境下。同时,设置 NEXT_SHARP_PATH`变量用于防止找不到 `sharp`
ENV NODE_ENV production
ENV NEXT_SHARP_PATH /wev-v4/node_modules/sharp
# 从之前的 builder 阶段复制构建好的静态文件和应用程序到当前阶段
COPY --from=builder /web-v4/public ./public
COPY --from=builder --chown=nextjs:nodejs /web-v4/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /web-v4/.next/static ./.next/static
# 切换用户到 nextjs 用户
USER nextjs
#可以指定运行的端口,next应用默认是3000
# ENV PORT 3000
# 这里如果不是使用docker compose,容器运行成功但访问不了可以尝试把HOSTNAME 设置为 “localhost”
# ENV HOSTNAME "localhost"
# 定义容器启动时运行的默认命令,这里是运行 server.js 文件
CMD ["node", "server.js"]
详细的注释我也写上了,大致是这样的,在Github actions
中使用该配置构建后然后就可以上传到镜像仓库了。
搭配Prisma
Prisma是一个功能强大的数据库工具和 ORM 框架,在之前的文章中有提到:Next.js 踩坑记录,这里多做介绍了。
如果你要在项目中进行使用,依次执行如下命令
npm install prisma --save-dev # 安装依赖
npx prisma init # 初始化
初始化之后会在根目录下创建一个 .env
(如果没有的话)文件和一个 prisma
目录,.env
文件用于定义环境变量(例如数据库连接),prisma 目录下生成了一个 schema.prisma
文件,schema.prisma
文件包含带有数据库连接变量和模式模型的 prisma
模式
在.env
文件定义数据库连接变量:DATABASE_URL="mysql://username:mysql_password@localhost:3306/db_name?schema=public
在schema.prisma
文件中使用该环境变量:
我用的是Mysql
,当然你也可以选择其他的,截止我写这篇文章为止它还支持PostgreSQL
、MongoDB
、SQL Server
和SQLite
,如果你不是Mysql
需要改动一下provider = "mysql"
,改成自己使用的数据库即可。
在`
设置完成并且没有问题后,如果使用的数据库中已有表,这个时候可以运行 npx prisma db pull
,通过 这个prisma
的命令来帮我们查询数据库,并且在schema.prisma
文件中自动生成数据模型定义描述,可以看到很多的model
,这就是数据库中的表的映射模型。
当然你可能新建的数据库,如果是以schema.prisma
文件为切入点,想要将变更同步到数据库,那么你可以在schema.prisma
文件中手动新建model
,也就是数据库表,类似于上图一样的格式,不过手动可能需要一点基础知识,建好之后,执行命令npx prisma db push
,执行之后会自动检测数据模型文件的变更,并应用这些变更到数据库中。
到这里数据库的连接和定义描述算是没有问题了,接下来需要安装并生成prisma
客户端,这样才能和数据库进行CRUD
,通过 Prisma Client
来进行数据库交互,执行命令 npm install @prisma/client
。由于 Prisma Client
是根据您的schema定制的,因此每次 schema.prisma
文件发生更改时,您都需要通过运行prisma generate
来更新它,当你安装@prisma/client
时,他会自动执行prisma generate
,因此首次并不需要执行prisma generate
。
接下来是使用,你需要创建一个 PrismaClient
实例,可以将其导入到任何需要的文件中使用该实例,如下:
// lib/prisma.ts
import { PrismaClient } from "@prisma/client";
declare global {
var prisma: PrismaClient | undefined;
}
const prisma = global.prisma || new PrismaClient();
if (process.env.NODE_ENV === "development") global.prisma = prisma;
export default prisma;
然后就可以愉快的使用了~ 在需要的地方导入import prisma from "@/lib/prisma";
然后使用,例如我查询一个用户:
await prisma.t_user.findUnique({
where: {
password: Encrypt(password),
username,
},
});
到这里就可以进行基本的食用了,感兴趣可以进一步了解
最后需要注意的就是构建Next.js
镜像的时候,要把schema.prisma
也复制出来(参考上面的dockerfile
文件),如果出现prisma
的报错,有可能你需要在build
之前,加上命令 RUN npx prisma generate
,保证是正确的Prisma Client
,还有就是因为Mysql
是使用的容器,因此本地开发和构建的时候数据库连接会有所变化,应使用docker compose
的服务名连接,例如DATABASE_URL="mysql://username:mysql_password@mysql:3306/db_name?schema=public"
Spring Boot构建镜像
Spring boot
构建相较于Next.js
稍微简单一点,以下是我的Dockerfile
文件:
# 使用 Maven 3.6.3 和 OpenJDK 8 作为构建阶段的基础镜像。这个阶段用于构建应用程序
FROM maven:3.6.3-openjdk-8 AS build
# 设置工作目录为 /web-api
WORKDIR /web-api
# 将项目的 pom.xml`文件和 src 目录拷贝到容器的 /web-api 目录
COPY pom.xml .
COPY src ./src
# 运行 Maven 命令,执行项目的 `clean` 和 `package` 阶段,将构建的 jar 文件从 /web-api/target/ 目录复制到 /web-api 目录,并重命名为 web-api.jar
RUN mvn clean package \
&& cp /web-api/target/*.jar web-api.jar
# 使用 OpenJDK 8 的 JRE 版本作为最终镜像的基础镜像
FROM openjdk:8-jre-alpine
# 设置最终镜像的工作目录为 /web-api
WORKDIR /web-api
# 从前一个构建阶段 (`build`) 中复制构建好的 web-api.jar 文件到最终镜像的当前目录
COPY --from=build /web-api/web-api.jar ./
# 设置 Java 虚拟机的启动参数,包括 `-server` 表示使用服务器模式,以及设置为初始堆大小(-Xms)和最大堆内存(-Xmx)
ENV JAVA_OPTS="-server -Xms256m -Xmx512m"
# 暴露容器的 8001 端口,表示该容器应用程序监听在该端口上
EXPOSE 8001
设置容器启动时执行的默认命令
ENTRYPOINT ["java","-jar", "web-api.jar"]
# 设置镜像的作者信息
MAINTAINER kasuie
它们打包需要的基础镜像不一样,后面的打包步骤也不一样,使用该配置构建后上传到镜像仓库
需要注意的是,Spring boot
项目里面连接Mysql
和Redis
的信息是在Docker compose
配置文件通过环境变量注入的,需要配合进行修改,如果设置不当,会导致数据库连接失败。
至此,两个镜像的自动化部署时的构建过程就算是说完了。
MySql 和 Redis
这部分是题外话,不讲具体的过程了,反正也是用的官方镜像,只是简单说一下我在部署的时候,遇到的几个坑,一个是Mysql
和Redis
连接不上,这个需要注意在运行的时候用服务名+端口连接,还有统一各个服务运行时的时区,另一个是进行数据数据持久化的时候,注意一下文件的权限,有可能服务没权限导致出问题。
最后
放一下自己的actions
面板:
❗一共失败了 67 次,这还只是Next.js
的部分,还不包括后端服务,至少尝试了100次,有些成功了也未必算成功。
总之以上都是自己一步一步踩坑得到的,当然也并不代表完全正确,根据实际情况看吧,或者也有错误地方,欢迎指正~
可以看到我前端项目名是web-v4
,是的现在又重构了一个版本了,之前是Next.js
的pages
路由,现在是app
路由,以前如果我要部署的话,大概流程是先在本地打包,打包后,需要将生产文件上传至服务器解压缩到对应文件夹,服务器停止对应服务,必要的话需要删除旧的文件夹,里面包含文件很多删除都挺费时间的,最好再重启,来回折腾的话大概十分钟起步吧。使用自动化部署,将为你节省这十分钟,让你可以干其他事情,还是蛮不错的👏。
- 地点: 成都
- 心情:自由的小猫在冬天会被冻死,有点不喜欢冬天了