Git实现自动化部署

业务需求

随着项目业务越来越复杂,参与开发的人越来越多,代码管理,部署就会越来越复杂。传统手动部署变的不可靠,容易出错,而且浪费大量时间。有没有什么办法制动部署呢?这了介绍利用git hook完成制动部署。

当然,制动化部署是DevOps的重要部分。

关于钩子(hooks)

客户端钩子

客户端钩子分为很多种。 下面把它们分为:提交工作流钩子、电子邮件工作流钩子和其它钩子。脚本写在工作区的.git/hooks中。

提交工作流钩子
pre-commit在键入提交信息前运行。
prepare-commit-msg在启动提交信息编辑器之前,默认信息被创建之后运行。
commit-msg如果该钩子脚本以非零值退出,Git将放弃提交。
post-commit钩子在整个提交过程完成后运行。

电子邮件工作流钩子
有3个钩子,不常使用,就不介绍了。

其它客户端钩子
post-rewrite钩子被那些会替换提交记录的命令调用。
pre-push钩子会在 git push 运行期间

服务端钩子

服务端钩子脚本在推送到服务器之前和之后运行。脚本是写在git服务端。

pre-receive
处理来自客户端的推送操作时,最先被调用的脚本是pre-receive。推送到服务器前运行的钩子可以在任何时候以非零值退出

update
update脚本和pre-receive脚本十分类似,不同之处在于它会为每一个准备更新的分支各运行一次。假如推送者同时向多个分支推送内容,pre-receive 只运行一次,相比之下 update 则会为每一个被推送的分支各运行一次。

post-receive
post-receive 挂钩在整个过程完结以后运行,该脚本无法终止推送进程。它的用途包括:发邮件,持续集成,通知等。

服务器本地自动部署

如果使用的gitlab搭建的私有库,在项目的设置 - GIT钩子管理中将如下代码粘贴进去即可。如果没有web界面,可以在git服务器的仓库目录中hooks中的post-receive中添加。

#!/bin/sh
cd /data/webdata/dev.app.cps.com.cn
unset GIT_DIR
git pull origin develop
echo `date "+%Y-%m-%d %H:%M:%S"` "cpsapp-api.git develop分支更新到测试服" >> /data/weblogs/hook.log
echo 0

修改执行权限

chmod +x post-receive

远程自动部署

如果git服务器与web服务器不是同一服务器,那么应该怎么部署呢。如果git服务器,安装了gitlab或者gitea等。那么可以使用webhooks自动部署,

webhooks原理

  • 配置gitlab当push动作的时候,访问web服务器上的一个链接。比如xxx.example.com/webhooks.php
  • webhooks.php里面写着一行代码,会让服务器git pull相应项目的代码到web目录。
  • pull结束,代码就部署在web目录了。

webhooks.php代码参考

<?php
$valid_token = 'secret_token';
$valid_ip = array('127.0.0.1'); //这里填你的gitlab服务器ip
$client_token = $_SERVER['HTTP_X_GITLAB_TOKEN'];
$client_ip = $_SERVER['REMOTE_ADDR'];
if ($client_token !== $valid_token) die('Token mismatch!');
if (!in_array($client_ip, $valid_ip)) die('Ip mismatch!');
exec("cd /var/www/html/; git pull origin master");
//exec("cd /var/www/html/; git pull origin master 2>&1", $output);
//var_dump($output); 这样可以用浏览器调试输出
?>

功能完善的代码

//默认是用git全局变量,有的环境可能要指明具体安装路径
$git = "/usr/bin/git"; 
//指定pull分支,为空就是默认分支
$branch = ""; 
//本地日志名称,需要有写的权限
$hookLogName = "../runtime/hook.log"; 
//网站根目录
$webRoot = "/home/www/wwwroot/heidou.store/"; 
//在GITEE设置的密码
$password = "password"; 
//测试模式,无需密码:true打开,false关闭$isTest = true;
$isTest = false;

$requestBody = file_get_contents("php://input");
if (empty($requestBody) && empty($isTest) && $isTest === false) {
    exit('参数错误');
}

//解析gitee发过来的JSON信息
$content = json_decode($requestBody, true);
//密码验证
if($content['password'] == $password || $isTest){
    if ($content['ref'] == "refs/heads/$branch" || !$branch || $isTest) {
        // $cmd = "cd $webRoot && $git reset --hard && $git clean -f && $git pull $branch 2>&1";
        $cmd = "cd $webRoot && $git pull $branch 2>&1";
        $result = shell_exec($cmd); //关键命令,拉取代码,2>&1后台执行
        $res_log = PHP_EOL."【PULL START】" .date('Y-m-d H:i:s'). PHP_EOL;
        if(!empty($isTest)){
            $res_log .= date('Y-m-d H:i:s') . '执行测试!'. PHP_EOL;
        }else{
            $res_log .= date('Y-m-d H:i:s') . '向' . $content['repository']['name'] . '项目的' . $content['ref'] . '分支push了' . $content['total_commits_count'] . '个commit:'. PHP_EOL;
        }
        $res_log .= $cmd. PHP_EOL;
        $res_log .= $result. PHP_EOL;
        $res_log .= "【PULL END】";
        file_put_contents($hookLogName, $res_log, FILE_APPEND);//写入日志
        if ($isTest) {
            # code...
            var_dump($res_log);
        }

    }
} else {
    file_put_contents($logName, '密码错误!', FILE_APPEND);
    echo '密码错误!';
}

遇到的问题

  • hooks没有权限控制,不能指定某个分支中才能触发hooks,如果需要指定分支,就需要使用gitlab等工具提供的webhooks功能

相关文章

此处评论已关闭