自动构建 Hugo 博客部署至腾讯云对象存储 COS 并刷新 CDN

使用 Github Action,自动构建 Hugo 博客并部署至腾讯云 COS 静态存储,并触发 CDN 刷新。

hugo 和 hexo 都是静态博客,将最终构建生成的静态文件放置到 web 服务器即可访问。通过 Github Action 构建静态博客并发布到 GitHub Pages 十分简单,但是考虑到国内访问速度问题,还是选择了国内服务商来承载博客。

之前使用 hexo 时有插件可以比较方便的通过 hexo g && hexo d 自动部署到阿里云或腾讯云的对象存储,hugo 没有找到现成的轮子,看了下腾讯云对象存储的文档,发现借助 Github Action 自动上传挺简单的,记录一下。

自动构建

在博客仓库根目录下新建 .github/workflow 文件夹,新建一个 deploy.yaml(文件名随意),指定触发条件:

1
2
3
4
5
6
7
name: Build and deploy

on:
  workflow_dispatch:    # 触发方式 1: 手动触发
  push:                 # 触发方式 2: push 到 master 分支时自动触发
    branches:
      - master

紧接着继续写自动构建工作流部分:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true      # 下载子仓库,即主题仓库
          fetch-depth: 0

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

      - name: Build
        run: hugo --minify

整个工作流主要包括三个部分:

  • 拉取代码仓库
  • 准备 Hugo 环境
  • 构建静态页面

这样,即完成了触发工作流时自动构建静态页面的配置,当工作流被触发时,便会生成静态文件放置在 publish 目录下。

部署至对象存储

准备工作

部署到对象存储之前,首先要完成一些使用对象存储发布静态页面的基本配置。下面以我正在使用的腾讯云为例演示。

首先到 对象存储控制台 创建一个 bucket,访问权限设置为 公有读私有写(如果后面会套一层 CDN,建议使用私有读写,并且在回源时开启鉴权)。

https://img.rneko.com/upic/2022/08232225_ACw4UB.png

创建成功后,到 基础配置 - 静态网站 中开启静态网站托管。

https://img.rneko.com/upic/2022/08232227_cowBHS.png

如果要使用 CDN 进行加速,到 域名与传输管理 - 默认 CDN 加速域名 - 自定义 CDN 加速域名 中添加你的域名,国内加速需要备案,海外加速可使用未备案的域名。

源站类型为 静态网站源站,如果前面选择的是私有读写,那么要开启回源鉴权,并且为 CDN 配置 HTTPS 证书(可使用腾讯云的证书控制台直接申请并配置)。

https://img.rneko.com/upic/2022/08232230_tZGCBS.png

API 鉴权配置

在开始下一部分之前,我们还需要获取腾讯云的 access key,以使用命令行工具操作 COS 和 CDN。

首先,点击控制台右上角的头像,进入 访问管理,切换到 用户-用户列表新建用户自定义创建,选择类型 可访问资源并接收消息,填写一个用户名,仅启用编程访问

https://img.rneko.com/upic/2022/08232240_g25et7.png

在权限策略板块,搜索并添加 QcloudCOSDataFullControl(对象存储数据读写删除权限) 和 QcloudCDNFullAccess(内容分发网络全读写访问权限)。如果有更细粒度的权限控制要求,可以选择自定义策略,并详细控制权限和范围。

https://img.rneko.com/upic/2022/08232244_hf75f1.png

全部添加完成后,将生成的 SecretIdSecretKey 保存下来。

使用 Github Action 自动部署到 COS

继续书写我们前面的工作流,该部分要完成将构建好的静态文件自动上传至存储桶的工作,主要使用腾讯云官方的 cosmod 工具 来实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
- name: Setup Python                #配置 python 环境,cosmod 基于 python 开发
  uses: actions/setup-python@v4
  with:
    python-version: 3.9

- name: Setup coscmd               # 安装 coscmd 工具
  run: sudo pip install coscmd

- name: Configure coscmd           # 配置存储桶参数和鉴权
  env:
    SECRET_ID: ${{ secrets.SecretId }}      # SecretId
    SECRET_KEY: ${{ secrets.SecretKey }}    # SecretKey
    BUCKET: ${{ secrets.Bucket }}           # 存储桶名称,在存储桶基本信息中获取
    REGION: ${{ secrets.Region }}           # 存储桶地域,在存储桶基本信息中获取,如 ap-shanghai
  run: coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION # 为 coscmd 工具配置存储桶信息

