2014年のふりかえりエントリも書いたし、今年はもうブログ書かないと思った?...残念!むしろいろいろと遊んでみてるのでした!
ってことで、表題の件。
前提
awesome_events は、CircleCI による CI まではできているという状態。
awesome_events とは、"パーフェクト Ruby on Rails" のサンプルアプリケーションで、a-know は既に写経済み。
- 作者: すがわらまさのり,前島真一,近藤宇智朗,橋立友宏
- 出版社/メーカー: 技術評論社
- 発売日: 2014/10/31
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
今回やりたいこと
- awesome_events の master ブランチに push が行われ、そのテストが通ったら、master ブランチがそのまま heroku にデプロイされるようにしたい
- それと同様のことを、feature ブランチでも行いたい
- feature ブランチの内容を、staging 環境(に見立てた heroku app)にデプロイしたい。
効果・効能
heroku への手動デプロイが不要になる。また、全ての変更を feature ブランチ(PR)を通して行うようにすれば、その変更を master ブランチにマージする前に heroku 環境で確認することができる。
つまり
CircleCIでfeature branchをHerokuに継続deploy - Masatomo Nakano Blog の記事の内容ができれば良い!
やったこと
まずは master ブランチ -> 本番用 heroku app、の実現
下準備
もちろん CircleCIでfeature branchをHerokuに継続deploy - Masatomo Nakano Blog を参考に。
deploy 用の shellscript が下記のようになっていたので、それぞれ手入れ。
- 上記サイトの方のサイトから毎回 curl するようになっていた
- 自分のところ(s3 に置いた)から curl するように
- デプロイ先の heroku app が、何らかの organization に属する前提だった
heroku join --app ${herokuapp}
をコメントアウト
あとこれも上記ブログには書かれているのだけど、
- heroku への SSH key の登録
HEROKU_USER
とHEROKU_API_TOKEN
を、CircleCIのEnvironment variablesに設定する(deploy script から参照される)
これらもやっておく必要がある。
heroku への SSH key の登録は、CircleCI の当該プロジェクト設定メニュー Continuous Deployment
の heroku 項目から行えるのでそれで済ませちゃうのが一番簡単かな。
HEROKU_USER
は heroku に登録されているメールアドレス、HEROKU_API_TOKEN
は heroku の Manage Account > Account タブの下の方で見れる、API Key の値でおk。
上記のようなことを含めた対応は、全てこの PR にまとめてますので、よろしければ。
実際の動き
PR(ブランチ)に対しての CI は走るが、今回はまだ production 向けのデプロイしか準備してないので、CI が通ったからといってこの段階ではまだなにも行われない。
肝心なのは、これが master ブランチにマージされてからの動き。
実際にマージしてみると、まず master ブランチの CI が走る。これは今まで通り。
おお、deploy script が正常に走った...
いぇあ!deploy された!☆-(ノ゚Д゚)八(゚Д゚ )ノイエーイ
feature ブランチの内容を staging 用途の heroku app にデプロイする
考えなきゃいけないこと
ここまでで実施した production 用のものは簡単だ。なぜなら
- デプロイ対象は master ブランチ固定
- デプロイ先の heroku app も固定(
awesome-events-production.herokuapp.com
)- 必要な configuration(環境変数とかアドオンとか) も既にされている前提で良いことが多い(と思う)
といった要因があるからだ。feature ブランチの内容を staging 用途の heroku app にデプロイするとなると、多分下記のようなことを考えなければならないはず。
- デプロイ対象は master ブランチ以外の全てのブランチ
- デプロイ先の heroku app は可変
- app がひとつしかないと、いつ他者の feature ブランチの内容で deploy されてしまうかわからないので、デプロイ先としては複数あるべきだろう
ここらへん、上記ブログではどのように解決しているのか、も考えながらやってみたい。
"デプロイ対象は master ブランチ以外の全てのブランチ" の対処
これは簡単。circle.yml には下記のように記述ができるから、あとは CircleCI に頑張ってもらえば良い。
deployment: feature: branch: /^(?!^master$).+$/ commands: - ./script/staging_deploy.sh
"デプロイ先の heroku app は可変" の対処
これをどのように実現しているかを確認するため、上述ブログで使用されているスクリプトを少し読んでみるとー。
#!/bin/bash -e STAGING_APP_PREFIX="hoge-cms" NUM_OF_STAGING_SERVERS=4 DEPLOY_SCRIPT=/tmp/deploy.$$.sh curl https://quipper-deploy-support-tools.herokuapp.com/scripts/staging_deploy.sh.txt > ${DEPLOY_SCRIPT} . ${DEPLOY_SCRIPT} function prepare_for_staging_server() { heroku addons:add redistogo:nano || : # nothing if it's already installed heroku labs:enable user-env-compile heroku config:add \ FOO=bar \ BAZ=hoge } deploy
ふむ。
https://quipper-deploy-support-tools.herokuapp.com/scripts/staging_deploy.sh.txt の中身も見よう。
HEROKU_APP_NAME=`curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=${STAGING_APP_PREFIX}&branch=${CIRCLE_BRANCH}&servers=${NUM_OF_STAGING_SERVERS}"`
...ん? デプロイ先 heroku app の名前を、どこぞの URL にリクエストすることで生成している?
試してみる。
$ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=test&servers=4" hoge-staging-1% $ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=test&servers=4" hoge-staging-1% $ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=piyo&servers=4" hoge-staging-2% $ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=huga&servers=4" hoge-staging-3% $ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=hoge&servers=4" hoge-staging-4% $ curl https://quipper-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=abc&servers=4" hoge-staging-1%
おおおなるほど。すごい。
今回の用途でこれはちょっとオーバースペックな気もしたけど、便利なことには変わりないので、fork して自分の heroku app にデプロイして使うことにする。
(自分の heroku にデプロイする場合、mamcache の addon が必要 $ heroku addons:add memcachier
。要クレカ登録。)
$ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=hoge&servers=4" hoge-staging-1% $ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=hoge&servers=4" hoge-staging-1% $ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=fuga&servers=4" hoge-staging-2% $ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=piyo&servers=4" hoge-staging-3% $ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=moga&servers=4" hoge-staging-4% $ curl https://shitemil-deploy-support-tools.herokuapp.com/apps --data "app=hoge&branch=poko&servers=4" hoge-staging-1%
おk!
以上を踏まえてやってみる
今回も PR 作ったよ。だいぶ試行錯誤しちゃったけど。
- feature ブランチをデプロイするための shellscript(scirpt/feature_deploy.sh。circle.yml で指定しているもの)を作成
- その shellscript から curl して使用される script も、自分の管理下に配置してそれを用いるように修正
- heroku app 名の生成をするための deploy tool も、自分のものを使うように変更
環境変数の設定も shellscript として書いてやらないといけないのがちょっともにょるけど、production 用のものではないし、目を瞑る。
ただ、今回のアプリケーションの場合 DB のマイグレーションが必要で、最初はそれを prepare_for_staging_server()
の中で書いてやってたんだけど、それが呼ばれるのは git push
の前なので、このままだと「rake がない(bundle install されてないよ)」と怒られてしまう。
なので、git push
の後ろで setup_for_staging_server()
を呼ぶように手を入れ、そこで heroku run rake db:migrate
してやることにした。
prepare_for_staging_server # https://github.com/quipper/deploy-support-tools/pull/5#issuecomment-36588889 [[ ! -s "$(git rev-parse --git-dir)/shallow" ]] || git fetch --unshallow GIT_TRACE=1 git push -f heroku ${CIRCLE_SHA1}:refs/heads/master + setup_for_staging_server notify_all
実際の動き
ここまでできたら、最後に circle.yml に追記をして push。
この push により CI が走り、テストが問題なければ、staging 用途の heroku app が作成され、そこに feature ブランチの内容でデプロイされるはずだ。
CI が走り...
イェイ!ちゃんと staging 用途の heroku app が作成され、そこにデプロイされたね!
このままこの PR をマージすれば、master の CI が走り、テストOKならそのまま本番用の heroku app にデプロイされるはず。マージボタンポチー
グレイツ!!