Gitリポジトリにプッシュすればサーバーに自動でデプロイしてくれるような外部サービスもあるようですけど…
どうせGitHubでソース管理してるなら何箇所にもプッシュせず、GitHubにだけプッシュしたら自動デプロイさせたい!
しかも、プッシュするブランチ毎に動作を変えたい!
ってことで、今回は先人の力を借りまして、レンタルサーバー(エックスサーバー)上にGitHubプッシュでブランチ毎に自動デプロイする仕組みをPHPで作ってみました!
僕の作っている野良WordPressテーマyStandardがまさにこの仕組で自動デプロイされています!
目次
GitHubプッシュでブランチ毎に自動でサーバーにデプロイさせたい
よっひー(@yosiakatsuki)です。
僕は今年から自作のWordPressテーマ(yStandard)の一般配布を始めたのですが、
バージョンアップ時の展開作業が結構面倒で、GitHubのmasterブランチにプッシュしたら自動でサーバー上に配布用zipを作りたいと思い、いろいろ調べてその仕組を作ってみました。
やりたいこと
今回やりたいことの概要はこんな感じです▽
- ローカルからGitHubにpush
- サーバー上でどのブランチのpushイベントかを判断
master
ブランチだったらサーバー上に配置しておいたシェルスクリプトを実行しデプロイ作業をゴニョゴニョ
…っと結構単純な内容です。
デプロイ内容は作るシステムによって変わると思うので適宜ご自身の都合に合わせて変えていただければと思います。
それでは実際の作業に進みます!
GitHubプッシュでブランチ毎に自動デプロイする仕組みをつくる
全体の流れ
今回の仕組みづくりの全体の流れはこんな感じです▽
- GitHubにリモートサーバーのSSHキーを登録
- デプロイ用PHPプログラムの作成・配置
- GitHubでwebhookの設定
- 動作確認
今回、サーバー環境はレンタルサーバーの「エックスサーバー」を使っています。
サーバーに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 -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' );
file_put_contents( LOG_FILE, date( "[Y-m-d H:i:s]" ) . " Start Deploy\n", FILE_APPEND | LOCK_EX );
/**
* データ取得
*/
$post_data = file_get_contents( 'php://input' );
$hmac = hash_hmac( 'sha1', $post_data, SECRET_KEY );
$payload = json_decode( $post_data, true );
/**
* 認証&処理実行
*/
if ( isset( $_SERVER['HTTP_X_HUB_SIGNATURE'] ) && $_SERVER['HTTP_X_HUB_SIGNATURE'] === 'sha1=' . $hmac ) {
foreach ( $commands as $branch => $command ) {
/**
* ブランチ判断
*/
if ( $payload['ref'] == 'refs/heads/' . $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 );
}
}
}
} else {
/**
* 認証失敗
*/
file_put_contents( LOG_ERR, date( "[Y-m-d H:i:s]" ) . " invalid access: " . $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND | LOCK_EX );
}
参考記事からの変化点は…
- ブランチ毎に実行するコマンドを配列で定義
- GitHubから送られてきたJSONデータからプッシュされたブランチを判断
- 対応するコマンドを実行する
…と言った内容を追加しています。
ブランチ毎に実行するコマンドなどを記述した設定ファイル
先述のdeploy.php
で読み込ませる設定ファイルです。
<?php
/**
* 設定
*/
define( 'LOG_FILE', dirname( __FILE__ ) . '/hook.log' );
define( 'LOG_ERR', dirname( __FILE__ ) . '/hook-error.log' );
define( 'SECRET_KEY', 'secretkey' );
/**
* 実行するコマンド
*/
$commands = array(
'develop' => '',//developブランチ
'master' => '' // masterブランチ
);
LOG_FILE
… ログファイル名LOG_ERR
… 認証失敗時のログファイル名SECRET_KEY
… GitHubのwebhookで設定するSecretキー$commands
… key:ブランチ,value:コマンド のペア(配列)
ブランチとコマンドの組み合わせは運用に合わせて変更して下さい。
GitHubでwebhookの設定
デプロイ用プログラムの作成・配置が完了したら、GitHubのwebhookの設定をしていきます。
まずはwebhookを設定するリポジトリの[Settings]→[Webhooks]を開いて「Add 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ファイルを作ったりなどなど…うまくシェルスクリプトと組み合わせることでいろいろ出来るようになって楽できますね!