远程git自动部署
前言:
说到自动部署,之前试过在自己的服务器上面搭建一个svn仓库,使用钩子来触发自动部署代码,这样做就免去了每次去部署代码的麻烦。可是这么做还是会有缺点。比如代码仓库和生产环境高度耦合,单机还好。多节点部署就比较麻烦。还有没有直观的页面去看代码的提交和版本控制的地方。所以选择一个成熟的代码托管服务是比较好的方案。国外有知名的github。国内也有很多,比如开源中国的码云。
选用码云作为git仓库
-
在码云的后台创建一个项目
创建项目
-
拿到git仓库的地址
仓库地址
- 本地拉取仓库
3.1 如果你已经写好了代码 那就在你的项目根目录初始化一下git init
,然后和仓库绑定git remote add origin 你的仓库地址
3.2 如果你没有开始写代码那就可以直接把线上仓库git clone https://gitee.com/xxxx
克隆下来 - 最后将你想要提交的代码push出去。就可以在码云的网页中查看和管理啦
使用远程仓库自动部署
下面灵魂画手上线

由图中所示。一次自动部署总共需要4步。我们下面来分解各个步骤和各个步骤需要解决的问题
- push代码
本地开发好之后需要push代码到远程仓库中去。我们默认自动部署master代码。那么就是你平时在分支上面开发push的代码是不会部署到服务器上面的。
那么push的方法也很简单。只要你和仓库关联没问题。那么就是git commit
git push
就好了 -
hook钩子触发
当仓库收到一次commit之后。就会进入到一个事件的触发。整理这次push的一些数据,然后完成一次http请求。这一步骤可以说是我们自动部署的关键。但是,这个功能远程仓库已经帮我们做好了
webHook设置的位置
设置内容
设置的内容其实也很简单,一个url一个密码。密码会通过http的时候带过来。用来防止恶意的请求。当然除了密码,http请求中还会带过来很多关于push的信息。来供开发者使用。事件我这里选择的是push。其他的事件也是同样的道理,大家视自己的使用场景来考虑吧。
- http请求
既然有http请求。那么我们就需要一个能接受请求的地址。而这个地址背后的逻辑呢,其实很简单。主要有两个
- 验证请求是否合法
- 将mater代码更新到服务器
验证请求是否合法其实就明显了。我们设置了密码,我们判断下请求header里有没有密码且密码是否正确就可以验证了。(我们先不着急介绍这部分。下文会有代码贴出。一看就懂)
而第二步。将master代码更新到服务器上面。这里就涉及到一个问题。服务器上面使用哪个的git账号呢?
其实并不需要给服务器配一个单独的账号,只需要配置一个公钥。就可以给服务器一个合法的身份拉取代码了
同样的码云提供了部署公钥的配置。部署公钥其实就是一个只有clone和pull权限的账号。将里的服务器公钥配置到这里就能获得只读权限

3.1 公钥的设置
首先你需要切换的是你要使用的用户。这一定非常重要。因为,http请求进来的一般都是nginx的操作人 (一般情况下是www) 那么你的文件归属最好也和nginx操作人一直,避免出现权限问题。那么我们就以www用户为例
先切换到www 使用命令 su www
生成密钥
ssh-keygen -t rsa
密钥一般是存储在用户文件夹中 比如/home/www/.ssh/id_rsa

配置密钥
然后将公钥复制出来添加到下面的表单中,并取个名字方便区分

这样就完成了一次部署公钥的配置
获取ssh地址

服务器中拉取项目
配置好了部署公钥。就等于给了服务器合法的身份。那么服务器就可以不用账号密码拉去项目里面的代码了。
git clone 你的ssh地址
代码拉下来了之后就可以配置nginx之类的web服务了。这里不做过多介绍。
接收http请求并触发git pull
之前有提到,每次push都会触发一次http的请求。请求的地址是我们事先配置好的。那我们假设现在我们配置的地址是https://www.zzz.cn/pull.php
这样的话,http的请求就会通过nginx调起php-fpm来执行脚本。那么只需要在脚本中完成验证和执行git pull命令就可以了
我们直接来看代码
<?php
//error_reporting(1);
$webPath="/home/www/xxx/";//项目的根目录
//获取header里面参数的方法
if (!function_exists('getallheaders')) {
function getallheaders()
{
$headers = array();
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
}
$headers=getallheaders();
//拿到header里面存放密码的字段
$requestPass = $headers['X-Gitee-Token'];
//判断密码是否一致。如果不一致就die
if($requestPass!=666){
die;
}
//密码一致。则cd到根目录 完成对远程仓库master代码的拉取
$cmd = "cd {$webPath} && /usr/libexec/git-core/git checkout -f && git pull origin master 2>&1";
$res=shell_exec($cmd);
//输出结果
var_dump($res);
代码的意思非常简单。通过注释完全能看懂。就是需要注意shell_exec一般在php.ini视为被禁止使用的函数。需要在php.ini里去除对这个函数的禁用 再重启php-fpm。
演示
这样一来你将写好的脚本放到配置的url的位置。就可以实现自动部署了。我来简单试一下

我在LICENSE文件最后加入一个hello world
然后push
在服务器中查看文件

同时呢,我们push的日志也记录在了码云里面。其中还包括我们在脚本中打印的信息,也是可以看到的

结语
其实这个方法也不仅仅局限于php这样的脚本语言。脚本语言是比较方便的是git pull下来的代码就可以直接执行,比较简单。如果是使用java这类的静态语言,其实同样是可以达到这样的效果的。只需要在接收http请求的地方将编译重启的逻辑写好。同样可以达到自动部署的效果的。
本次分享,只是站在一个开发的角度上面去学习了下运维的知识。算不上太难,不过的确是很有用的方法。希望能给大家带来帮助。
微信公众号:RichardTalked