使用 Drone CI 构建部署 Hakyll 网站

初次发布于 2022-05-17

对于 Hakyll 这类静态网站构建系统来说,写完的没有写完的网站文章、网站的样式和静态资源等有关的一切都可以方便地使用 Git 进行管理。出于隐私和信息安全方面的考虑,我自建了 Gitea 来管理这个小网站的源码,也自建了 Drone CI 来自动构建和发布网站更新。怎么搭建这两个服务可以参考 这篇文档这篇文档 以及 我的 dockerfiles 仓库 里的 docker-compose 文件,这篇文章将会记录一些官方文档没有涉及到的东西。

为 Hakyll 网站定义 Drone CI 管道

在网站 Git 仓库的根目录下新建包含如下内容的 .drone.yml 文件:

---
kind: pipeline
type: docker
name: default

steps:
- name: build
  image: haskell:8.10.7-slim  # current lts
  commands:
  - stack build
  - stack exec site build

以上就是一个最基础的构建管道定义了,上述管道在执行的时候会调用 Docker Runner 拉取 镜像 并在容器内使用 stack 构建网站。我现在在用 GitHub Pages 托管网站,所以我找来了 gh-pages 插件 来实现使用 CI 发布网站更新。我们需要在 .drone.ymlbuild 这一步下方添加如下内容:

- name: publish
  image: plugins/gh-pages
  settings:
    target_branch: gh-pages
    pages_directory: public/
    remote_url: https://github.com/zebraNeon/zebraNeon.github.io.git
    username: zebraNeon
    password:
      from_secret: gh_token
  when:
    event:
    - promote
    target:
    - gh-pages

其中 when 对应的值定义了 publish 这一步仅会在项目被 promotegh-pages 时执行。我们可以在 Drone 后台的构建详情页面的右上角找到 promote 按键(我用的这一版后台上这个按钮是在详情菜单里),然后在 target 内填上 gh-pages 就能触发一次带有 buildpublish 两阶段的构建了。(如果没有这个按钮或者详情菜单之类的,可能是 Drone 后台处于未登录状态。)from_secret: gh_token 表示系统将会在执行构建时从仓库设置的 Secrets 中拿取这一敏感信息的值,详细信息可以参考 这篇文档

为构建管道添加缓存

Drone CI 没有自带的缓存构建文件功能,需要通过插件来实现。我选择了 Meltwater 开发的缓存插件,这个插件可以将构建文件缓存以模板字符串为键储存到 S3 服务或文件系统中。在这里我自建了 MinIO 这一 S3 兼容的储存服务用来存放构建缓存。由于插件自身限制,我们在创建 MinIO 储存桶时需要为桶指定区域(使用 AWS 代号),不然插件将无法正常工作。将 .drone.yml 中的步骤定义重写为如下内容:

steps:
- name: restore-cache
  image: meltwater/drone-cache:dev
  environment:
    AWS_ACCESS_KEY_ID:
      from_secret: drone_cache_access_key
    AWS_SECRET_ACCESS_KEY:
      from_secret: drone_cache_secret_key
  settings:
    restore: true
    cache_key: '{{ .Repo.Name }}-{{ .Commit.Branch }}'
    endpoint: <YOUR-MINIO-HOST>:9000
    region: <YOUR-MINIO-REGION>
    bucket: <YOUR-MINIO-BUCKET>
    path_style: true
    mount:
      - .stack  # i.e. <workspace-path>/.stack
      - .stack-work  # i.e. <workspace-path>/.stack

- name: build
  image: haskell:8.10.7-slim  # current lts
  environment:
    STACK_ROOT: /drone/src/.stack  # /drone/src is the default workspace-path
  commands:
  - stack build
  - stack exec site build

- name: rebuild-cache
  image: meltwater/drone-cache:dev
  environment:
    AWS_ACCESS_KEY_ID:
      from_secret: drone_cache_access_key
    AWS_SECRET_ACCESS_KEY:
      from_secret: drone_cache_secret_key
  settings:
    rebuild: true
    cache_key: '{{ .Repo.Name }}-{{ .Commit.Branch }}'
    endpoint: <YOUR-MINIO-HOST>:9000
    region: <YOUR-MINIO-REGION>
    bucket: <YOUR-MINIO-BUCKET>
    path_style: true
    mount:
      - .stack
      - .stack-work

- name: publish
  image: plugins/gh-pages
  settings:
    target_branch: gh-pages
    pages_directory: public/
    remote_url: https://github.com/zebraNeon/zebraNeon.github.io.git
    username: zebraNeon
    password:
      from_secret: gh_token
  when:
    event:
    - promote
    target:
    - gh-pages

可以看到在这里我使用了环境变量指定了 .stack 文件夹的位置,将「仓库名 - 分支名」作为缓存文件的键。cache_key 的具体定义方式可以参考 这段文档