Git webhook 实现自动部署教程
Git Hook(钩子) 是 Git 在代码提交、推送、合并等工作流程中引入的事件触发器,其中最常用的场景是代码检查,持续集成,自动部署等。本文主要讲解一下利用 Git webhook 实现自动部署。
一、Git hook
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
环境假设
为叙述方便,我们做如下假设。
项目 | 值 |
---|---|
域名 | www.weixinbook.net |
接收请求的URL | https://www.weixinbook.net/webhook.php |
项目部署目录 | /var/www/weixinbook |
build.sh路径 | /var/www/hooks/build.sh |
webhook.php | /var/www/weixinbook/webhook.php |
环境 | nginx php |
用户组 | www-data |
Git 项目地址
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。
如果使用 nginx:
sudo -u www-data ssh-keygen -t rsa -C "nginx"
如果使用 apache:
sudo -u apache ssh-keygen -t rsa -C "apache"
然后复制你的 public key,粘贴到项目的“SSH 公钥”设置里。
cat ~/.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 /var/www/hooks/build.sh');
build.sh
build.sh 用来执行自动部署的具体操作。一般情况下,不要放在外网可访问的 webroot 目录下。
#! /bin/bash
SITE_PATH='/var/www/weixinbook'
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
这样每次在客户端 push 代码,服务器会发请求给 webhook.php,webhook.php 检查通过后,启动 build.sh 进行自动部署。
三、结语
自动部署并不难,如果失败,大部分是权限问题。解决的方法很简单:
- 保证 ssh key 的用户为 www-data
- 保证 build.sh , webhook.php 以及代码目录的用户为 www-data.
权限问题解决不了,不要草率地全用 root,这样会带来一定的安全风险。