GitHubのWebhook機能を利用して、 git pushしたら自動でdeployする仕組みを作る方法についてメモをまとめます。

仕組みの全体像

このエントリでは以下のような仕組みを作ることにします。

deployサーバは、大きく以下の2つのモジュールで構成します。

  • Webhookの受け付けイベント管理ファイルをtouchするWebサーバ
  • 定期的にイベント管理ファイルを確認しdeployを実行するスクリプト

仕組みを作る手順

Webサーバの構築

deployサーバに、apache/phpがインストールされている前提で、 以下のようなphpスクリプトを配置します。

イベント管理ファイルを配置するディレクトリを作成し、 apacheの実行ユーザに書き込み権限を与えておきます。 (以下の例では「/home/deploy/webhook/event/」ディレクトリ)

SECRET_KEYには、パスワードツールなどで生成した文字列を指定しておきます。

/var/www/html/github_webhook.php

<?php
$SECRET_KEY = '<ここに鍵>';

if (! isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) die();
if (! $_SERVER['HTTP_X_HUB_SIGNATURE'] === sha1($SECRET_KEY)) die();
$json_string = file_get_contents('php://input');
$payload = json_decode($json_string, true);
if (! $payload['ref']) die();

if ($payload['repository']['full_name'] === '<ユーザ>/<リポジトリ>' && $payload['ref'] === 'refs/heads/deploy/staging') {
  touch('/home/deploy/webhook/event/hookfile');
}
?>
ok

GitHubのリポジトリ画面から、以下のようにたどってWebhookの管理画面を表示します。
GitHubのリポジトリ → Setting → Webhooks & services

「Add Webhook」を選び、「Payload URL」と「Secret」を指定して設定を追加します。
PayloadURLは先ほどのphpのURL、SecretはSECRET_KEYに設定した文字列です。

ここまでの手順を終えた後、githubの「deploy/staging」ブランチにpushすると、deployイベントファイル「/home/deploy/webhook/event/hookfile」が作られることを確認します。

うまくファイルが出来ない場合は、 GitHubのWebhooks&service画面に出てくる「Recent Deliveries」に表示されるリクエストの結果を見ながら、原因を調べます。

deployスクリプトの構築

deployサーバに、以下のようなスクリプトを配置します。

/home/deploy/webhook/deploy.sh

#!/bin/sh

WORK_PATH=/home/deploy/webhook

# 二重起動制御
touch $WORK_PATH/deploy.$$
ln -s $WORK_PATH/deploy.$$ $WORK_PATH/deploy > /dev/null 2>&1
if [ $? == "1" ]; then
  rm $WORK_PATH/deploy.$$
  exit 0
fi

# hookファイルのチェック
if [ ! -f $WORK_PATH/event/hookfile ]; then
  rm $WORK_PATH/deploy $WORK_PATH/deploy.$$
  exit 0
fi

# deploy開始slack通知
curl -X POST --data-urlencode 'payload={"text": "staging環境 デプロイ いきます!", "username": "deploy-user", "icon_url": "<アイコンのURL>"}' https://hooks.slack.com/services/<slackのwebhookのurl>

# deployの実行
<ここにdeploy手続きを記載>

# deploy開始slack通知
curl -X POST --data-urlencode 'payload={"text": "staging環境 デプロイ しました!", "username": "deploy-user", "icon_url": "<アイコンのURL>"}' https://hooks.slack.com/services/<slackのwebhookのurl>

# hookファイルの削除
rm $WORK_PATH/event/hookfile

# LOCKファイル削除
rm $WORK_PATH/deploy $WORK_PATH/deploy.$$

shell scriptに実行権を与えたら、以下のようにcrontabに設定します。

crontab -e

* * * * * /home/deploy/webhook/deploy.sh

ここまでの手順を終えた後、もう一度githubの「deploy/staging」ブランチにpushすると、デプロイ手続きが実行され、slackに通知が送られます。
次のような感じで。

後は使いやすいように。deployの成功/失敗でslackのメッセージを変えるとか、deploy時のログをメールで送るとか、shellscriptを変更したりなどすれば良いかと思います。