使用 GitHub Actions 自动化部署 全栈个人博客项目

lxf2023-03-18 18:01:01

引言

最近有在陆续地为自己的“全栈个人博客网站”增添一些新的功能,但每次开发完毕后都需要手动地将整个项目重新部署到服务器,且该过程十分繁琐。诸如:将前端代码打包到指定路径(生产环境);在本地压缩代码并上传到服务器;在服务器解压代码并移动到指定路径;进入工程文件夹并安装项目依赖;执行指令以重新运行项目等。部署成功之后,如果发现某些被漏掉的BUG,则要继续重复上述流程,繁琐至极。

那么,有没有什么办法能够将上述重新部署的流程自动化呢?

当然有,而且有很多方法!由于该项目是托管到GitHub上的,因此采用“GitHub Actions”方案来实现。最终效果为:每次开发完毕后,我们只需要将整个“前后端”项目push到GitHub,项目就会被自动化部署到服务器。

概念初探

  • Workflow(工作流)

    即工作流程,是一个可配置的自动化过程,它将运行一个或多个任务。 工作流程由工程根目录/.github/workflows路径下的 YAML 文件定义,在该文件中我们可以监听某些事件,当事件被触发后则会进入到对应的工作流程。

  • Job(任务)

    一个工作流程中包含一个或多个任务,一个任务由若干个步骤组成。

  • Step(步骤)

    一个任务可以包含一个或多个步骤,且上述步骤会被依次执行。

  • Action(动作)

    每个步骤可以包含一个或多个动作,诸如一些实际的指令(npm install等)。

使用 GitHub Actions 自动化部署 全栈个人博客项目

语法简述

  • name

    工作流程(workflow)的名称,会在 GitHub 相应的 UI 界面上显示。 如果省略 name,GitHub 会将其设置为相对于仓库根目录的工作流程文件路径。

    name: GitHub Actions Test
    
  • on

    触发工作流程(workflow)的事件,更多可用事件的列表,请参阅“触发工作流程的事件”。

    # 单个事件
    on: push # 将任何分支push到仓库时,将运行具有上述 on 值的工作流程
    
    # 多个事件
    on: [push, fork] # 将任何分支push到仓库或有人fork仓库时,将运行具有上述 on 值的工作流程
    
    # 筛选器
    on:
      push:
        branches:
          - main # 当main分支发生push操作时,将执行所属工作流程
    
  • jobs

    jobs 包含当前工作流程中的所有任务,每个任务会在 runs-on 指定的运行器环境中运行,常用的关键字段如下:

    • jobs.<job_id>

      jobs 中的每个任务都有一个<job_id> ,且其必须为 jobs 对象中唯一的字符串键值。<job_id>必须以字母或_开头,并且只能包含字母数字字符、-_

      jobs:
        my_first_job:  # <job_id>,任务id
          name: My first job
        my_second_job:
          name: My second job
      
    • jobs.<job_id>.name

      该字段用以指定当前任务的名称,且其将会展示在 GitHub 对应的 UI 界面上。

      jobs:
        my_first_job:  
          name: My first job  # <job_id>.name,任务名称
        my_second_job:
          name: My second job
      
    • jobs.<job_id>.needs

      该字段用以指定各个任务之间的依赖关系。

      jobs:
        job1:
        job2:
          needs: job1
        job3:
          needs: [job1, job2]
      

      上述代码中,job1 必须在 job2 开始之前成功完成,而 job3 要等待 job1job2 完成。最终运行顺序为:job1job2job3

    • jobs.<job_id>.runs-on

      该字段用来指定任务将在哪个虚拟环境中运行。如果使用 GitHub 托管的运行器,每个作业将在 runs-on 指定的虚拟环境的新实例中运行。

      runs-on: ubuntu-latest
      

      可用的 GitHub 托管的运行器类型包括:

      使用 GitHub Actions 自动化部署 全栈个人博客项目

      虚拟环境-latest是 GitHub 提供的最新稳定映像,可能不是操作系统供应商提供的最新版本的操作系统。

    • jobs.<job_id>.steps

      每个任务会包含一系列步骤,称为 steps。 在步骤中,可以运行命令、运行设置任务,或者运行您的仓库等操作。 并非所有步骤(step)都会运行操作(action),但所有操作(action)都会作为步骤(step)运行。

      每个步骤一般会包含下面三个字段:

      jobs.<job_id>.steps.name:该步骤的名称。
      jobs.<job_id>.steps.run:该步骤需要执行的命令,如 npm install
      jobs.<job_id>.steps.env:该步骤所需的环境变量。
      

      当然,也可以使用其他大佬封装好的 action,详见 actions 市场。

      steps:
        - name: Use extra action
        - uses: actions/checkout@v3
      

      更多语法,详见官方文档:GitHub Actions

