如何使用 github actions 实现 Nest 项目自动化部署

2,221 阅读8分钟

好久没发文章了,久到连朋友都开始催我了

这是昨天晚上跟成哥的对话,既然说了今天产出一篇,那今天就一定要产出一篇!

今天就来讲一下前端通往全栈的最后一公里叭,Nest 项目的自动化部署。

初识 Nest.js

先来简单介绍一下 Nest。

Nest 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)并结合了 OOP(面向对象编程),FP(函数式编程)和FRP(函数式响应编程)的元素。

在底层,Nest 使用强大的 HTTP Server 框架,如 Express(默认) 和 Fastify。Nest 在这些框架之上提供了一定程度的抽象,同时也将其 API 直接暴露给开发人员。这样可以轻松使用每个平台的无数第三方模块。

Nest 也提供了一个开箱即用的应用程序架构,允许开发人员和团队创建高度可测试、可拓展、松散耦合且易于维护的应用程序。

由于本文不是专门写 Nest 开发相关的内容,所以就只介绍这么多,有兴趣的可以自行去 Nest 官网了解更多(nestjs.com/)。

还有一点 Nest !== Next.js。它们两个真的是一点关系都没有,如果真的要说有关系,那可能就是他们都跟 JavaScript有点关系。Next.js 是一个 React 应用程序开发框架,他是基于 React的SSR和SSG的框架,用于构建高性能的 Web 应用程序和静态网站。所以,跟 Nest 真的关系不大,有很多同学会把他们搞混,我这里必须要为 Nest 正名!

emmmm……不好意思,扯远了扯远了。

开始正文

老传统

在讲自动化之前先讲一下传统的部署方案。

  1. 将本地资源上传到服务器上。
  2. 安装依赖
  3. 打包
  4. 启动服务

自动化部署其实也是这么个流程,只是把整个流程通过流水线作业的形式自动完成,减少开发的任务量以及在部署过程中的出错的概率,毕竟只要指令正确,机器是不会出错的~

自动化

首先,要实现 Nest 项目的自动化部署,那么首先一定要有一个 Nest 项目叭。

我这里已经准备好了,这是我一个练手的项目,把 realworld 的接口都写了一遍。

项目有了之后,在项目的最外层建一个 .github/workflows 的目录,在该目录下创建一个 deploy.yml

编写脚本:

name: Deploy to CentOS Server

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Copy files to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          password: ${{ secrets.SERVER_PASSWORD }}
          source'./'
          target: /home/apps-server/realworld-server/

      - name: SSH to server and restart application
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          password: ${{ secrets.SERVER_PASSWORD }}
          script: |
            cd /home/apps-server/realworld-server
            npm install
            npm run build
            pm2 restart ./dist/src/main.js --name realworld-server

作为一个前端er,我怎么会看得懂这些!这不是运维的兄弟搞得嘛?!

emmmm,看不懂没关系,只要知道语句的意思之后,还是很好理解的。接下来来挨个儿解释一下:

  • name: 定义步骤的名称,github action 的脚本执行的时候是像流水线一样按步骤一步一步来的,nam 就是给每一个步骤加一个名称,用来标明这个步骤是在做什么事情,也可以理解为流水线上的每个工种的工种名称。 比如这里的 name:

  • 对应在git action 里边就是:

  • on: 定义触发 Github Actions 运行的事件类型,这里触发的是 push,分支 branchmaster,也就是当我们向 master 分支 push 代码的时候,会出发当前的流水线作业。
  • jobs: 定义一个或多个需要执行的作业。
  • deploy: deploy 语句通常用于部署代码或应用到目标环境,例如生产环境或测试环境。 jobs 下边可以有多个 deploy
name: Deploy to Production and Staging

on:
  push:
    branches:
      - master

jobs:
  deploy-to-production:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      # Add steps for deployment to production environment

  deploy-to-staging:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      # Add steps for deployment to staging environment