- name: Upload to COS
  run: coscmd upload -rfs --delete public/ /     #上传 public 中的文件 至 cos 存储桶根目录

本部分中,我们安装了 python 环境和 coscmd 工具,在最后一条命令中, - -r 参数用于上传文件夹; - -s 参数用于同步上传,即仅上传发生变化的文件; - -f 参数用于强制同步文件; - --delete 参数用于删除云端中本地已经删除的文件。

其中的 {{ secrets.xxxxxx }} 需要在 Github 仓库中进行配置,即不能将鉴权信息泄露。

在仓库的 Settings 界面,选择 Secrets - Actions,点击 New repository secret,分别配置 SecretId SecretKey BucketRegion

https://img.rneko.com/upic/2022/08232259_iJqKZT.png

到此为止,我们便完成了构建静态博客并自动上传至 COS 的工作流。

刷新 CDN

在上传完成后,需要刷新 CDN,否则访客看到的页面依然是 CDN 之前缓存的页面。

该部分有两种配置方式,一种是在存储桶页面,通过 函数计算 - CDN 缓存刷新函数 来自动触发刷新,该方法基于与你的存储桶同区域的腾讯云函数,当前腾讯云函数已经转为收费,因此如果没有购买资源包,不建议使用该付费方法。

https://img.rneko.com/upic/2022/08232303_aVyQdT.png

第二种,使用腾讯云的 Python-SDK 实现,写一个 Python 脚本,在部署完成后执行脚本调用 API 完成缓存刷新。

缓存刷新脚本

在仓库根目录下创建文件 flush-dns.py,文件内容如下,将其中的 https://blog.example.com/ 修改为你的 CDN 加速域名。

 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
import json
import argparse
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import (
    TencentCloudSDKException,
)
from tencentcloud.cdn.v20180606 import cdn_client, models

# 传入参数
parser = argparse.ArgumentParser(description='-i <secretId> -k <secretKey>')
parser.add_argument('-i', '--secretid', type=str, required=True, help='secretId')
parser.add_argument('-k', '--secretkey', type=str, required=True, help='secretKey')
args = parser.parse_args()

try:
    cred = credential.Credential(args.secretid,args.secretkey)
    httpProfile = HttpProfile()
    httpProfile.endpoint = "cdn.tencentcloudapi.com"

    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    client = cdn_client.CdnClient(cred, "", clientProfile)

    req = models.PurgePathCacheRequest()
    params = {"Paths": ["https://blog.example.com/"], "FlushType": "flush"}
    req.from_json_string(json.dumps(params))

    resp = client.PurgePathCache(req)
    print(resp.to_json_string())

except TencentCloudSDKException as err:
    print(err)

配置工作流

创建完脚本后,需要在工作流中调用,配置如下:

1
2
3
4
5
6
7
- name: Flush CDN
  env:
    SECRET_ID: ${{ secrets.SecretId }}      # 传入鉴权信息
    SECRET_KEY: ${{ secrets.SecretKey }}
  run: |                                    # 安装 sdk 并运行刷新脚本
    pip install --upgrade tencentcloud-sdk-python
    python flush-dns.py -i $SECRET_ID -k $SECRET_KEY

这样,即完成了 撰写博客 - 上传 Github 仓库 - 自动构建、发布并刷新 DNS 的全部操作。

完整的 Action 工作流配置文件

 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
47
48
49
50
51
52
53

name: Build and deploy

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: 3.9

      - name: Setup coscmd and sdk
        run: sudo pip install coscmd

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

      - name: Build
        run: hugo --minify

      - name: Configure coscmd
        env:
          SECRET_ID: ${{ secrets.SecretId }}
          SECRET_KEY: ${{ secrets.SecretKey }}
          BUCKET: ${{ secrets.Bucket }}
          REGION: ${{ secrets.Region }}
        run: coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION

      - name: Upload to COS
        run: coscmd upload -rfs --delete public/ /

      - name: Flush CDN
        env:
          SECRET_ID: ${{ secrets.SecretId }}
          SECRET_KEY: ${{ secrets.SecretKey }}
        run: |
          pip install --upgrade tencentcloud-sdk-python
          python flush-dns.py -i $SECRET_ID -k $SECRET_KEY