部署流程

1. 项目概览

  • 项目预览:hechunxu.tech

  • 项目地址:github.com/Allen-He/my…

  • 项目描述:即“全栈个人博客网站”,前端使用 Vue2.x,后端使用 NodeJS & Express。如下是该项目的主要工程目录结构。

    • client(前端工程目录)—— 可执行命令

      • npm run serve:开发环境下启动项目(本地)
      • npm run build:生产环境下打包代码(打包结果的存放路径为:/server/public/
    • server(后端工程目录)—— 可执行命令

      • npm run server:开发环境下启动项目(本地)

      当访问对应的 URL 地址时,该后端工程会进入/server/public/目录获取对应的前端页面及静态资源。

      使用 GitHub Actions 自动化部署 全栈个人博客项目

2. 开始部署

注意:

  • 期望效果:每次开发完毕后,我们只需要将整个“前后端”项目push到GitHub,项目就会被自动化部署到服务器。
  • 基础前提:已预先将项目成功托管到了GitHub上,并且此前已经手动地完成了服务器端的首次部署(即保证在服务器端已搭建好项目所需的运行环境)。则可继续如下步骤。

新建 .yml 文件

  1. 进入GitHub上的对应仓库,点击“Actions”以进入“GitHub Actions”开始页,接着点击“setup a workflow your self”以新建默认的yaml文件。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

  2. 点击“Start commit”按钮,在弹出框中输入自定义的commit信息,并点击“Commit new file”按钮以提交上述操作。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

  3. 上述步骤完成之后,一方面,可发现该项目的根目录下新增了一个.github/workflows目录,其中存放着一个main.yaml配置文件;另一方面,可发现现在已经成功执行了一次工作流程(如下图所示)。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

    使用 GitHub Actions 自动化部署 全栈个人博客项目

  4. 此时,已经成功地在GitHub上的项目工程目录中创建好了yaml文件。然后,在本地执行一次git pull命令以同步远程main分支的最新代码,即可在本地通过 VSCode 编辑器查看并配置 main.yml 文件的内容。main.yml 文件的初始内容如下:

    # This is a basic workflow to help you get started with Actions
    name: CI
    
    # Controls when the workflow will run
    on:
      # Triggers the workflow on push or pull request events but only for the "main" branch
      push:
        branches: [ "main" ]
      pull_request:
        branches: [ "main" ]
    
      # Allows you to run this workflow manually from the Actions tab
      workflow_dispatch:
    
    # A workflow run is made up of one or more jobs that can run sequentially or in parallel
    jobs:
      # This workflow contains a single job called "build"
      build:
        # The type of runner that the job will run on
        runs-on: ubuntu-latest
    
        # Steps represent a sequence of tasks that will be executed as part of the job
        steps:
          # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
          - uses: actions/checkout@v3
    
          # Runs a single command using the runners shell
          - name: Run a one-line script
            run: echo Hello, world!
    
          # Runs a set of commands using the runners shell
          - name: Run a multi-line script
            run: |
              echo Add other actions to build,
              echo test, and deploy your project.
    

    阅读上述默认文件内容时,记得参照上文所讲的相关概念及语法。相信你一定可以理解的!!!

配置 .yml 文件

话不多说,完整的配置内容如下:

name: Auto Deploy # 当前工作流程的名称
on: 
  push: 
    branches: 
      - main # 只要push到main分支,就会触发该工作流程
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      # 使用别人封装好的的action,用于clone该仓库的源码到工作流中
      - name: Checkout
        uses: actions/checkout@v3

      # 在工作流中安装node环境(必需,这样才能在后续工作流程中运行 npm install 等指令,否则会报错
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 16 # 指定node版本
          
      # 打包代码生成环境
      - name: Build
        run: |
          cd client # 进入前端侧的工程目录
          npm install # 安装依赖
          npm run build # 打包前端代码到生产环境(目标路径为:server/public)

      # 同步server目录下的后端代码到服务器(目标路径:/home/nginx/myBlogServer)
      - name: Deploy
        uses: cross-the-world/scp-pipeline@master
        with:
          host: ${{ secrets.MY_HOST }} # 服务器IP(需要在GitHub上自行配置对应的secret)
          user: ${{ secrets.MY_USER }} # 服务器用户名
          pass: ${{ secrets.MY_PASS }} # 服务器密码
          connect_timeout: 10s
          local: './server/*' # 源路径(工作流)
          remote: /home/nginx/myBlogServer # 目标路径(服务器)
      
      # 在服务器端执行相关指令
      - name: Executing remote ssh commands
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.MY_HOST }} # 服务器IP(需要在GitHub上自行配置对应的secret)
          username: ${{ secrets.MY_USER }} # 服务器用户名
          password: ${{ secrets.MY_PASS }} # 服务器密码
          script: |
            cd /home/nginx/myBlogServer # 进入服务器中的端工程所在的目录
            export NODE_HOME=/root/.nvm/versions/node/v12.19.0  # 可使用`whereis node`查询node所在的目录
            export PATH=$PATH:$NODE_HOME/bin # 重新定义node的环境变量(必需,这样才能在后续工作流程中运行 npm install 等指令,否则会报错)
            npm install # 安装项目依赖
            pm2 delete myBlogServer # 删除旧的进程
            pm2 start --name myBlogServer npm -- run server # 启动新的进程

