Webhook+PHPを利用したGitデプロイ自動化
BitbucketのWebhook+PHPスクリプトによる外部サービスを使わない簡単なデプロイ自動化をしてみます。
今回の環境は以下のような感じ。nginxですが、ApacheでもSSHキーの部分を変更すれば対応できるかと思います。
▼環境 Bitbucket CentOS 6 nginx php-fpm
*PHPでシェルコマンドを実行するexec()関数が使える前提
デプロイ自動化のイメージ
- ローカルからBitbucketにpush
- BitbucketからWebhookでリモートサーバーのdeploy.phpにリクエスト
- deploy.phpがexec()でgitコマンドを実行
- git fetch && git checkoutで更新を反映
ローカル → Bitbucket → リモートサーバー
サーバーにGitレポジトリをクローン
$ mkdir /git
$ cd /git
$ git clone --mirror git@bitbucket.org:accountname/myproject.git
git clone –mirror とするとリポジトリのミラーが作成されます。
$ cd /git/myproject.git
$ GIT_WORK_TREE=/var/www/html git checkout -f
WordPressのテーマだけホストする場合は、GIT_WORK_TREEを/var/www/html/wp-content/themes/twentyfourteenというようにします。
デプロイ用のPHPスクリプトを作成
まずデプロイ用のPHPスクリプトを作ります。PHPでシェルコマンドを実行するので、exec()関数使います。
実際にexec()で実行するシェルコマンドは以下のような感じ。
$ cd /git/myproject.git/
$ git fetch
$ GIT_WORK_TREE=/var/www/html/ git checkout -f
実際のPHPスクリプトは以下の通りです。今回は、ログ出力もなしのでミニマムのスクリプトを紹介します。
$git_path, $www_path, $secret_keyを環境に合わせて変更してください。
//GitとWebのディレクトリへのフルパス
$git_path = '/git/myproject.git/';
$www_path = '/var/www/html';
//example.com/deploy.php?key=以下の任意のキー
$secret_key = 'YOUR_SECRET_KEY';
//keyパラメータと$secret_keyが合っていればexec()
if ($_GET[key] === $secret_key) {
$command = "cd {$git_path} && git fetch && GIT_WORK_TREE={$www_path} git checkout -f";
exec($command);
}
/var/www/html以下にdeploy.phpとして保存します。
$ vi /var/www/html/deploy.php
nginxのSSHキーをssh-keygenで作成
リモートサーバーのSSHキーをBitbucketに登録します。
外部(Bitbucket)からのHTTPリクエストを受けて、deploy.phpが実行されるのでSSHキーはPHPを実行するnginxのものを作ります。
もしApacheを使っている場合は、Apacheに置き換えればOKかと。
sshキーの置き場所は、Apacheのデフォルトと同じ/var/www/.sshにします。
nginxのデフォルトだと/var/cache/nginx/.sshになっていて、キャッシュ用ディレクトリのせいなのか2度ほど消えてしまったことがあるためです。
$ mkdir /var/www/.ssh
$ chmod 777 .ssh
$ sudo -u nginx ssh-keygen
Enter file in which to save the key (/var/cache/nginx/.ssh/id_rsa):
とでるので、/var/www/.ssh/id_rsaと入力してEnter。パスワードは空のままなのでEnterします。
Generating public/private rsa key pair. Enter file in which to save the key (/var/cache/nginx/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /var/cache/nginx/.ssh/id_rsa. Your public key has been saved in /var/cache/nginx/.ssh/id_rsa.pub. The key fingerprint is: aa:jd:87:40:58:cn:as:jd:73:8f:a0 nginx@example.com The key's randomart image is: +--[ RSA 2048]----+ | . | | . | | . + * | | . S o | | = . = . oE | | . .=.+o | | S...o= oo| +-----------------+
パーミッションを変更しておきます。
$ chown -R nginx:nginx .ssh
$ chmod 700 -R .ssh
あとはSSHを登録。
$ ssh-agent /bin/bash
$ ssh-add /var/www/.ssh/id_rsa
登録されていることを確認します。
$ ssh-add -l
2048 aa:jd:87:40:58:cn:as:jd:73:8f:a0/var/www/.ssh/id_rsa (RSA)
Bitbucketのデプロイキー登録&Webhookの設定
$ cat /var/www/.ssh/id_rsa.pub
Settings > デプロイ鍵 > 鍵を追加をクリック。catした文字列をコピペ。
さらに、Webhookを設定します。Settings > Webhooks > Add webhookをクリック。
タイトルは、「Deploy to exmaple.com」など好きなタイトルにして、URLは「http://example.com/deploy.php?key=SECRET_KEY」を入力します。
フックとなるアクションはpush以外にもmergeなどもあるので、開発サーバーのフックはdevelopブランチへのpush、本番サーバーのフックはmasterブランチへのmergeなど分けることもできます。
パーミッションを変更
/gitのパーミッションと/var/www/.sshを変更します。
$ chown -R nginx:nginx /git/
$ chown nginx:nginx /var/www/html/deploy.php
ssh_configの編集
nginxのsshキーの場所をデフォルトから変更したので、ssh_configを編集します。
~/.ssh/configはユーザー用、ssh_configはシステム共通のsshの設定ファイルです。
$ vi /etc/ssh/ssh_config
以下の内容を追記します。
Host bitbucket.org User git IdentityFile /var/www/.ssh/id_rsa
ローカル開発環境からpush
最後にローカル開発環境からpushします。README.mdなど好きなファイルを編集して、pushしてください。
$ git add README.md
$ git commit -m 'change README.md
$ git push -u origin master
あとは、サーバー側も更新されていればOK!ファイルサイズによっては、デプロイに時間がかかる場合もあります。
BitbucketのWebhookが動かない場合のトラブルシューティング
以下の順で確認していきます。
1. Webhookが200を返しているか 2. PHPスクリプトは間違っていないか 3. ファイルパーミッションの確認 4. デプロイキーが正常に登録されているか 5. exec()でgitコマンドが実行されない
1. Webhookが200を返しているか
Bitbucketのレポジトリ > Settings > Webhook からView requestsをクリック。
Webhookのリクエスト履歴が見れるので、右端のステータスコードが200になっていることを確認。
2. PHPスクリプトは間違っていないか
サーバーにssh接続して、ターミナルから直接PHPを実行してみます。これで更新が反映されているようなら、PHPには問題ないはずです。
$ cd /var/www/html/
$ php deploy.php
3. ファイルパーミッションの確認
ファイルパーミッションが正しく設定されているか確認します。ls -laで確認するか、chown、chmodコマンドを再実行してみてください。
4. デプロイキーが正常に登録されているか
そのユーザーのssh鍵の設定が正しく行われているか確認します。実際にnginxユーザーになってgit fetchして確認するのが簡単なのでやってみます。
$ su -s /bin/bash nginx
$ cd /git/myproject.git
$ git fetch
ついでに、nginxユーザーでphp deploy.phpをして正常に動くことも確認しておくと良いと思います。
5. exec()でgitコマンドが実行されない
意外と落とし穴なのが、HTTPリクエストで実行されるPHPスクリプトがnginxじゃなくてApacheだったといった単純な罠。
これを確認するために、シェルコマンドのwhoamiを利用します。/var/www/htmlにtest.phpなどを作って以下をコピペ。
echo exec("whoami");
http://example.com/test.phpにブラウザからアクセスするとPHPスクリプトがどのユーザーで実行されたのか表示されます。
もし実行結果がapacheとなっていれば、service nginx statusとservice httpd statusでnginxが起動していて、apacheが止まっていることを確認。
さらに、/etc/php-fpm.d/www.confを開いてuserとgroupがnginxになっていることを確認します。
user = nginx group = nginx
ここまで確認できればある程度のエラーには対応できるかなと思います。