git实现服务器自动push拉取代码--webhooks

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: git实现服务器自动push拉取代码--webhooks

前言:我们在进行git代码维护时,每次本地push代码,都要去服务器再进行pull代码的拉取,以保证代码本地和线上的一致性,但是频繁的拉取是非常繁琐的,特别是大项目要进行多个服务器代码同步时,这时候就用到了webhooks(网络钩子)这个东西。


部署使用例子


ps:注意我这里全程用到的是码云进行测试举例,其他的都大同小异

  1. 去git仓库创建webhooks

  2. 添加钩子文件 执行shell命令

以我自己项目为例,框架使用的是tp5,在public/下创建一个名为webhooks.php的文件,目的在于当代码推送至服务器上时,github可以访问到并且可以执行的一个文件。该文件用于执行shell 命令,在触发该链接时自动执行该文件里的命令,从而实现git 自动拉取。

具体代码

<?php
// 本地仓库路径 项目目录
$local = '/www/wwwroot/wurenji';

// 密码 gitee项目管理webhook中设置
$password = '123';

//如果请求体内容为空,返回错误
$payload = file_get_contents('php://input');
if (!$payload) {
    header('HTTP/1.1 400 Bad Request');
    die('HTTP HEADER or POST is missing.');
}

// 如果启用验证,并且验证买QQ平台失败,返回错误
// gitee默认返回json,解析json后验证密码
$data = json_decode($payload, true);
if(empty($data) || $data['password'] != $password) {
    header('HTTP/1.1 403 Permission Denied');
    die('Permission denied.');
}

// 如果仓库目录不存在,返回错误
if (!is_dir($local)) {
    header('HTTP/1.1 500 Internal Server Error');
    die('Local directory is missing');
}
//输出执行结果 包括错误信息,在gitee webhook中可以查看和测试
$res = shell_exec("cd {$local} && git pull 2>&1");
echo $res;
$res_log = '-------------------------'.PHP_EOL;
$res_log .= ' 在' . date('Y-m-d H:i:s') . '向' . $content['repository']['name'] . '项目的' . $content['ref'] . '分支push'.$res;
file_put_contents("git-webhook.txt", $res_log, FILE_APPEND);//将每次拉取信息追加写入到日志里
die("done " . date('Y-m-d H:i:s', time()));
  1. 修改.git/config文件url

url = https://账号:密码@gitee.com/xiangyuphp/项目名.git

  1. php.ini 文件里shell 没有禁用

处理方法 将php.ini 里的shell_exec删除,重启服务即可

(重启php:systemctl restart php-fpm)

  1. 修改.git和FETCH_HEAD的文件权限

chmod -R 777 .git

chmod -R 777 .git/FETCH_HEAD

测试


点击测试就可以看到返回信息,是否成功


日志


每次本地提交代码时,会在public/下生成git-webhook.txt日志文件,记录webhooks运行日志

原理:

每次你push代码到git仓库后,git代码管理平台就会检测push事件,然后发送一个post请求到你的绑定https://xxx.webhooks.php,在该访问的post请求中处理git拉取代码功能。


多服务器例子


SSH 连接公钥登入

其他登入方法:Linux 系统实现 SSH 连接的 3 种 方式

原理:注入公钥到服务端,表示拥有该公钥的客户端可以免密登入

将客户端 A 的公钥~/.ssh/id_rsa.pub复制到服务端 B 的授权Key文件~/.ssh/authorized_keys中。
可采用手动方式,也可以在客户端 A 执行命令 ssh-copy-id root@172.19.0.2来实现
也可以使用ssh -p 16222 root@xxxx,手动在服务器上连接一遍ssh

在客户端 A 执行命令 ssh 172.19.0.2 即可实现免密登入

输入 exit 退出

index.php

<?php

define('ROOT', __DIR__);

include './common.php';

$json = file_get_contents('php://input');
//fileLog($json, date('Y-m-d'));
$input = json_decode($json, true);
    
//如果没数据 不做处理
if (!$input) {
    header('HTTP/1.1 400 Bad Request');
    die('HTTP HEADER or POST is missing.');
}
//如果不是合并, 推送事件 不做处理
if(!in_array($input['object_kind'], ['merge_request', 'push'])) return true;

//分支(只有合并事件才有这个变量)
$branch = $input['object_attributes']['target_branch'] ?? null;

//分支(只有推送事件才有这个变量)
$branch_ref = $input['ref'] ?? null;

//项目绝对路径
$path = '/data/wwwroot/';
//获取项目名称
$projectName = strtolower($input['repository']['name']);


if($projectName == 'guildapi'){
    $projectName = 'guildApi'; //大小写转义
}

//后台
$ips_guild = [
  '43.13xxxx',  //洛谷
];

//api
$ips_guildapi = [
  //洛谷
  '43.138.xxx', //sdk1
  '43.138.1xxx',  //sdk2
];


//测试服
$ips_test = [
  '101.3xxx',
];

$msg = '';
$ips = [];
//调用shell脚本拉取代码
if($branch == 'master' || $branch_ref == "refs/heads/master"){ //正式服
  if($projectName == 'guild'){
    $ips = $ips_guild;
  }else{
    $ips = $ips_guildapi;
  }
  foreach($ips as $ip){
    $res = shell_exec("sudo ./gitlab_config.sh {$path}{$projectName} {$ip} 2>&1");
    echo $res;
    echo "\n";
    echo '-------------------------';
    echo "\n";
  }

}else{ //测试服
  foreach($ips_test as $ip){
    $res = shell_exec("sudo ./gitlab_config.sh {$path}{$projectName} {$ip} 2>&1");
    echo $res;
    echo "\n";
    echo '-------------------------'.PHP_EOL;
    echo "\n";
  }
}
//$res = json_encode($out);
//file_put_contents("log.txt", $res . "\n", FILE_APPEND);//将每次拉取信息追加写入到日志里
die("done " . date('Y-m-d H:i:s', time()));

gitlab_config.sh文件shell脚本代码

#!/usr/bin/expect -f

#保持交互式命令
#interact

set projectPath [lindex $argv 0]

set ip [lindex $argv 1]

# 设置ssh连接的超时时间
set timeout -1
set password "h87xxxxx"

#ssh -p 16222 root@42.1.xxxx      ssh每连接一个新的服务器,需要手动在服务器上连接一遍ssh,保存
spawn ssh -p 16222 root@$ip

# set host "192.168.1.14"
# set passwd "123456"
# spawn ssh root@$host
# expect {
# "yes/no" { send "yes\r";exp_continue }
# "assword:" { send "$passwd\r" }
# }
# interact

expect "]*"         # 通配符

send "cd $projectPath\r"
expect "]*"

send "sudo git pull\r"
expect "]*"

exit

expect eof          # 退出此expect交互程序


shell脚本扩展


执行

./gitlab_config.sh x y

定义一个变量

set username "leo"            
set name "xx.domain"

获取命令行参数(与bash不同的是第一个参数index为0)

set hostname [lindex $argv 0] //获取第一个参数,及x值,存入hostname变量中
set password [lindex $argv 1] //获取第二个参数,及y值,存入password变量中

定义数组

// 定义一个数组
set host_list(0) {host1 127.0.0.1}
set host_list(1) {host2 192.168.1.1}
set host_list(3) {host3 8.8.8.8}
 
//获取数组长度
set len [array size host_list]
send $len

if条件

[string compare $host "123"]    //判断变量是否相等,相等返回0,不相等返回1
 
set host [lindex $argv 0]    //获取第一个参数
if ![string compare $host ""] {    //此处花括号前必须有一个空格,具体请参考TCL语言规范
    //如果host变量为空字符串
}
 
if {[string compare [string toupper $choose] "N"] == 0} {
    //如果choose变量为"N"
} elseif {[scan $choose {%[0-9]} choose] == 0} {
    //如果choose不是数字,scan用户匹配,详情参考TCL语法
} elseif { $choose < 0 || $choose >= $len } {
    exit //退出
}

for循环

set len [array size host_list]
for {set index 0} {$index < $len} {incr index} {
    puts "$index -> $host_list($index)"
}
// incr为自增关键字
// puts用于输出到用户,类似于send_user

注意:

配置gitlab合并dev分支触发钩子,测试服自动拉取dev分支代码:
shell脚本最低要655权限,并且需要unix格式,
可以:
vi filename
然后用命令
:set ff
可以看到dos或unix的字样. 如果的确是dos格式的, 那么你可以用set ff=unix把它强制为unix格式的, 然后存盘退出. 再运行即可

