通过 Gitlab 的 WebHooks 实现网站内容同步
通过 Gitlab 的 WebHooks 实现网站内容同步
丁俊尧2020-09-25 更新:阿里云在最近推出了云效,以替代之前的阿里云 CODE。操作方法类似。但是,在云效中,Webhooks 的请求头变成了
Codeup-Event: Push Hook
,所以涉及到请求头的判断需要更改。 有时候,执行git
命令不成功,这时候可以使用os.system(要执行的Shell命令字符串)
替代。但是该方法返回的是表示执行状态的整数,所以还是要对后续判断进行更改。2023-09-24 更新:文中的这种情形,建议使用 Docker 这样的容器管理,节省时间,易部署、迁移。
背景
我自己有一个用 Hexo 搭建的网站——https://4ading.com/,用来发布自己写的文章。文章使用阿里云的代码托管服务(以下简称 CODE,使用 Gitlab 搭建)存储,并在 ECS 上进行克隆,通过 Nginx 进行访问。
开始的时候,我发布文章的流程如下:
- 在电脑上编辑文章。
- 要发布的时候,执行
hexo g -d
,通过 Git 发布到 CODE 上。 - 使用 SSH 登录服务器,在服务器上的网站根目录下执行
git pull
,完成同步。
在此之前,我把连接配置名、密钥什么的都设置好了。新版的 Windows 10 自带 SSH 客户端,因此基本上不需要下载其他的 SSH 客户端。
不过,上面的流程要输入好几行代码,中间等待的时间还是比较长的。后来,我将第二步和第三步用一行 PowerShell 命令行搞定了:
1 | hexo g -d; ssh 之前设置好的连接配置名 "cd 服务器上的网站根目录 && git pull" |
不过,这行代码太长,我一般都是在终端里面上翻历史命令,找到这一条再执行的。结果,几周前重装系统后,这条记录就没了,我还因为命令中的分隔符纠结了半天。
于是,我便想:如果能够在执行hexo g -d
之后自动更新服务器上的文件,就好了。
WebHooks 介绍
我以前听说,GitHub 上面可以通过 Travis CI 这样的持续集成工具,在推送时进行测试、构建、部署等工作。
后来,我发现,Gitlab 中,有一个叫 WebHooks 的东西,如果加以利用,可以自建属于自己的持续集成工具(其他的代码托管平台也有类似的功能,包括上面提到的 GitHub)。
简单来说,WebHooks 就是:当项目进行了某项操作(如提交),代码托管平台就会调用给定的 URL,发送一条 POST 请求。至于 URL 那边的服务器,接收到请求之后,就可以为所欲为了——这篇文章中提到的同步存储库什么的,只是冰山一角,如果你会写一些脚本,理论上可以做到发邮件、在社交平台/即时通信平台上发送消息、甚至如前面提到的那样,自动进行测试、构建、部署。当然,和一般的请求一样,服务器也会给一个返回。不过这个返回的意义并不是非常大,相比之下,服务器内的处理流程才是最重要的。
设置 WebHooks 的方法
在 CODE(其他基于 Gitlab 的托管平台的操作流程应该也差不多)中,设置 WebHooks 的方式很简单:
在项目的设置中,点击“WebHooks”选项,填入接收请求的 URL,选择触发事件,点击下面的“增加 WEBHOOKS”,即可成功添加一条。可以看到,在“触发”的选项中,有一个“推送事件”,当推送内容至仓库后,即触发。
这样一来,我们可以写实现如下操作的代码:当接收到请求后,即在服务器中对网站根目录进行
git pull
操作。
其实,这种要求非常低。如果你装了宝塔面板,只要装一下 “宝塔 WebHook” 的插件,在插件里面设置好如下的 shell 脚本就可以了。
1 | cd 网站根目录 |
点“查看密钥”,就可以看到插件给你的 URL,用这个 URL 做 WebHook 的链接就行了。
仅在提交特定分支时调用 URL
但是,我的这个仓库有两个分支:master
和
hexo
。master
分支存储生成的网页文件,hexo
分支存储网站的源文件和设置。我只想让服务器在 master
分支被提交时更新网站内容,而 hexo
分支更新与否与网站无关。
Gitlab 中并没有关于“提交某个特定的分支”的触发事件,但是,在调用 URL 的时候,会发送特定的请求头和请求体。
帮助文档中给出了比较详细的事例。比如推送事件的请求头如下:
1 | X-Gitlab-Event: Push Hook |
请求体为 JSON 格式的内容,如下:
1 | { |
可以看到,请求体里面的 "ref"
字段中包含了推送的分支,只要做到这个操作就可以了:在服务器收到请求后,读取请求体,判断该字段中是否表示
master
分支,如果是,则更新网站根目录的内容。
当然,为了安全,还要验证请求头是否正确。
但是,“宝塔 WebHook”插件太简单了,做不到这个。它的传值在查询字符串中,读不了请求头和请求体。这样一来,我就只能写服务器脚本来实现这个功能了。
你可以使用你熟悉的语言和框架写服务器脚本,只要能够收到请求并作出正确的反应就行了。我接触 JS 和 Python 比较多,不过 Python 中的 Flask 框架足够轻量(说实话貌似有更轻量的),开发起来也容易得多。于是,我便使用了 Python 和 Flask 框架来写这个脚本。
使用 Python 和 Flask 框架实现功能
安装好 Flask,然后写入如下的代码。
基本骨架是 Flask 提供的 Hello World 示例,我翻了很多资料,东拼西凑出来可以运行的代码。不过确实非常简单。
一些必要的注释我放在代码里面了。
1 | # flask.request是用来处理请求的 |
在服务器上部署代码。我用的是宝塔的 Python 项目管理器,因此具体的脚本我就不清楚了,反正我用了 gunicorn。
之后,用 Nginx 进行端口的反向代理,并应用
SSL。具体设置方法看网上的文档,因为我也是用宝塔的默认文档魔改的。当然,如果你对安全不那么在意的话,你也可以不用设置
Nginx。这时,监听主机要设置为 '0.0.0.0'
。
此后就可以到 CODE(Gitlab)去设置 WebHooks 了。如果你用了反代什么的,就根据反代的参数设置 URL。如果你开了 SSL,就可以点下面的“开启 SSL 证书验证”了。
增加完成后,要多测试。页面下方给出了测试按钮,会发送一条测试的请求。到主机的服务器上看日志、看返回结果什么的,看看执行的怎么样。
不仅要用这个测试按钮,还要在本地实际进行提交,进行测试。我上面的代码就测试了不下十次才写出点样子。
不仅仅是网站,还可以是整个项目
实际上,一开始,这个仓库只有一个分支。之所以开另一个分支,是因为我希望能够在不同的地方写文章。
和 WordPress 这样的博客系统不同,Hexo
在线上是静态的,源文件都在本地。我此前希望自己写在线编辑器,但是因为我懒、菜,就一直没有写。后来我试了
hexo-admin
、hexo-myadmin
这样的在线编辑器,但是前者太丑了,后者在手机端上几乎没法用。最后我找了半天,选择了
hexo-hey
,因为它的页面适配手机端比较好。但是,作者不更新了,手机端上也有一些问题。目前我还没有找到满意的在线编辑器。
要使用在线编辑器,就要把整个工作目录放上去,而不仅仅是生成的文件。我在知乎上找到了教程,将生成文件和工作目录放到不同的分支下。然后,我按照组件、用 pm2 执行,再用 Nginx 做反向代理,以便使用 SSL 证书,终于搞好了。
这时,如果在手机端上修改了文章的草稿(由于我修改了一些
node-modules
,加上我写文章并不快,所以我目前不期望在手机端上发布文章),就要:在手机端上使用
SSH 登录到服务器,再在工作目录下执行以下命令,以将更改上传到 CODE:
1 | git add . |
然后,回去用电脑编辑之前,也要从 CODE 上下载更改。更要命的是,编辑好了之后,还要上传更改,然后在服务器上下载更改,以便手机端修改。
简而言之,每次编辑前后,都要拉取、提交修改。电脑端上倒无所谓,但是手机端上执行这一系列流程挺困难的。而且,虽然关于 git 的所有流程都在电脑上进行,但是还是挺麻烦的,而且容易忘记拉取,一旦忘了就尴尬了。
在我写完上面的脚本之后,我想到了这个情况,便想到了一个方法:当推送
hexo
分支后,同时在服务器上拉取该分支。这样一来,就能省下一半的工作量。
修改起来也简单,只要在上面的代码中的
# 非master分支的提交
处,照着写一下 hexo
分支提交之后的处理方法,再测试一下,就行了。
至此,我的服务器的功能图如下: