在 Hello Hugo 文章中介绍了 Hugo 的入门,并使用 git hook 机制实现了一个简单的部署工作。在完善博客的过程中,我想实现读者在线纠错、修改文章内容的功能,需要将文章内容托管到公有的平台,最好的选择当然是 GitHub。这时候问题就来了,我关联了两个远程仓库,一个在自己的远程主机上,用于实现部署;另一个在 GitHub 上,方便读者进行在线编辑。每次在本地完成内容后,都要向两个远程仓库提交代码,这多少有些膈应,更重要的是,在线编辑的内容是要从 GitHub 上同步到我的远程主机的,显然这是不合适的。
Hugo官方提供了多种部署方式,其中,Host on GitHub 和 Deployment with Rsync 结合正好可以满足我的需求,具体实现是直接放弃自己远程主机上的仓库,并使用 GitHub Actions 进行站点的部署。
GitHub Actions
概念
官方文档给出的定义如下:
GitHub Actions 是 GitHub 官方提供的一种自动化、定制化的工作流,包括了 CI/CD。关于 CI/CD 的简单理解:
- CI:持续集成(Continuous Integration),使用 Git 向代码仓库推送代码后,后台将会自动进行构建、测试等工作。
- CD:持续交付(Continuous Delivery),推送完成的代码(经过了自动构建、测试等流程),最终部署到生产服务器,供客户直接使用。
GitHub Actions 中的几个重要概念如下:
workflow
:工作流,持续集成一次运行的过程,就是一个workflow
。enent
:事件,表示触发workflow
执行的某些特定活动,例如某些workflow
可以在仓库中的push
、pull request
发生时开始执行。job
:任务,每个workflow
都可以包含一个或多个job
,表示每次持续集成可以执行多个任务。step
:步骤,每个job
可以包含一个或多个step
,表示每个任务可以由多个步骤完成。action
:动作命令,每个step
包含多个action
,它是workflow
的最小单元,通常是独立的脚本命令。runner
:执行workflow
的服务器,可以使用 GitHub 内置的服务器,也可以使用自己的服务器。使用自定义的服务器时,需要在服务器上安装 GitHub Actions Runner。
下图由 GitHub官方 提供,表示 GitHub Actions 的整体结构:
简单示例
GitHub Actions 的具体实现是在当前工作目录下创建 .github/workflows/
,并在目录中添加 .yml
脚本文件,每个 .yml
文件都代表了一个 workflow
。目录结构如下:
|
|
下面是 GitHub官方 提供的示例文件:
|
|
代码 | 说明 |
---|---|
name: learn-github-actions | 可选,表示 workflow 的名称,可以在 GitHub Actions 的标签中显示 |
on: [push] | 表示触发 workflow 的事件,这里的 push 表明每次进行 push 时都会执行当前的 workflow |
jobs: | 表示开始定义 workflow 的具体任务 |
check-bats-version: | 自定义的第一个 job 名称 |
runs-on: ubuntu-latest | 表示使用GitHub提供的 runner ,系统环境为 ubuntu-latest |
steps: | 开始定义 check-bats-version 任务的具体 step |
- uses: actions/checkout@v2 | uses 表示使用在 GitHub 社区中提供的名为 actions/checkout@v2 的 workflow ,它的工作是将仓库中的代码检出并下载到 runner 中,它通常是一个 step 的起点 |
- uses: actions/setup-node@v2 | 表示使用 actions/setup-node@v2 的 workflow ,它的工作是在当前 runner 中安装 node 环境,该环境提供了 npm 命令, with 表示传入该 workflow 的参数,由该 workflow 内部使用,这里指定了 node 的版本号 |
- run: npm install -g bats | run 表示在 runner 中执行具体的命令,这里使用 npm install -g bats 进行全局安装 |
- run: bats -v | 执行 bats -v 命令,打印 bats 的版本 |
该 action 的执行流程如下图所示:
为了使 GitHub Actions 能得到复用,GitHub 提供了发布的机制,可以将自己写好的 action 分享给其他用户使用,详细步骤可以参考 官方文档。
上面示例所示,actions/setup-node
就是一个在社区中分享的action,它表示 github.com/actions/setup-node 这个仓库,同时也是一个 action,作用是安装 Node.js
,而 v2
就表示了使用的 actions/setup-node
的版本为 v2
。
- 所有的公有仓库免费。
- 用户使用自己提供的
runner
也是免费。 - 私有仓库,且使用的是 GitHub 提供的
runner
,收费标准见 官网。
Hugo 部署
准备工作
-
远程主机配置
部署流程使用
rsync
进行文件的同步工作,rsync
默认是基于 SSH,需要提前在自己的远程主机上安装rsync
,并准备密钥对。这里使用 上篇文章 中创建的 git 用户作为同步数据时使用的账户:
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
# 安装 rsync sudo apt-get install rsync cd /home/git mkdir .ssh cd .ssh # 不支持Ed25519算法的系统请使用 ssh-keygen -t rsa -b 4096 -C "your_email@example.com" ssh-keygen -t ed25519 -C "your_email@example.com" # 交互完成密钥的生成 Generating public/private ed25519 key pair. Enter file in which to save the key (/root/.ssh/id_ed25519): rsync # 输入密钥对名称,默认名id_ed25519 Enter passphrase (empty for no passphrase): # 输入密码,这里选择不输入 Enter same passphrase again: # 重复上述密码 # 成功 Your identification has been saved in rsync. Your public key has been saved in rsync.pub. The key fingerprint is: SHA256:xxxxxxxxxxxx/xxx/xxxxxxxxxxx/xxx your_email@example.com The key's randomart image is: +--[ED25519 256]--+ | | | o + .o o +| | .| | + . oo .| | | | | | + .o+ o oo.| | o. .. + +| | | +----[SHA256]-----+
密钥对生成成功后,在
.ssh
目录下新建authorized_keys
文件,并将公钥信息增加到该文件末尾:1
cat rsync.pub >> authorized_keys
私钥文件中的内容需要拷贝到 GitHub,稍后介绍。
-
GitHub Secrets 配置
Secrets 是提供给 action 使用的安全变量机制,Secrets 中定义的变量都会进行加密,但后续可以在 action 中正常使用。
进入 Hugo 博客仓库,点击
Settings
,左侧找到Secrets
,进入 Secrets 配置:如图所示,点击右上角的
New repository secret
创建新变量:这里先创建私钥变量REMOTE_KEY
,在变量Name
中输入REMOTE_KEY
。从服务器上拷贝私钥文件rsync
的全部内容到Value
中,点击Add secret
保存:1 2 3 4 5
cat rsync # 拷贝输出中所有内容 -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY-----
使用同样的方式创建剩余 Secrets:
REMOTE_HOST
:远程主机地址。REMOTE_PORT
:远程主机 SSH 端口,默认为 22 可不配置,若不是 22 必须配置。REMOTE_USER
:数据同步使用的用户,如本文中使用的 git。REMOTE_PATH
:远程主机上的目标路径,同步文件将会拷贝到该路径中,如 nginx 配置的静态网站路径。
配置 GitHub Actions
在仓库目录下创建 .github/workflows
目录,并且在目录中创建 deploy.yml
文件:
|
|
deploy.yml
中的内容如下:
|
|
action 的 3 个 step
工作内容分别如下:
- 先检出代码到
runner
,包括 submodule 下的内容,这是为了保证作为 submodule 的主题目录能正常使用。 actions-hugo@v2
安装准备好 Hugo 的环境,with
表示 Hugo 版本为 latest。hugo --gc --verbose --minify
构建 Hugo 静态站点,默认输出到 public 目录中。rsync-deployments@5.1
将 public 目录中 所有的内容 全部拷贝到服务器指定路径,这里${{ secrets.XXX }}
引用我们之前创建好的 Secrets 变量。注意在使用rsync
时 public 与 public/ 的区别。前者会在目标目录中创建同名目录 public,后者不会创建该目录,而是直接将源目录public中的 所有内容 拷贝到目标目录。要了解更多关于rsync
的使用细节可以参考 这篇文章。
检验结果
将新创建好的 action push 到 GitHub 仓库,在 Actions 标签下就可以看到所有的 action 了。
本地修改一些代码,提交并 push 后,可以看到 deploy
这个 action 的执行过程,包括执行结果(成功或者失败)、执行时间、输出等信息。
访问自己的站点,看看是否运行成功。若一切正常,这次的部署转移计划算是顺利完成了。