通过gitee钩子自动部署php代码
首先去gitee下登录账号,进入设置页面(右上角头像鼠标悬停下拉菜单中的设置)
点击SSH公钥,然后去服务器上生成一个公私钥,(直接基于root账号生成即可,之后需要改变)
ssh-keygen -t rsa -C "xx@xx.com"
其中xx.xx.com是你的gitee账号的登录邮箱,然后点三次回车会在~/.ssh/目录下生成了一对公私钥,id_rsa,id_rsa.pub,打开id_rsa.pub公钥文件,将里面的所有内容复制处理然后去gitee中的SSH公钥页面中粘贴确定
标题不需要管,会自动生成。然后去服务器中执行命令:
ssh -T git@gitee.com
得到如下反馈,代表成功:
Hi nickname! You've successfully authenticated, but GITEE.COM does not provide shell access.
然后就可以跳转到web跟目录去拉取代码了,此时就可以基于ssh方式拉取:
git clone git@gitee.com:xx/xx.git
将代码全部拉取下来之后,就该去为www用户设置pull的权限了,因为网站自动化部署都是基于www用户去执行的,而非root用户,所以需要把root用户的.ssh目录复制一份给www目录:
cd /home/www cp -aR ~/.ssh .
复制成功之后,需要把这个目录的所有者全部赋给www:www用户才行,不然www用户无权使用这些文件
chown -R www:www .ssh/
这里不需要再做chmod操作,需要保证之前生成的私钥文件的权限是600,不然拉取同步代码时会失败。
然后编写钩子方法:
1 if(substr($_SERVER['REMOTE_ADDR'],0,10) != '106.13.250') { 2 echo '非法IP:' . $_SERVER['REMOTE_ADDR']; 3 exit(0); 4 } 5 // 获取请求参数 6 //$headers = getallheaders(); 7 $body = json_decode(file_get_contents("php://input"), true); 8 // 请求密码 9 $password = 'pwd'; 10 // 验证提交分支是否为master 11 if (!isset($body['ref']) || $body['ref'] !== 'refs/heads/master') { 12 echo '非主分支' .($body['ref']); 13 exit(0); 14 } 15 // 验证提交密码是否正确 16 if (!isset($body['password']) || $body['password'] !== $password) { 17 echo '密码错误'; 18 exit(0); 19 } 20 // 验证成功,拉取代码 21 $path = $body['project']['path']; 22 $result = $this->pull('git_pull', $path);//伪代码,调用nodejs 23 echo 'git pull执行结果:' . $result;
并且将钩子方法的全URL复制到项目的webhook地址中,此时如果提交代码做测试,那么可能会出现下面的问题:
insufficient permission for adding an object to repository database ./objects
这个问题是因为项目目录下的.git目录中的文件没有归给www:www用户,解决方法是:在项目根目录下执行chown -R www:www .git
需要注意,在服务器上生成公私钥之后,去gitee上绑定公钥之后,需要把.ssh目录拷贝到/home/www目录下面,并且把目录归给www:www用户,且给里面的文件的权限是600
再就是可以使用php的shell_exec函数去执行git pull指令去同步代码,但需要在php.ini解锁这个函数,这样有一定的安全隐患,
所以可以让php做前置拦截,(比如目标服务器的IP判断和hook密码),过了验证再调用nodejs的api,通过nodejs的exec命令执行sh文件,在sh文件中去做cd目录和git pull拉取,这样相对就安全很多
笔者使用的是nodejs当下比较流行的koa框架,基于restfulApi去调接口执行,需要注意的是操作shell时需要安装的特定优化包,再就是使用shell时不能随意写,比如cd到任意的一个目录下去执行命令,而只能在项目跟目录下去执行一些py或者sh脚本。
cnpm i --save child-process-promise
代码:
const { exec } = require('child-process-promise'); const { stdout, stderr } = await exec('sh a.sh');
shell脚本:
echo "git pull:" cd /home/www/xx git pull 2>&1 chown -R www:www /home/www/xx