Схема работы следующая. В github на репозиторий ставится хука - post на мой URL. Главное чтобы данные приходили не в json. На веб сервере запрос разбирается и добавляется задача в gearman какой скрипт выполнить и с какими параметрами (название ветки). В crone крутится скрипт который случает очередь gearman'а и при получении задания - выполняет его. Почему нужен gearman? Развертывание может происходить достаточно долго и если его выполнять сразу при получении запроса от github времени может не хватить. В схеме с gearman развертывание может длиться сколь угодно по времени и нет конкуренции, так как все запросы обрабатываются последовательно.
Скрипт для получения хук index.php
Скрипт для получения хук index.php
<?phpСкрипт для обработки заданий gearman deploy.php
const QUEUE_NAME = 'deploy';
$map = [
'/hook/super-secret' => [
'name' => 'Project',
'deploy' => '/opt/deploy/init.sh',
'remove' => '/opt/deploy/remove.sh'
],
];
function log_message($message)
{
$message = '[' . date('c') . '] ' . $message . PHP_EOL;
file_put_contents(__DIR__ . '/../logs/deploy.log', $message, FILE_APPEND);
}
$uri = $_SERVER['REQUEST_URI'];
if (isset($map[$uri]) && isset($_POST['payload'])) {
$data = json_decode($_POST['payload'], true);
$branch = isset($data['ref']) ? $data['ref'] : null;
$deleted = isset($data['deleted']) ? $data['deleted'] : false;
if ($deleted) {
log_message(sprintf('[%s] Delete branch %s', $map[$uri]['name'], $branch));
} else {
log_message(sprintf('[%s] Deploy branch %s', $map[$uri]['name'], $branch));
}
if (preg_match('/^refs\/heads\/(.+)$/', $branch, $match) && $match[1]) {
$data = [
'branch' => $match[1],
'script' => $deleted ? $map[$uri]['remove'] : $map[$uri]['deploy'],
];
$client = new GearmanClient();
$client->addServer();
$client->doHighBackground(QUEUE_NAME, json_encode($data));
}
}
<?phpdeploy.php добавляем в cron вот так flock -n /var/lock/php_deploy.lock -c "php /opt/deploy/deploy.php" чтобы не запускалось больше одной копии.
/*
* flock -n /var/lock/php_deploy.lock -c "php /opt/deploy/deploy.php"
*/
const QUEUE_NAME = 'deploy';
function log_message($message)
{
$message = '[' . date('c') . '] ' . $message . PHP_EOL;
file_put_contents(__DIR__ . '/logs/deploy.log', $message, FILE_APPEND);
}
$worker = new GearmanWorker();
$worker->addServer();
$worker->setTimeout(60000);
$worker->addFunction(
QUEUE_NAME,
function ($job) {
$data = @json_decode($job->workload(), true);
if (isset($data['script'], $data['branch'])) {
log_message($data['script'] . ' ' . $data['branch']);
system($data['script'] . ' ' . $data['branch']);
}
return 0;
}
);
do {
$worker->work();
} while ($worker->returnCode() == GEARMAN_SUCCESS);
Еще можно выполнить fastcgi_finish_request() чтобы сразу закрыть соединение и после запустить сценарий деплоя.
ОтветитьУдалитьignore_user_abort(true);
set_time_limit(0);
fastcgi_finish_request();
// Deployment...