代码自动部署
前言:
代码托管平台如:Github等提供了一个 Webhooks功能,每次 push 完代码,可以利用它实现代码的自动拉取,这样可以减少好多部署代码的麻烦事。
-
Webhooks
Webhooks 是代码托管平台提供的一个功能,对于任意一个项目,可以设置一个 URL,同时选择一些事件,当触发了这些事件(push、pull request、fork 等)时,代码托管平台会自动请求该 URL,并带上一些必要的参数。
-
实现(以GitHub为例)
-
设置回调URL 选择事件
登录GitHub,新建一个版本库,命名为 testWebhooks,依次点击 Settings -> Webhooks -> Add webhook
- Payload URL 配置为可以测试机上正常访问的地址,比如在/www/ 下面有 index.php 或 main.go ,下面以index.php 为例,并且服务器的环境也搭建好了,可以通过http请求直接访问到
- Content type:POST 携带数据的方式,GitHub 上提供 application/json 和 application/x-www-form-urlencoded 两种,如果上面设置的index.php 中需要用到请求的参数,可以选取自己适合的方式。在这里可以随便选择一个
- Secret:密钥,用于验证
-
添加 Deploy keys
-
两个公钥
- 用户公钥:SSH keys,认证用户身份,添加用户公钥后,对该用户的所有项目拥有读写权限,用于开发机;
- 部署公钥:Deploy keys,对项目进行授权,拥有只读权限,一般用于生产或测试服务器。
-
生成公钥
在服务器上执行下面命令
sudo mkdir /var/www/.ssh //将目录 .ssh 的拥有者、所属组修改为 www-data sudo chown -R www-data:www-data /var/www/.ssh // 在 /var/www/.ssh 目录下生成密钥,同时将该密钥的拥有者、所属组修改为 www-data。在 Ubuntu 中,PHP 运行时的用户为 www-data,如果不修改,PHP 运行时的用户是读不到这个部署公钥的,也就拉不了代码了 sudo -Hu www-data ssh-keygen -t rsa -C "your_name@example.com"
如果不确定系统的 PHP 运行时使用的哪个用户,在测试机上建一个测试PHP文件test.php,然后执行以下即可
// test.php <?php system("whoami"); ?>
-
查看并添加部署公钥
-
查看部署公钥
sudo cat /var/www/.ssh/id_rsa.pub
-
添加部署公钥
依次点击项目的 Setting -> Deploy keys -> Add deploy key,将公钥粘进去,点击 Add key 添加完成
-
-
-
准备钩子文件
之前设置的回调URL可以访问到的index.php的文件,如下:
<?php // 切换到项目目录,执行 git pull,加上 2>&1 会输出一些错误信息,便于调试 shell_exec("cd /www/testWebhooks && git pull 2>&1"); ?>
-
克隆项目文件
cd /www/ sudo -Hu www-data git clone git地址
到此为止,每次往项目中推送代码,测试服务器都会自动拉取代码到测试服务器上,如果没拉取成功,很有可能就是由于前面所说的部署秘钥及项目文件夹没有设置成拉取脚本(index.php文件)运行时的用户。
-
-
效果
打开项目,点击 Setting -> Webhooks,可以看到刚刚设置的回调 URL,点进去拉到最下面 Recent Deliveries,可是看到所有的被触发事件的请求
-
Request
- Headers:请求头,包含一些基本信息;
- Payload:触发这次事件的所有信息都包含在这里面,包括项目名、commit、用户名等等,如果服务器上的钩子文件要做一些高级操作,就可以解析这个字段。
-
Response
- Headers:响应头
- Body:服务器钩子文件的返回信息,调试输出信息可以写到钩子文件里,请求后在这里查看。
每一种事件发送的 Payload 格式是不一样的,关于 Payload 更多信息,请看官方文档: Event Types & Payloads
-
-
服务器拉取代码时进行验证,防止恶意攻击(设置的回调URL有可能被泄露,被认为请求)
-
添加 Webhooks 的时候,Secret 列填上一个随机字符串比如: testWebhooks
-
钩子函数文件 index.php 改为:
<?php $secret = "testWebhooks"; //密钥,和 GitHub 上对应 $path = "/var/www/html/Webhooks"; //服务器上的项目文件目录 $signature = $_SERVER["HTTP_X_HUB_SIGNATURE"]; //获取散列字符串 if($signature) { $rawPost = file_get_contents("php://input"); //获取收到的数据 list($algo, $hash) = explode("=", $signature, 2); //获取散列算法、散列值 if ($hash === hash_hmac($algo, $rawPost, $secret)) { //验证 shell_exec("cd /var/www/html/Webhooks && git pull 2>&1"); echo "代码拉取成功"; } else { echo "Secret 验证失败"; } } else { echo "请输入 Secret"; }
-
注意:
-
每次触发事件,GitHub 会使用 SHA-1 将发送的数据和 Secret 一起散列,生成一个散列字符串,在钩子文件中需要对这个散列字符串进行验证。
-
对于其它代码托管平台,有的不提供 Secret 字段,有的 Secret 在钩子文件中直接验证,具体使用还需要研究一下官方说明
-
-
注: