Git Hook(钩子) 是 Git 在代码提交、推送、合并等工作流程中引入的事件触发器,其中最常用的场景是代码检查,持续集成,自动部署等,本文主要讲解利用webhook 实现自动部署的两种方式。
一、什么是Git webhook
Git 的 hook 分为本地仓库 hook 和服务器仓库 hook。
(一)本地 hook
本地 hook 通常在代码的 .git/hooks 目录下,如下所示:
$ hooks git:(master) ls
applypatch-msg.sample pre-commit.sample prepare-commit-msg.sample
commit-msg.sample update.sample
post-update.sample pre-push.sample
pre-applypatch.sample pre-rebase.sample
默认情况下,这些脚本不会生效。使用时,只需将 .sample
后缀去掉,然后赋予脚本执行权限即可。
本地 hook 主要用于代码静态分析、REVIEW、代码规范、命名规范等。
- pre-commit
提交之前的代码检查,包括是否通过单元测试,静态代码分析 - prepare-commit-msg
提交信息之前,可用来生成默认的提交信息 - commit-msg
提交信息之后,可用来检查提交信息是否符合特定的格式 - post-commit
提交代码之后,一般用来通知代码已提交。 - post-checkout
checkout 代码之后,可用来设置工作目录、生成文档、生成静态资源等工作 - post-merge
合并代码之后,可用来保存 merge 操作中,git 没有保存的信息。 - pre-push
push 代码之前,可用来检查本次 push 的 commits 是否符合特定的标准。
(二)服务器 hook
服务器 hook 指代码传输到服务器时,在服务器端所做的一系列操作。
- pre-receive
处理 push 操作之前,可以检查本次 push 的 commits 和文件是否符合特定的标准。 - update
update 与 pre-receive 操作类似,不同的是 pre-receive 只执行一次,而 update 可能执行多次。 - post-receive
整个提交过程完成之后,可用于更新其它服务或通知用户,比如发邮件告诉开发人员已提交代码,通知持续集成 (Continuous Integration) 服务器部署代码
(三)webhook
如果 Git 服务部署在自己的服务器上,如用 GitLab 搭建一套 Git 服务,则可以使用服务器 hook。如果使用了 GitHub、Bitbucket 等云端平台,那么只能使用 webhook 来完成脚本。
webhook 本质上属于服务器 hook,因为发送通知的方式是网络请求,因此得名。使用 webhook 的步骤如下:
- 设置用于接收请求的 URL。
- 服务器收到 push、pull request、merge、tag 等操作时,会将相应信息发送给步骤 1 里的 URL。
- URL 对应的程序收到网络请求后,执行自动部署、邮件通知等操作。
二、部署 webhook
部署webhook有很多方式,本文仅讲解使用github-webhook工具和在nginx+php环境下部署webhook的两种方式
(一)github-webhook工具
github-webhook 文档
使用github-webhook
1.Go环境搭建
安装Sudo、Curl、Wget、Git、Vim
apt update && apt install sudo wget vim curl
(1)下载GO并解压
curl -O https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
tar xvf go1.14.2.linux-amd64.tar.gz
sudo chown -R root:root ./go
sudo mv go /usr/local
注意:虽然/usr/local/go是官方推荐的位置,但有些用户可能更喜欢或需要不同的路径。
(2)设置Go路径
设置Go的根值,告诉Go在哪里查找其文件:
vi ~/.profile
在文件末尾添加以下行:
export GOPATH=$HOME/work
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
如果为Go选择了不同的安装位置,则应将以下行添加到此文件中
export GOROOT=$HOME/go
export GOPATH=$HOME/work
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
注意:export GOROOT=$HOME/go
在主目录中安装Go时所需的行
在Go安装到位并设置必要的环境路径后,让我们通过编写一个简短的程序来确认我们的设置是否有效
source ~/.profile
2.下载github-webhook工具
wget http://img.sgfoot.com/github-webhook1.4.1.linux-amd64.tar.gz
3.运行github-webhook
(1)安装
tar -zxvf github-webhook1.4.1.linux-amd64.tar.gz
cp github-webhook /usr/bin/
chmod u+x /usr/bin/github-webhook
(2)运行
- 默认端口: 2020
- 有效访问地址: http://ip:2020/web-hook
- -b 是shell脚本路径参数
- -s 是github webhook设置的密码
# 非后台运行
github-webhook -b [shell脚本路径] -s [github webhook设置的密码]
# 后台运行
nohup github-webhook -b [shell脚本路径] -s [github webhook设置的密码] &
# 定向日志输出
nohup github-webhook -b ~/webhook.sh -s sopsopsop >> ~/webhook.log 2>&1 &
(3)webhook.sh
#! /bin/bash
SITE_PATH='/var/www/html'
USER='www-data'
USERGROUP='www-data'
cd $SITE_PATH
git reset --hard origin/master
git clean -f
git pull
git checkout master
chown -R $USER:$USERGROUP $SITE_PATH
赋予webhook.sh可执行权限
chmod +x webhook.sh
这样每次在客户端 push 代码,服务器会发请求给 github-webhook,github-webhook检查通过后,启动 webhook.sh
进行自动部署。
配置github webhook
- 填写你服务器的地址, http://ip:2020/web-hook
- 设置的密码必须与服务器运行github-webhook -s 设置的密码一致
(二)nginx+php环境下部署webhook
环境
Item | Value |
---|---|
域名 | www.qq.com |
接收请求的URL | https://www.qq.com/webhook.php |
项目部署目录 | /var/www/html |
webhook.sh路径 | ~/webhook.sh |
webhook.php | /var/www/html/webhook.php |
环境 | nginx php |
用户组 | www-data |
Git config
Git 项目需要使用 SSH 地址,如 git@github.com:xxx/xxx.git 。如果之前采用了 HTTPS 链接,需要修改 .git/config 文件里的 url 字段:
vi .git/config
[remote "origin"]
url = git@github.com:xxx/xxx.git
fetch = +refs/heads/*:refs/remotes/origin/*
部署 SSH 无密码登录
首先需要生成 SSH key
sudo -u www-data ssh-keygen -t rsa -C "nginx"
然后复制你的 public key,粘贴到项目的“SSH 公钥”设置里
cat /var/www/.ssh/id_rsa.pub
Github仓库中 Settings -> Deploy keys
选择 Add deploy key
添加完毕后,可以运行 ssh -T git@github.com
来验证是否设置成功。首次运行时会看到一条 RSA key 指纹的连接确认信息,输入 yes 回车即可
Hi username! You've successfully authenticated, but GitHub does not
provide shell access.
webhook.php
webhook.php 用来接收 webhook 请求,一般要做以下操作:
- 监测请求来源合法性。检查方法:密码,AES等。
- 检查是否为特定分支,如 master 分支。
- 启动自动部署脚本,如完成拉取最新代码,重新设置目录权限等
<?php
$raw_data = file_get_contents("php://input");
$pay_load = json_decode($raw_data,true);
//监测请求来源合法性,
if($pay_load['password'] != 'pass'){
exit('ok 400');
}
//检查是否为master分支
if($pay_load["ref"] != "refs/heads/master"){
exit('ok 401');
}
exec('sh ~/webhook.sh');
webhook.sh
webhook.sh和github-webhook中脚本一样
三、声明
本文所有内容,包括文字、图片等来源以下地址,版权归原作者所有。
1.百里江山的博客,《github-webhook工具实现github自动构建》
2.David's world,《Git webhook 实现自动部署教程》