博客自动化部署
前情提要
在 博客搭建笔记 中,我记录了搭建现在这个博客的过程。为了便于管理,我现在把网站的全部文件用 git 做管理,并上传到 Github 上的一个 private repo 里。这样一方面便于版本管理,另一方面也可以省的每次有改动都要开 FileZilla 传一遍。每次有改动或者发布新文章,只需要推上 Github,然后 SSH 进服务器拉下来重新 hugo
一下就可以。
还是麻烦!
虽然说我写了个小脚本可以一键完成 git pull
和 hugo
,但是每次都还是要 SSH 上去,外网的 ec2 连接又总是延迟高还不稳定。既然这么麻烦,干脆搞个自动化部署吧。
思路
在每次 push 事件发生后,让 Github 向一个特定的接口发送一个通知;服务器则配置这么一个接口用于监听事件,一旦收到 push 的通知就运行脚本自动部署。
工具
webhook:一个用 Golang 编写的轻量级 webhook 工具。可以在服务器端特定端口监听,接收到符合要求的请求后执行指定的命令。
webhooks:一项 Github 自带的功能,在 repo 的 Settings -> Webhooks 选项中可以找到相关的设置项。可以在每次 push 事件发生后,让 Github 向一个特定的接口发送一个 HTTP POST 请求。
要注意此 webhook 非彼 webhooks,前者是一个正好叫 webhook 的 webhook 工具,后者则是一项 Github 的 webhook 功能。
配置
以下配置参考了这两篇博客:
Deploy using GitHub webhooks by @awea
Setting up Automatic Deployment and Builds Using Webhooks by Will Browning
安装
直接使用 APT 安装:sudo apt install webhook
Service
使用 APT 安装,会自动把 webhook 配置成一个 systemd 服务。我在这里做过一些相关解释。要更改 webhook 的运行指令,需要更改 /lib/systemd/system/webhook.service
这个脚本中的内容。因为只需要更改启动指令,因此只要更改 [Service]
项下的 ExecStart
即可。
1[Service]
2ExecStart=/usr/bin/webhook -nopanic -hotreload -hooks /etc/hooks.json
相较于默认配置,这里我添加了热加载 -hotreload
选项,并把配置文件位置改成了 /etc/hooks.json
。
更多命令行参数的配置,可以参考文档。
hooks.json
直接编辑 /etc/hooks.json
或者在其他地方编辑后软链接到对应位置。
1[
2 {
3 "id": "my-blog-deployment-webhook",
4 "execute-command": "/path/to/your/script/update.sh",
5 "command-working-directory": "/path/to/your/script/",
6 "response-message": "Executing deploy script...",
7 "trigger-rule":
8 {
9 "and":
10 [
11 {
12 "match":
13 {
14 "type": "payload-hash-sha1",
15 "secret": "<RANDOM-SECRET-STRING>",
16 "parameter":
17 {
18 "source": "header",
19 "name": "X-Hub-Signature"
20 }
21 }
22 },
23 {
24 "match":
25 {
26 "type": "value",
27 "value": "refs/heads/master",
28 "parameter":
29 {
30 "source": "payload",
31 "name": "ref"
32 }
33 }
34 }
35 ]
36 }
37 }
38]
其中,id
是这个接口的名字,excute-command
是运行部署脚本的指令,command-working-directory
是执行脚本的位置,response-message
是回复 HTTP POST 的消息。最后还需要更改下面的 secret
项,里面要填写一个 足够长 且 足够随机 的字符串作为密钥。
NGINX
根据文档,webhook 会在 http://0.0.0.0:9000/hooks/{id}
这个接口上监听(按照上面的示例就是 http://0.0.0.0:9000/hooks/my-blog-deployment-webhook
)。虽说官方提供了 HTTPS 支持,但是需要另外指定证书,而且还要到控制台安全组放开 9000 端口,就很麻烦,还让人觉着不安全。
既然我们前面已经配好了 NGINX 和 HTTPS,不如就继续用 NGINX 转发请求好了。在 server 块中添加这个 location:
1location /hooks {
2 proxy_pass http://127.0.0.1:9000;
3}
于是就非常轻松的把 /hooks
为开头的 uri 请求转发到了 webhook 的接口上。这样一来,外网访问就可以直接使用 443 端口的 https://your-domain-name/hooks/{id}
作为 webhook,HTTPS 用的就是之前为域名配置的证书啥也不用改,而服务器内部 NGINX 会把请求再转发到在 9000 端口监听的 webhook。(反正是内部转发所以用 HTTP 也无所谓)
这里 NGINX 的配置参考了这篇教程:nginx 关于 uri 的截取
部署脚本
部署脚本本应该很简单,不就是 git pull
一下,然后 hugo
一下完事。不过用了以后发现不是这么回事,webhook 在调用脚本的时候使用了 root 用户,这使得一切都不一样了。由于使用了 snap 来安装 Hugo,在 root 身份下无法执行 hugo
命令;输出 log 文件的时候,log 文件会是以 root 身份创建的,当回到原本的 ubuntu 身份手动执行脚本的时候就无法写入这个 log 文件了。(手动改文件权限当然可以,但是非常不鲁棒)
另外,在 hook.json
中的 excute-command
里直接重定向输出行不通,需要在脚本里直接搞定。(套两个脚本当然也是可以,但是看着令人不爽)
查阅资料以后我写了如下脚本:
1#!/bin/bash
2# Open a shell with ubuntu as user
3sudo -i -u ubuntu bash << EOF
4
5# Redirect output
6exec >> /path/to/log/deployment.log
7exec 2>&1
8
9echo "=============== Blog deployment ==============="
10echo $(date "+%Y-%m-%d %H:%M:%S") UTC
11echo
12
13# Start doing some real stuff
14cd /path/to/hugo/blog/
15git pull origin master
16rm -r public
17rm -r resources
18
19echo
20hugo
21echo
22
23echo "==============================================="
24echo
25
26EOF
这里使用了 sudo -u
和 Here Document 创建了一个身份为 ubuntu 的 shell,然后在里面执行命令。还使用了 exec >> file
和 exec 2>&1
在文件内实现输出重定向。
参考了以下资料:
How do I redirect the output of an entire shell script within the script itself?
How do I use su to execute the rest of the bash script as that user?
Github webhooks
最后就是在 Github repo 里设置对应的 webhook 事件啦。到 Settings -> Webhooks 中新建一个 webhook,Payload URL
就是你定义的接口;Content type
选择 application/json
;Secret
填入之前在 hooks.json
中填的那个 secret
;SSL verification
自然是选择启用;事件选择仅 push 事件。
设置完成以后,博客的自动化部署就最终配置完成了!
后续
webhook 是用 Golang 编写的,而 Hugo 也是 Golang 编写的,用过的人都知道速度那是真的快。Hugo 加上一样超快的 webhook,整个自动化部署的效率真的是巨高。完成全部配置以后,git push
完几秒钟就可以看到服务器端已经完成了建站操作,非常牛逼了。
Nobody:“自动化是解放生产力的必经之路。”
#tech notes
本文总字数 2025
本文阅读量
本站访客量