上述代码中所用的第三方Actions,在 Actions 市场 都可以找到使用文档,如:cross-the-world/scp-pipeline@master、appleboy/ssh-action@master 等。

上述配置的整体思路为:

  • 监听main分支的push事件,当上述事件被触发(即本地向远程仓库的main分支push最新代码时)时,运行名为"Auto Deploy"的工作流程。

  • 该工作流程中有一个名为“build-and-deploy”的任务,且该任务运行在“ubuntu-latest”虚拟环境下。通过依次执行其包含的多个步骤,可实现整个自动化部署功能。

    • 使用actions/checkout@v3将对应仓库的源码克隆到当前工作流中

    • 使用actions/setup-node@v3在工作流中安装node环境(必需运行该步骤,这样当前工作流的后续步骤才可以运行npm install等指令,否则会报错)

    • 从根目录进入到前端工程目录client,安装项目依赖,并将前端代码打包到“后端工程目录client”中的public文件夹中(后续,该后端工程在服务器本地启动之后,便会按早预期从public文件夹下获取到最新的前端页面及静态资源)

    • 使用cross-the-world/scp-pipeline@master将“后端工程目录client”中的所有内容通过scp传输到服务器端的指定路径下

    • 使用appleboy/ssh-action@master在服务器端执行一系列指令操作:

      • 进入上述后端工程所在路径

      • 重新定义node的环境变量(防止后续执行 npm 指令时报错)

      • 安装项目依赖

      • 执行pm2 delete myBlogServer指令删除旧的进程(myBlogServer为旧版项目启动时的进程名)

      • 执行pm2 start --name myBlogServer npm -- run server指令启动新的进程(myBlogServer为新版项目启动时的进程名,必须与旧版的保持一致)

        此时,当前工作流程结束,项目将会成功地重新部署 ~~~

配置 GitHub Secrets

出于安全考虑,在配置 yaml 文件的内容时,我们并没有直接将服务器的 IP、服务器的用户名、服务器的密码等信息直接写在文件中,而是需要从 GitHub 的 secrets 中读取。那么,GitHub secrets 的配置方法如下:

  1. 点击“Settings”进入设置页,点击左侧菜单栏的“Secrets --- Actions”菜单项进入 secret 添加页,点击右上角的“New repository secret”按钮,即可添加自定义的 secret。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

  2. 按照下图提示配置自定义的 secret,并点击“Add secret”按钮确定添加。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

    添加成功后,就可以看到如下结果。

    使用 GitHub Actions 自动化部署 全栈个人博客项目

功能测试

完成上述步骤之后,我们便可以在本地修改项目源码,并推送到GitHub的远程main分支,以测试上述“GitHub Actions”配置是否生效。

当我们push成功之后,对应的actions便会被自动运行,帮助我们自动化重新部署项目。可在GitHub的UI界面中查看其运行情况。

使用 GitHub Actions 自动化部署 全栈个人博客项目

使用 GitHub Actions 自动化部署 全栈个人博客项目

使用 GitHub Actions 自动化部署 全栈个人博客项目

如果部署成功之后,会出现以下结果。

使用 GitHub Actions 自动化部署 全栈个人博客项目

使用 GitHub Actions 自动化部署 全栈个人博客项目

如果部署失败,会在对应工作流程运行的详情页中输出详细的报错信息,可以根据报错信息定位问题所在并解决。

总结

以上便是本文的全部内容,相信你已经能够让自己的项目实现“GitHub Actions”自动化部署啦!若有疑问,欢迎在评论区交流!!!

参考文档

  • GitHub Actions 官方文档
  • Github Actions 自动化部署 Vue3 博客项目
  • 使用Github Actions来实现项目的CI/CD
  • GitHub Actions自动化部署前端项目指南

PS:本文内容仅供交流学习,转载请注明出处。