GitHubにpushしたらブランチ毎に自動デプロイする仕組みをXサーバー上に作ってみた

GitHubにプッシュしたらブランチ毎に自動デプロイする仕組みをXサーバー上に作ってみた

Gitリポジトリにプッシュすればサーバーに自動でデプロイしてくれるような外部サービスもあるようですけど…

どうせGitHubでソース管理してるなら何箇所にもプッシュせず、GitHubにだけプッシュしたら自動デプロイさせたい!

しかも、プッシュするブランチ毎に動作を変えたい!

ってことで、今回は先人の力を借りまして、レンタルサーバー(エックスサーバー)上にGitHubプッシュでブランチ毎に自動デプロイする仕組みをPHPで作ってみました

僕の作っている野良WordPressテーマyStandardがまさにこの仕組で自動デプロイされています!

GitHubプッシュでブランチ毎に自動でサーバーにデプロイさせたい

よっひー(@yosiakatsuki)です。

僕は今年から自作のWordPressテーマ(yStandard)の一般配布を始めたのですが、

バージョンアップ時の展開作業が結構面倒で、GitHubのmasterブランチにプッシュしたら自動でサーバー上に配布用zipを作りたいと思い、いろいろ調べてその仕組を作ってみました。

やりたいこと

今回やりたいことの概要はこんな感じです▽

  • ローカルからGitHubにpush
  • サーバー上でどのブランチのpushイベントかを判断
  • masterブランチだったらサーバー上に配置しておいたシェルスクリプトを実行しデプロイ作業をゴニョゴニョ

…っと結構単純な内容です。

デプロイ内容は作るシステムによって変わると思うので適宜ご自身の都合に合わせて変えていただければと思います。

それでは実際の作業に進みます!

GitHubプッシュでブランチ毎に自動デプロイする仕組みをつくる

全体の流れ

今回の仕組みづくりの全体の流れはこんな感じです▽

  1. GitHubにリモートサーバーのSSHキーを登録
  2. デプロイ用PHPプログラムの作成・配置
  3. GitHubでwebhookの設定
  4. 動作確認

今回、サーバー環境はレンタルサーバーの「エックスサーバー」を使っています。

サーバーにSSH接続出来ることが前提になります!

GitHubにリモートサーバーのSSHキーを登録

SSH鍵の作成

自動デプロイの一連の流れの中でリモートサーバーからgit pullなどのgitコマンドを実行するので、リモートサーバー側でSSHキーを作成し、GitHubに登録します。

エックスサーバーへSSH接続した後、ssh-keygenでSSHキーを生成します

$ ssh-keygen -t rsa

パスフレーズは空にしておきます(パスフレーズありの鍵作ったらうまく動かなかった)

GitHubに公開鍵を登録

SSHキーが生成出来たらGitHubに公開鍵を登録します

以下のコマンドで公開鍵の中身を表示させて、コピーしておきます。

cat /home/[サーバーID]/.ssh/id_rsa.pub
GitHubの設定ページからSSH鍵を登録します

GitHubのアカウント設定ページからコピーした公開鍵を登録します。

登録が完了したら接続確認してみます

$ ssh -T git@github.com

「Hi yosiakatsuki! You've successfully authenticated, but GitHub does not provide shell access.」のような返事があればOKです(「yosiakatsuki」はアカウント名)

SSH鍵に名前をつけて生成した場合

SSH鍵を生成する際にデフォルトの「id_rsa」ではなく、名前をつけた場合は、.sshディレクトリ内にconfigファイルを作成して接続先情報を書いておきます。

#configの中身の例
Host github
HostName github.com
IdentityFile ~/.ssh/id_rsa_github #生成した鍵ファイル名
User git

編集が完了したら接続確認です

$ ssh -T github

「Hi xxxx! You've successfully ~~」が帰ってくればOKです!

デプロイ用PHPプログラムの作成・配置

デプロイ用のPHPプログラムについては以下のQiitaの記事を参考に、ちょこっと改造していきます。(細かい動きの説明は参考記事をご覧ください)

記事ではwebhookの通知を受けた時に実行するコマンドなどがコード直書きになっているので、もう少し汎用性を出すためにブランチ毎に実行するコマンドなどはconfig.phpというファイルを用意して読み込ませるようにしてみました。

GitHubにプッシュの通知を受け取るプログラム

deploy.php」とでも名付けておきます

<?php

