使用 github webhook 进行自动化部署
给php用户生成ssh-key
sudo -Hu www ssh-keygen -t rsa
# 一路回车就完事了
# 然后保存公钥到github上
cat /home/www/.ssh/id_rsa.pub
检查php是否允许使用 shell_exec()
<?php
echo shell_exec('ls -la');
如果无法成功执行,则需要修改 php.ini
并重启 php-fpm 。
sudo权限
- 编辑
/etc/sudoers
文件, 允许www
用户使用sudo
指令并且不需要密码
# /etc/sudoers
www ALL=(ALL) NOPASSWD:ALL
- 这一步骤是为了允许php成功执行 git pull/composer install/npm run install 等命令。 我认为给
www
用户赋予sudo
权限是一种不安全的行为,目前有另一种方案,是把整个项目文件的权限都给到www
。 因为未进行过具体操作,所以这里不再赘述
github中设置webhook
- github 的仓库主页setting -> setting -> Webhooks -> Add webhook
Payload URL
填入你的 webhook 地址Content type
根据个人需要,建议是application/json
Secret
填入你自定义的密码, 用于防止 webhook 泄漏后被恶意调用,鉴别非 github 的请求- 下一个选项,可以根据自己的需要,选择需要发送触发 webhook 的事件。 建议是只处理
Pull request
,选择Let me select individual events.
并勾选Pull requests
即可
安装 Laravel Shield 中间件保护 github webhook
# 引入package
composer require laravel-shield/github
# 输出配置文件
php artisan vendor:publish
# 然后选择 laravel-shield
# 之后就会生成 config/shield.php
# 务必把刚才 github 中设置的 Secret 写入 .env 文件,通过 env() 来读取使用,避免泄漏
# config/shield.php
<?php
return [
'services' => [
'github' => [
'driver' => \Shield\GitHub\GitHub::class,
'options' => [
'token' => env('GITHUB_WEBHOOK_SECRET'),
]
]
]
];
# .env
...
GITHUB_WEBHOOK_SECRET=刚才在github中设置的密码
...
创建一个webhook路由
- 以 laravel 为例:
- 创建一个钩子 controller
php artisan make:controller HooksController
编辑路由
# routes/web.php ... // webhooks , middleware('shield:github') 为刚刚安装的 laravel shield package 中间件 Route::post('hooks/github', 'HooksController@github')->middleware('shield:github'); ...
- 编辑 webhook 文件
<?php
namespace App\Http\Controllers;
use Symfony\Component\HttpFoundation\Response as HttpResponse;
class HooksController extends ApiController
{
public function github()
{
$pullRequestInformation = \Request::json('pull_request');
if (empty($pullRequestInformation)) {
return $this->response->setStatusCode(HttpResponse::HTTP_OK)->json('not found pull request information');
}
// 只处理合并的 webhook , 其他开始/关闭都不进行操作
if (
$pullRequestInformation['state'] != 'closed'
|| $pullRequestInformation['merged'] != true
) {
return $this->response->setStatusCode(HttpResponse::HTTP_OK)->json("it is not a merge action");
}
// 为适应多环境,可以自行设置限制分支
if (empty(env('CURRENT_BRANCH'))) {
return $this->response->setStatusCode(HttpResponse::HTTP_OK)->json("need to set a current branch.");
}
// 如果 pull request 不是更新本分支,则忽略
if (
$pullRequestInformation['base']['ref'] != env('CURRENT_BRANCH')
) {
return $this->response->setStatusCode(HttpResponse::HTTP_OK)->json("current branch is incorrect");
}
// 执行 git pull , 并进行记录
$result = shell_exec('cd '.base_path().' && sudo git pull 2>&1');
\Log::info(__METHOD__." : $result");
// 还可根据 $pullRequestInformation 中返回的更新文件array, 执行例如 composer install/migrate 等操作
// 最后返回 http 200 给 github 即可
return $this->response->setStatusCode(HttpResponse::HTTP_OK)->json($result);
}
}
测试
- 一切准备之后,更新好线上机器代码,随便创建一个 pull request , 通过github 的仓库主页setting -> setting -> Webhooks -> 对应的webhook地址 ,在最下方会显示每一次 request 的状况和返回
- 如果出现错误, 解决后可以直接重新执行 (
Rediliver
) 而不需要重复的新建/关闭 pull request
bingo!
恭喜你~ 完成了简易的 webhook 自动部署
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。