gitlab设置:

1、点击项目里的设置,选择Webhooks
2、填写服务器URL、勾选合并请求事件(只处理合并到dev分支),如果URL是本地域名,需要点击管理中心、
   点击设置、选择网络、点击外发请求 勾选允许Webhook和服务对本地网络的请求 填写本地域名
   如:gitlab.script.com 点击保存, 如果gitlab使用外部的nginx 则需要在/etc/hosts文件将域名指向本地

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
20天前
|
网络安全 开发工具 git
解决fatal:remote error:You can’t push to git://github.com/username/*.g
通过上述诊断与修复步骤,绝大多数的推送错误都能得到有效解决,确保您的Git工作流顺畅无阻。
23 1
|
1月前
|
IDE 网络安全 开发工具
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
本文介绍了如何使用VS Code通过Remote-SSH插件连接远程服务器进行代码开发,并与PyCharm进行了对比。作者认为VS Code在连接和配置多个服务器时更为简单,推荐使用VS Code。文章详细说明了VS Code的安装、远程插件安装、SSH配置文件编写、服务器连接以及如何在连接后切换文件夹。此外,还提供了使用密钥进行免密登录的方法和解决权限问题的步骤。
350 0
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
|
1月前
|
开发工具 git
git如何修改提交代码时的名字和邮箱?
git如何修改提交代码时的名字和邮箱?
55 4
|
1月前
|
IDE 网络安全 开发工具
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
本文介绍了如何在PyCharm专业版中连接远程服务器并配置远程Python环境解释器,以便在服务器上运行代码。
282 0
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
|
1月前
|
Java Linux 开发工具
IDEA中git提交前如何关闭code analysis以及开启格式化代码
【10月更文挑战第12天】本文介绍了在 IntelliJ IDEA 中关闭代码分析和开启代码格式化的步骤。关闭代码分析可通过取消默认启用检查或针对特定规则进行调整实现,同时可通过设置 VCS 静默模式在提交时跳过检查。开启代码格式化则需在 `Settings` 中配置 `Code Style` 规则,并通过创建 Git 钩子实现提交前自动格式化。
193 3
|
1月前
|
前端开发 开发工具 git
如何清理 docker 磁盘空间+修改 Gitea 服务器的 Webhook 设置+前端一些好学好用的代码规范-git hook+husky + commitlint
如何清理 docker 磁盘空间+修改 Gitea 服务器的 Webhook 设置+前端一些好学好用的代码规范-git hook+husky + commitlint
31 5
|
1月前
|
Linux C语言 C++
vsCode远程执行c和c++代码并操控linux服务器完整教程
这篇文章提供了一个完整的教程,介绍如何在Visual Studio Code中配置和使用插件来远程执行C和C++代码,并操控Linux服务器,包括安装VSCode、安装插件、配置插件、配置编译工具、升级glibc和编写代码进行调试的步骤。
192 0
vsCode远程执行c和c++代码并操控linux服务器完整教程
|
1月前
|
前端开发 Java
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
文章介绍了如何使用SpringBoot创建简单的后端服务器来处理HTTP请求,包括建立连接、编写Controller处理请求,并返回响应给前端或网址。
53 0
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:如何提高代码的可维护性与扩展性在软件开发领域,PHP 是一种广泛使用的服务器端脚本语言。随着项目规模的扩大和复杂性的增加,保持代码的可维护性和可扩展性变得越来越重要。本文将探讨 PHP 中的设计模式,并通过实例展示如何应用这些模式来提高代码质量。
设计模式是经过验证的解决软件设计问题的方法。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理地使用设计模式可以显著提高代码的可维护性、复用性和扩展性。本文将介绍几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并通过具体的例子展示如何在PHP项目中应用这些模式。
|
2月前
|
开发工具 git
GIT:如何合并已commit的信息并进行push操作
通过上述步骤,您可以有效地合并已提交的信息,并保持项目的提交历史整洁。记得在执行这些操作之前备份当前工作状态,以防万一。这样的做法不仅有助于项目维护,也能提升团队协作的效率。
144 4