// 設定
require_once(dirname(__FILE__).'/config.php');

$header = getallheaders();
$post_data = file_get_contents( 'php://input' );
$hmac = hash_hmac('sha1', $post_data, $SECRET_KEY);
if ( isset($header['X-Hub-Signature']) && $header['X-Hub-Signature'] === 'sha1='.$hmac ) {
    $payload = json_decode($post_data, true);  // 受け取ったJSONデータ

    foreach ($COMMANDS as $branch => $command) {
      // ブランチ判断
      if($payload['ref'] == $branch){
        if($command !== ''){
          // コマンド実行
          exec($command);
          file_put_contents($LOG_FILE, date("[Y-m-d H:i:s]")." ".$_SERVER['REMOTE_ADDR']." ".$branch." ".$payload['commits'][0]['message']."\n", FILE_APPEND|LOCK_EX);
        }
      }
    }//foreach


} else {
    // 認証失敗
    file_put_contents($LOG_FILE_ERR, date("[Y-m-d H:i:s]")." invalid access: ".$_SERVER['REMOTE_ADDR']."\n", FILE_APPEND|LOCK_EX);
}

//http://qiita.com/oyas/items/1cbdc3e0ac35d4316885
?>

参考記事からの変化点は…

  • ブランチ毎に実行するコマンドを配列で定義
  • GitHubから送られてきたJSONデータからプッシュされたブランチを判断
  • 対応するコマンドを実行する

…と言った内容を追加しています。

ブランチ毎に実行するコマンドなどを記述した設定ファイル

先述のdeploy.phpで読み込ませる設定ファイルです。

<?php
  // 設定
  $LOG_FILE = dirname(__FILE__).'/hook.log';
  $LOG_FILE_ERR = dirname(__FILE__).'/hook-error.log';
  $SECRET_KEY = 'secretkey';

  // 実行するコマンド
  $COMMANDS = array(
                'refs/heads/develop'=>'',//developブランチ
                'refs/heads/master'=>'' // masterブランチ
              );

 ?>
  • $LOG_FILE … ログファイル名
  • $LOG_FILE_ERR … 認証失敗時のログファイル名
  • $SECRET_KEY… GitHubのwebhookで設定するSecretキー
  • $COMMANDS … key:ブランチ,value:コマンド のペア(配列)

ブランチとコマンドの組み合わせは運用に合わせて変更して下さい。

GitHubでwebhookの設定

デプロイ用プログラムの作成・配置が完了したら、GitHubのwebhookの設定をしていきます。

リポジトリの設定ページからwebhookの設定をしていきます

まずはwebhookを設定するリポジトリの[Settings]→[Webhooks]を開いて「Add webhook」からwebhookを追加します。

webhookの各種設定をしていきます
  • Payload URL : 先に配置したdeploy.phpまでのURLを入力します。
  • Content type : application/jsonを選択
  • Secret : 先に作成したconfig.phpの$SECRET_KEYに入力するパスワード的なもの
  • Which events would you like to trigger this webhook? : 「Just the push event.」でプッシュ時に実行されるようにします。

Basic認証をかけたディレクトリにdeploy.phpを配置する場合は「Payload URL」にhttps://[Basic認証のユーザー]:[Basic認証のパスワード]@[ドメイン以下〜]という形式で設定します。

動作確認

デプロイ用プログラムの配置、GitHubでのwebhookの設定が完了したら実際にローカルからGitHubにプッシュして動作確認してみます!

まずは簡単に1行テキストを吐き出すだけのようなシェルスクリプトで試してみて、その時点で期待通りの結果にならなければphpプログラムかwebhookの設定を見直してみて下さい。

途中でGitコマンドを実行した場合に動作がおかしくなる場合はちゃんとSSH接続できているかなどを再確認してみて下さい

まとめ

GitHubのwebhookを使うとどのブランチにPushしても動いてしまうようですが、今回の方法でなんとか特定のブランチへのPushのみでデプロイ処理出来るようになりました!

あとは組み込みたいサイトごとにconfig.phpをつけかえればいいだけなのである程度汎用的なものになったのでは?…と思います。

自分のブログはローカル環境にVCCWを使っているので修正したテーマを本番サイトに適用するのはWordMoveで一発なんですけど、配布用にzipファイルを作ったりなどなど…うまくシェルスクリプトと組み合わせることでいろいろ出来るようになって楽できますね!

今回参考にした記事