本文所提到的大概还是有实用价值的,但是我个人应该是不会用在博客上了。至于为什么 … 因为心态炸了,退掉了手里所剩的几台 vps ,没必要使用自动部署了,但是日后可能会用在 CQU mirror wiki 上。

事情起因

其实本来这种自动化部署之前弄过一次,但是因为某些原因服务器的 Debian 8 安装 node 11很麻烦,而我的自动化部署工具是基于 node11 的,所以索性放弃,每次登上去手动同步一下就好。

但是这时候朋友的博客刚刚做好备案,然后另外一个朋友的博客改为放到 vercel 上了(均带有自动化部署),本着攀比心理,因为自己博客之前一直部署于服务器上所以觉得自己可以再折腾一次自动化部署,本着方便使用语言选择了 golang ,毕竟作为 Linuxer 自己折腾才是一大乐趣。

开始折腾

既然语言选择了 golang ,那么如何实现就是一个问题,毕竟 nodejs 下面有现成的轮子可以用。所以基于对 golang 的了解和自己对于这个小工具的设计,决定这样来写这个工具:

1
2
3
4
- cli 可用
- 尽量简单
- 通过处理请求头的办法来实现
- 服务端通过端口转发来使用,尽量不暴露端口

使用到的库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"fmt"
"gopkg.in/urfave/cli.v1"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"sort"
"strconv"
)

其中 cli 框架是用来处理 cli 下 Flag 等传值的,比起自己造轮子这个库要好用得多。然后需要处理一下监听:

1
http.ListenAndServe(portForward, nil)

有了 http 库,监听只需要这一行代码即可实现。然后是请求头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func index(w http.ResponseWriter, r *http.Request) {

signature := r.Header.Get("X-Hub-Signature")
if len(signature) <= 0 {
return
}
payload, _ := ioutil.ReadAll(r.Body)
mac := hmac.New(sha1.New, []byte(secret))
fmt.Printf(secret)
_, _ = mac.Write(payload)
expectedMac := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature[5:]), []byte(expectedMac)) {
io.WriteString(w, "<h1>401 Signature is error!</h1>")
return
}
io.WriteString(w, "<h1>200 Deploy server is running!</h1>")
reLaunch()
}

这部分主要是需要有两个参数,一个是响应请求,一些是读取请求,具体怎么分析请求头,这接点开 webhook 的历史即可看到一个实例请求,我们需要处理的仅仅是 X-Hub-Signature 这一项,然后比对请求中的秘钥和转码后的秘钥是否相同判断是否可以执行接下来的动作。

http 库最好用的我认为应该是可以对请求执行自定义函数了,直接指定一个 reload 方法即可调用拉取更新的脚本等:

1
2
3
4
5
6
7
8
9
10
11
func reLaunch() {
cmd := exec.Command("load")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
err = cmd.Wait()
}

...
http.HandleFunc("/", index)

然后最后一点就是为整个功能套上 cli 框架即可,由于 cli 框架本身并不难用,所以一般直接看代码示例即可。项目地址:https://github.com/weearc/blog-webhook-deploy

项目使用 GPLv3 开源,许可证也会在稍后进行添加。