Github Action实践

本篇记录利用 github action 实现自动化构建和部署的过程。

本站除了部署在 github page 上,还部署在本人的服务器上,懒惰的 ddl 直到现在才去上手实验,因此利用在 github action 中实现两种部署方式。

Github Action 是 Github 提供的持续集成服务,可以在代码仓库中配置 workflow,实现自动化构建、测试、部署等功能。

有一些术语需要了解:

  • Workflow:一个 workflow 由一个或多个 job 组成,可以在不同的操作系统环境中运行。
  • Job:一个 job 由一系列 step 组成,可以在同一个 runner 上运行。
  • Step:一个 step 由一个或多个 action 组成,可以在同一个 runner 上运行。
  • Action:一个 action 是一个独立的任务,可以在不同的 runner 上运行。

这里我使用的是 github action 自带的SSH Deploy action,使用 ssh 链接远程服务器,将代码部署到服务器上。使用方法可以参考这里

首先需要在服务器上生成一个 SSH Key,用于 github action 登录服务器。

1
ssh-keygen -m PEM -t rsa -b 4096

key 的生成过程中会提示输入密码,可以不输入,直接回车,默认保存在/root/.ssh目录下(这个可能不同的服务器环境会有区别,具体的默认位置在生成ssh-key的时候命令行有提示。

生成的 key 包含一个私钥id_rsa和一个公钥id_rsa.pub,私钥保存在本地,我们需要将公钥添加到服务器的/root/.ssh/authorized_keys文件中。

1
cat ./id_rsa.pub >> /root/.ssh/authorized_keys

考虑到我们并不想把私钥暴露在 github 公开仓库上,我们需要将私钥id_rsa添加到 github 的 secrets 中。

在仓库的Settings->Security->Secrets and variables->Actions中,选择New repository secret,添加一个SSH_PRIVATE_KEY,将私钥内容粘贴进去。

再新建三个 secrets,分别是REMOTE_HOSTREMOTE_USERREMOTE_TARGET,分别对应服务器的地址、用户名、目标路径。

在代码仓库的.github/workflows目录下创建一个.yml文件,文件名可以自定义,如deploy.yml

一个库可以有多个 workflow,github 只要发现.github/workflows目录下有.yml文件,就会自动运行 workflow。

内容可以参考如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
name: Deploy

# 触发条件
on:
  push:
    branches: [main]
  workflow_dispatch: # 手动触发

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "16.x"
      - name: ssh deploy
        uses: easingthemes/ssh-deploy@v5.0.3
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          ARGS: "-rlgoDzvc -i"
          SOURCE: ""
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          TARGET: ${{ secrets.REMOTE_TARGET }}

向 github 仓库 push 代码之后,我们在Actions选项卡中可以看到 workflow 的运行情况。假如运行失败,可以点进去查看具体的错误信息,进行调试。

之后每次 push 到 main 分支或者手动触发 workflow,github action 就会自动运行 workflow,将代码部署到服务器上。

之前部署的时候只上传了public/文件夹,最近有同步源码的需求,但是源码包含一些隐私信息,并不适合上传到 github 的公开仓库,所以现在的需求是:

  • 将源码上传到一个私有仓库
  • 从私有仓库中将public/文件夹同步到<username>.github.io公开仓库中,并部署到github page

因此新增了一个在源码仓库根目录下的 workflow,将源码上传到私有仓库,通过 hugo 官方提供的 action,将生产的站点文件同步到<username>.github.io公开仓库中。

首先在 github 上创建一个私有仓库,用于存放源码。

在 github 的Settings->Developer settings->Personal access tokens中,点击Generate new token,勾选repo权限,生成一个 token,将 token 复制下来。

在源码仓库的Settings->Security->Secrets and variables->Actions中,添加一个ACTION_ACCESS_TOKEN,将刚刚生成的 token 粘贴进去,这个命名要和 workflow 文件中的一致。

在私有仓库的.github/workflows目录下创建一个gh-page.yml文件。

文件内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
name: github pages deploy

on:
  push:
    branches:
      - main

permissions:
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3 # 引用actions/checkout这个action,与所在的github仓库同名
        with:
          submodules: flase # 是否获取子模块
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3

      - name: Setup Hugo # 步骤名自取
        uses: peaceiris/actions-hugo@v3 # hugo官方提供的action,用于在任务环境中获取hugo
        with:
          hugo-version: "latest" # 获取最新版本的hugo
          extended: true

      - name: Build
        run: hugo --minify # 使用hugo构建静态网页

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v4 # 一个自动发布github pages的action
        with:
          # github_token: ${{ secrets.GITHUB_TOKEN }} 该项适用于发布到源码相同repo的情况,不能用于发布到其他repo
          external_repository: Florae006/Florae006.github.io # 发布到哪个repo
          personal_token: ${{ secrets.ACTION_ACCESS_TOKEN }} # 发布到其他repo需要提供上面生成的personal access token
          publish_dir: ./public/ # 注意这里指的是要发布哪个文件夹的内容,而不是指发布到目的仓库的什么位置,因为hugo默认生成静态网页到public文件夹,所以这里发布public文件夹里的内容
          keep_files: true # 是否保留其他文件
          publish_branch: main # 发布到哪个branch
          commit_message: ${{ github.event.head_commit.message }} # 提交信息

由于现在的xxx.github.io对应的仓库是在GitHub action中构建站点后直接commit同步的,故原来在公开仓库中的workflows并不方便添加到这个commit里,我这里的解决思路是将原来ssh连接云服务器进行deploy的代码进行修改,添加自动构建内容,再直接用ssh连接到云服务器,完成云服务器的内容更新。修改后的remote-deploy.yml参考如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
name: Deploy to remote server

# 触发条件
on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Install Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '16.x'

    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: 'latest'
        extended: true

    - name: Build
      run: hugo --minify

    - name: ssh deploy
      uses: easingthemes/ssh-deploy@v5.1.0
      with:
        SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
        ARGS: "-rlgoDzvc -i"
        REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
        REMOTE_USER: ${{ secrets.REMOTE_USER }}
        TARGET: ${{ secrets.REMOTE_TARGET }}
        SOURCE: "public/"
        # SCRIPT_BEFORE: |
        #   whoami
        #   ls -al
        # SCRIPT_AFTER: |
        #   cd ${{ secrets.REMOTE_TARGET }}
        #   ls -al
        #   pwd
        #   echo "Deployed successfully"