このブログはJekyll製なのですが、デプロイ方法が拙くて、jekyll new
で生成されるRakefileのdeploy taskを使って、ローカルマシンからサーバへrsyncしていました。
このデプロイ作業がめんどくさく、かといってプラグインを使いたかったのでGitHub Pagesは利用できず…と困っていたのですが、GitHubにWebHook (Post-Receive Hooks) という便利ツールがあることを知りました。
Webサイトをgithubで管理してpush時に自動的に同期する方法 - Blog by Sadayuki Furuhashi
…そこで、github の Post-Receive Hook を使うと、リポジトリに変更を push すると同時に、Webサーバにも同期させることができます。…
自分もこの知恵をお借りしようと思い、GitHubのWebHook通知を受け取り、サーバ側でビルド・syncするプログラムを用意しました。
動作
動作自体は単純なもので、
- ローカルマシンからGitHubへpushする
- GitHubからWebHookがサーバへ通知される
- サーバはWebHookを受け取ると、リポジトリから更新をpullする
- ブログのビルドスクリプトを実行する (
jekyll build
) - ビルド完了後、Webサーバのroot directoryへ同期される (
rsync
)
となっています。
4. Pull
+--------------------------+
| |
| ..........................
| : server :
v : :
+-------+ 1. Push +--------+ 2. WebHook : +--------------------+ :
| local | ---------> | github | ------------> : | blog_worker.rb | :
+-------+ +--------+ : +--------------------+ :
: | :
: | 3. Exec :
: v :
: +--------------------+ :
: | build.sh | :
: +--------------------+ :
: | :
: | 5. Build and Sync :
: v :
: +--------------------+ :
: | blog directory | :
: +--------------------+ :
: :
:........................:
script
blog_worker.rb
WebHook通知のレシーバとして、以下のスクリプトを用意しました。
pushの中身はPost-Receive Hooks#The payloadを参考にしています。
未だにこのスクリプト名がしっくりきていません。
require 'sinatra'
require 'json'
dir = File.dirname(__FILE__)
SYNC_SCRIPT = "#{dir}/build.sh"
post "/" do
push = JSON.parse(params[:payload])
system(SYNC_SCRIPT) if push["repository"]["id"] == 11420983
end
build.sh
実際このスクリプトがほとんどすべての作業をやってくれています。
- blogリポジトリを更新する
rake build
でビルドする (中で呼ばれてるのはjekyll build
)- ビルド完了後に生成される
_site/
をnginx rootへrsyncする
というステップになっています。
当初はnginx rootへ_site/
のsymlinkを張ろうかと思ったんですが、autoindex on
が必要で、nginxのデフォルトをあまり変更したくなかったのでrsyncに至ります。
#!/bin/bash
set -eu
GIT_LOCATION=/usr/local/src/blog
REPO=git@github.com:hfm/blog.git
WWW_LOCATION=/var/www/blog
BUNDLE_GEMFILE=$GIT_LOCATION/Gemfile
# update_repo
[ -d $GIT_LOCATION ] || mkdir -p $GIT_LOCATION
[ -d $GIT_LOCATION/.git ] || git clone $REPO $GIT_LOCATION
cd $GIT_LOCATION && git pull origin master
# build and sync
[ -d ./.bundle ] || bundle install --path vendor
bundle exec rake build
rsync -a --delete $GIT_LOCATION/_site/ $WWW_LOCATION
BUNDLE_GEMFILE
はbundle exec
時に作られる?環境変数で、bundle execしたGemfileの絶対パスが入ります。
blog_workerは$GIT_LOCATION
とは違うbundle contextで、blog_workerのGemfileのパスが入っています。
このままでは$GIT_LOCATION
でbundle実行が出来ないため、途中で書き換えています。
あるbundle context内から別のbundle contextを実行するという、無理矢理感漂うやり方ですが、こういうのって皆さんどうされているのでしょう…。
GitHubにpushしたら自動更新
ともかくこれで、ブログ記事を書いてGitHubにpushすれば、あとはサーバが勝手に更新してくれるようになりました。 便利だ!