使用git webhook实现代码自动部署

前言

每次项目修改完代码后,需要通过一些文件传输工具上传到服务器,显得有些繁琐。希望git push的时候,服务器上的代码也能自动更新,这样也能节省不少时间。

实现原理

利用git的hook机制,当每次用户提交了代码后触发一个动作去请求我们自己的服务器,服务器收到通知后将代码重新拉取一下,实现代码的自动部署。

具体实现

服务端设置SSH秘钥免密登录

  1. 在客户端生成公钥和私钥
1
ssh-keygen [-t rsa] [-C "comment"]
  1. 将公钥拷贝到需要免密登录的服务端,路径/path/to/.ssh

注意:

  1. /path/to/.ssh 文件权限必须为700
  2. /path/to/.ssh/authorized_keys 权限必须为600
  3. 公钥文件权限必须为600

在服务端创建一个站点,用来响应hook动作。

nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 80;
server_name localhost;
root /path/to/hook.php;

location / {
try_files $uri $uri/ /index.php?$query_string;
index index.php index.html index.htm;
}

location ~* ^\/(upload|plugins|themes)\/.+\.(html|php)$ {
return 404;
}

location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
}
hook.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php

/**
* Git钩子
* @author chen
*/

$_GET && safe_filter($_GET);
$_POST && safe_filter($_POST);
$_REQUEST && safe_filter($_REQUEST);
$_COOKIE && safe_filter($_COOKIE);

$gitMaps = [
'xxxx' => [
'name' => 'xxx',
'email' => 'xxx@qq.com',
'domain' => 'xxx',
'savePath' => '/www/wwwroot/',
'gitPath' => 'git@code.aliyun.com:xxx/xxx.git',
]
];

$logPath = 'git-webhook.log';

$projectName = $_GET['name'] ?? null;

if (is_null($projectName)
|| !array_key_exists($projectName, $gitMaps)){

return false;

}

extract($gitMaps[$projectName]);
/**
* @var $name
* @var $email
* @var $domain
* @var $savePath
* @var $gitPath
*/

// 判断是否存在.git文件夹
$isCloned = is_dir($savePath . $domain . '/.git');

if ($isCloned) {

$requestBody = file_get_contents("php://input");

if (empty($requestBody)) {
return false;
}

// 解析Git服务器通知过来的JSON信息
$content = json_decode($requestBody, true);

// 若是主分支且提交数大于0
if ($content['ref'] == 'refs/heads/master'
&& $content['total_commits_count'] > 0) {

// 拉取更新
shell_exec("cd {$savePath}{$domain} && git pull");

// 修改web路径的权限
shell_exec("chown -R www.www {$savePath}{$domain}");

//记录日志
$log = sprintf('%s在%s向%s项目的%s分支推送了%s个提交',
$content['user_name'],
date('Y-m-d H:i:s'),
$content['repository']['name'],
$content['ref'],
$content['total_commits_count']
);
file_put_contents($logPath, $log, FILE_APPEND);
}

} else {
//如果本地项目不存在,直接克隆项目
//注:在这里需要设置用户邮箱和用户名,不然后面无法拉去代码
//shell_exec 需要root的权限
shell_exec("git config --global user.email {$email}}");
shell_exec("git config --global user.name {$name}}");
shell_exec("git clone {$gitPath} {$savePath}{$domain}");
shell_exec("chown -R www.www {$savePath}{$domain}");

$log = sprintf('克隆项目');
file_put_contents($logPath, $log, FILE_APPEND);
}

/**
* php防注入和XSS攻击过滤
* @param $arr
*/
function safe_filter(&$arr)
{
$ra =[
'/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/',
'/script/', '/javascript/', '/vbscript/',
'/expression/', '/applet/', '/meta/',
'/xml/', '/blink/', '/link/', '/style/',
'/embed/', '/object/', '/frame/',
'/layer/', '/title/', '/bgsound/',
'/base/', '/onload/', '/onunload/',
'/onchange/', '/onsubmit/', '/onreset/',
'/onselect/', '/onblur/', '/onfocus/',
'/onabort/', '/onkeydown/', '/onkeypress/',
'/onkeyup/', '/onclick/', '/ondblclick/',
'/onmousedown/', '/onmousemove/', '/onmouseout/',
'/onmouseover/', '/onmouseup/', '/onunload/'
];

if (is_array($arr)) {

foreach ($arr as $key => $value) {

if (!is_array($value)) {

//不对magic_quotes_gpc转义过的字符使用addslashes()
//避免双重转义
if (!get_magic_quotes_gpc())
{

// 给单引号(')、双引号(")、反斜线(\)
//与 NUL(NULL 字符)加上反斜线转义
$value = addslashes($value);

}

//删除非打印字符,粗暴式过滤xss可疑字符串
$value = preg_replace($ra, '', $value);

//去除 HTML 和 PHP 标记并转换为 HTML 实体
$arr[$key] = htmlentities(strip_tags($value));

} else {

safe_filter($arr[$key]);

}

}

}
}

使用git webhook实现代码自动部署

https://chenmobuys.github.io/2019/08/19/git-webhook/

作者

Chenmobuys

发布于

2019-08-19

更新于

2020-10-14

许可协议