例如这段代码,在向maste分支推代码的时候,会执行流水线上的 deploy-to-productiondeploy-to-staging。哦,对了,需要注意的是,这两个job是并行执行的。

  • runs-on: 用于指定在哪个操作系统中运行 job,它允许你在 github actions 中选择一个特定的虚拟机作为 job 的运行环境。它的值可以有这几种形式:

    1. 操作系统名称:例如:ubuntu-latestmacos-latestwindows-latest,分别表示最新版本的 UbuntumacOSWindows 操作系统。
    2. 操作系统版本号:ubuntu-20.04macos-11.3windows-2019,分别表示特定版本的 UbuntumacOSWindows 操作系统。
    3. 自定义虚拟机镜像名称,例如:my-centos-image,表示使用你自己定义的虚拟机镜像。 在每个 job 中可以使用 runs-on 指定不同的操作系统,你可以根据需要选择合适的操作系统环境来执行不同的构建、测试、部署等操作。
  • steps: 定义作业中需要执行的作业。

    • name: 也就是任务名称,跟上边的name是一样的

    • uses: 引用外部的 Action,可以是 github上的 Action 或者是 Docker 镜像。

      • 这里第一步使用了 actions/checkout@v2,它是一个预定义的 github Actions action,用于从指定的仓库中检出代码到当前工作流的工作目录,以便后续步骤可以在该工作目录中执行操作。
      • 第二步使用了 appleboy/scp-action@master,它是一个自定义的 github Actions action,用于执行 SCP(Secure Copy Protocol) 命令,用于在不同计算机之间进行文件传输,可以通过配置 hostusernameport 等参数来设置 SSH 连接参数;source 是你要复制的资源文件,target 是复制之后输出的位置。这里是把上一步检出的内容(也就是master分支)输出到服务器上的 /home/apps-server/realworld-server/
      • 第三步使用了 appleboy/ssh-action@master,他是一个 github Actions 自定义的一个 Action,用于在 github Actins 工作流中通过 SSH 远程执行命。它可以用于与远程服务器交互,例如部署应用程序、执行远程命令、上传文件等等;也可以通过配置 hostusernameport 等参数来设置 SSH 连接的参数,并通过 script 参数来指定要执行的指令。
    • with: 用来定义步骤的参数和配置。比如 appleboy/scp-action@masterappleboy/ssh-action@master 中的主机名和用户名以及用户密码。

有些同学可能会问:secrets.SERVER_HOSTsecrets.SERVER_USERNAME 这些东西是从哪来的啊?要怎么用呢?

这些其实是在 github 仓库中配置的一些变量,在执行流水线作业的时候会自动读取。

进入到项目的仓库之后,选择 settings tab下的 Actions,然后直接点击 New repository secret 创建就可以了。

SERVER_HOST 就是你的服务器IP地址,如果是云服务器的话就是公网地址。 SERVER_USERNAME 就是登录服务器的用户名。 SERVER_PASSWORD 是登录服务器的用户密码。

可以在仓库的 Actions tab中查看执行了哪些流水线作业,以及任务的状态

点击进去可以查看任务执行的整个流程,以及每一步发生了什么事。

在这里我们可以看到,流水线已经执行完成,并且 pm2 也启动了 realworld-server 的服务。

我们在进入到服务器立板验证一下看看:

现在项目确实已经正常的copy过来了,并且也已经安装了依赖。再来看一下pm2 的 list 里边是否有这项任务:

这里也是正常的。

那要如何检验是否部署成功呢?我在写这些接口的时候也是写了 Swagger 文档的,如果部署成功, Swagger 文档肯定是可以访问的,所以我们来试一下 Swagger 文档能不能访问就好了~

一切正常~

到这里部署的流程其实已经结束了,但是地址是 IP 地址,端口号是 10086……,这实在不怎么好看,而且 ip 也太难记了,所以我想给他解析到我自己的域名上。

打开腾讯云,进入到 DNS 解析 DNSPod 的页面,进入到我的域名下边,然后再操作里边选择解析。

添加一条记录

这样就可以在你的域名上边加一条二级域名

接下来访问一下试试~

非常 Nice~

讲到这里,全文结束~

(哦, 对了,realworld-server 的仓库暂时还是 private 的状态,等我去掉一些敏感信息之后就开源出来~,可能……大概……两三天时间?我比较拖延……)