indexgo
login

[PHP版] GitレポジトリからWebhookで本番・テストサーバーに自動公開する

Gitレポジトリにpushしたら、対応するドメインにデータを反映させる流れを作りました。Webhook利用して、本番・テストサーバーに自動公開できます。レポジトリサービスはGitlabを使っていますが、他のサービスでも使えるはずです。

作成者:Ssさん 公開日:2018年8月24日 16時10分 更新日:2018年8月24日 16時36分

全体の流れ

(1) gitレポジトリにpushする
(2) pushされたブランチに対応するドメインのサーバーのデータをgit pullで更新する
(3) ログを残す

ドメインとブランチの構成

(0) Webhook用ドメイン
URL: hook.example.com
サーバー内のパス:/hook.example.com

(1) 本番
ブランチ: master
URL: www.example.com
サーバー内のパス:/www

(2) 開発
ブランチ: dev
URL: dev.example.com
サーバー内のパス:/dev.example.com

(3) ステージング
ブランチ: stg
URL: stg.example.com
サーバー内のパス:/stg.example.com

Gitlabの設定

Webhookというメニューがないためわかりづらいですが、

Settings > Integrations

の画面がWebhookの追加画面です。

ここに、URLとSecret Tokenを入れます。Triggerは、「Push events」のみにチェックを入れます。

本番サーバー側に置くプログラム

(0) まずは設定を書いて置く

// Gitlabの設定
$reposigory_url = "gitlab.com";
$project_name = "Gitlabのプロジェクト名";
$git_user = 'Gitlabのユーザー名';
$git_pass = 'Gitlabのパスワード';
$secret_token = '好きな文字列';


//サーバー側の設定
$git = '/usr/local/bin/git';
$log_file = '.webhook_logs.txt';
$branch_list = [
    'master'=>'../www',
    'dev'=>'../dev.example.com',
    'stg'=>'../stg.example.com',
];

(1) PHPでHTTP Header情報を取得する

PHP: getallheaders - Manual

http://php.net/manual/ja/function.getallheaders.php

Good SoSo

自分のGitlabレポジトリからのWebhookなのかを認証するためのTokenを確認します。

Gitlabの設定では、Secret Token」フィールドに予め自分で作成したコードを入れておきます。

$header = getallheaders();

$secret_token = '12345678910';

(2) GitlabからのWebhook以外を拒否する

エラー理由もjson形式で返すようにして、ついでにHTTPレスポンスを401にしておきます

PHPでHTTPレスポンスを返すのは「http_response_code(番号)」でいけます。

PHP: http_response_code - Manual

http://php.net/manual/ja/function.http-response-code.php

Good SoSo
if(!isset($header['X-Gitlab-Token'])){
    http_response_code(401);
    echo json_encode(['message'=>'Unauthorized.']);
    die;
}

(3) tokenが合わなかったらエラーを返す

// tokenがマッチするか?
if($header['X-Gitlab-Token'] !== $secret_token){
  http_response_code(401);
    echo json_encode(['message'=>'Token mismatch.']);
    die;
}
// 一応Push Hookだけに対応
if($header['X-Gitlab-Event'] !== "Push Hook"){
    http_response_code(401);
    echo json_encode(['message'=>'Disallowed Event']);
    die;
}

(4) Gitlabから送られてくるPOST情報を読み取る

Json形式でPOSTされてくるので、php://inputで情報を読み取ります。

PHPで処理しやすいように,json_decodeで配列に変換します。

$json_string = file_get_contents('php://input');
$json = json_decode($json_string,true);

(5) Push Hookされたブランチ名を取得する

$branch_name = str_replace("refs/heads/", "", $json['ref']);

(6-0) ブランチに対応するディレクトリで、git pullを実行する

if(isset($branch_list[$branch_name])){
    $path = $branch_list[$branch_name];
    $git_remote = "https://{$git_user}:{$git_pass}@{$reposigory_url}/{$git_user}/{$project_name}.git";
}

(6-1) 初回の場合(対象ディレクトリに.gitディレクトリがない場合)はまずgit clone

//初回の場合はまずはクローン
if(!file_exists("{$path}/.git/")){
    exec("cd {$path} && ${git} clone {$git_remote} .");
}

PHP: file_exists - Manual

http://php.net/manual/ja/function.file-exists.php

Good SoSo

(6-2) git pullを実行

// pullする
exec("cd {$path} && ${git} pull {$git_remote} {$branch_name} 2>&1", $output, $exit_status);

(6-3) ログを取る

$date = date("Y-m-d H:i:s");
if ($exit_status > 0) {
    $error_msg = "[{$date}] Error: \n";
    foreach ($output as $line) {
        $error_msg .= "    {$line}\n";
    }
   error_log($error_msg,3,$log_file);
} else {
    error_log("[{$date}] Updated successfully\n",3,$log_file);
}

あとはレポジトリにpushするだけ!

masterブランチへpushすれば本番サーバーに、stgブランチにプッシュすれば、stg.example.comにアップデートがされているはずです。

こちらのページを参考にさせていただきました!

GitlabのWebhookを使って簡易デプロイ(Webサーバへ)をしてみた

https://qiita.com/redamoon/items/a47178621d8bd8d95edf

Good SoSo
以前、[bitbucket-syncを使ってサーバ自動化をしてみた](http://qiita.com/redamoon/items/7ac784b3eb53d09b6e93)をやって簡易デプロイを行なう方法を公開しましたが、Git...