最近CIサーバーを自前Jenkinsから CircleCI に移した。CircleCIとても便利で簡単なのでオススメ。
CircleCIには普通のheroku deployは内蔵されているのだけど、 非開発者もGitHub Flowに巻き込んでみんなハッピーになった話 、をやるにはちょっと工夫が必要。
色々書こうと思ったけど、めんどくさくなったのでscriptを晒しておくだけにしよう!
この中で使われているスクリプト関連、特に秘密にする部分もないのでpublicでgithubに置いている。 https://github.com/quipper/deploy-support-tools
/circleci.yml
deployment:
feature:
branch: /^(?!^master$).+$/
commands:
- ./script/staging_deploy.sh
production:
branch: master
commands:
- ./script/production_deploy.sh
/script/staging_deploy.sh
#!/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
/script/production_deploy.sh (これは普通にdeployするだけのscript)
#!/bin/bash -e
HEROKU_APPS="<heroku app name1> <heroku app name2>"
DEPLOY_SCRIPT=/tmp/deploy.$$.sh
curl https://quipper-deploy-support-tools.herokuapp.com/scripts/production_deploy.sh.txt > ${DEPLOY_SCRIPT}
. ${DEPLOY_SCRIPT}
deploy
上のスクリプト、CircleCIのheroku deployの仕組みは使っていないので、HerokuのSSH keysの登録と、 上記スクリプトから参照される HEROKU_API_TOKEN
と HEROKU_USER
を、CirclCIのEnvironment variablesに設定する必要ある。
前提: GitHub flow を使っていてCIサーバーはJenkins
最近ちょっと開発フローの改善をして、とてもよく機能してて満足しているので紹介してみる。
この改善をやる前の悩み:
- pull-requestでコードレビューはできるのだけど、cssとかjavascriptなどの見た目や動作の変更ってコードだけだとわかりにくい。レビューする人が各自ローカル環境で実行するのもだるい。
- コードを読まないデザイナーとかプロダクトオーナーとかの人が、pull-requestのレビュープロセスに簡単に参加できない(非開発者全員のところでローカル環境設定するのはだるすぎる)。
- コード的にokに見えてmasterにmerge後、何か問題(特に仕様的な問題や、デザイン的な問題)が発生した場合、「修正branchを作ってpull-request」というフローを再度回さないといけない。最初のpull-requestで非開発者の人を巻き込めたらそこで気付けるのに。
これらの問題を解決するのに、feature branchもHerokuにJenkinsから自動的にデプロイするようにしたら色々幸せになれた。
具体的には、N個(N=アクティブな開発者の数くらいが良さそう)のfeature branchのテスト用のHeroku appを予め作っておいて、feature branchにpushされるたびに、Jenkinsからその中の一つへデプロイされる感じにした。
補足:
- 同じfeature branchの新しいpushがなるべく同じHeroku appにデプロイされ続けるようにとか、heroku configもするとか、多少工夫してる。
- 初期の頃、feature branch毎にJenkinsから毎回heroku createしてたが、それはさすがに怒られそうなので、複数をローテーションで使うようにした。
- いまどき?だとJenkinsで動的に仮想環境とか作っちゃうのもありだと思う。でも、Herokuが楽過ぎて頑張って仮想環境作る必要もないかな、というのが現在の弊社の状況。
非開発者にもレビューして欲しいときは、pull-request上でmentionして、heroku上のデプロイされたものを見てもらう感じ。基本的にUIに変更のあるようなものは非開発者もチームほぼ全員見るようにしている。
数ヶ月運用してるけど、もうこれなしでは生きるのが辛い感じにまでなってきてる。
非開発者の人もとても楽になった感じで、それまでは、色々な変更が入った(または肝心なものがコミュニケーションの問題で入っていない)masterブランチが動作しているのを見るしかなく「何が」実際変更されたのかわかりづらかったが、このフローにしてから、変更点がわかりやすく開発者とのコミュニケーションもだいぶ楽になった。また、チームメンバーの誰かが「思ってもみなかった」変更がいきなり入ってしまうということもなく、だいぶストレスが減った感じ。
また、開発者も、それまでは、merge後、非開発者に指摘されると「めんどくせーなー」という意識が生まれがちで、かつ、その場合mergeから時間が経っていることも多く、その変更に対するフレッシュさが減り、再度作業を始めるまでの心理的な負担(実際、実装を思い出すための脳のコストも高そう)も高かった。それが、pull-request中に非開発者からフィードバックが貰えることで、そのpull-requestにcommitを追加することだけでさくっと修正できて、全体のスピード感がとてもあがったし、開発者の負担も減った。
つまり、pull-requestのmergedがチームメンバー全員にとってのDONEというステータスになり「実装終わったけどまだ本番には入っていない」とか「チームメンバーが納得してないものが本番に入っちゃった」みたいな事故/ストレスを減らせた。Done means DONE!
これらの結果、masterにmerge後、Jenkinsからの自動デプロイもかなり安心してできるようになった。
おまけ:
@hsbtさんが いい感じのGitHub flowベースのワークフローをあげていたので、弊社(Quipper)との差分を書いてみる。
- masterブランチは常にデプロイ可能な状態でかつ自動デプロイされている。
- なので、手でデプロイという作業は発生しない。
- WIPのpull-requestはそれほど推奨してない。この辺はpull-requestの粒度の話もあるので別エントリで書きたい感じ。
- 関連して、チェックリストみたいのも基本作らない(必要ない)。
- mergeはレビューした人が行う。
- コードレビュー以外のテストも上に書いたように、feature branchでしてしまう。
- インフラメンバーいない。(が、そろそろ欲しい! 興味ある人ご一報を)。
- Release’s notes 作成してない。
フローの中でGithub(とJenkins)の外へ出たくない、という方針。
この辺りって、絶対的に正しい方法というのはなく、組織のサイズとかサービスの規模に応じて、ダイナミックに変えていくのが正しい道だと思っている。
前から気になっていた Heroku + MongoHQ を試してみた。HerokuはRubyアプリケーションを走らせるホスティングサービスで、MongoHQはMongoDBのホスティングサービスだ。この二つを組み合わせることで、MongoDBを使ったRubyアプリケーションを一瞬で運用開始することができる。
あまりにも簡単に使えてあまり書くこともないんだけどメモ。
まず、両方とも最低限の環境は無料で使用できる(ただしHerokuからMongoHQを使うためにはクレジットカードの登録は必要っぽい)。
今回は Ruby on Rails 3 + Mongoid で作ったアプリを置いてみた。
手順
1. まず、普通に RoR + Mongoid のアプリケーションを作る
2. Herokuにアカウントを作りアプリケーションを登録する (http://docs.heroku.com/quickstart )
3. HerokuでMongoHQを有効にする (http://docs.heroku.com/mongohq )
$ heroku addons:add mongohq:free
4. Mongoidの接続情報であるconfig/mongoid.ymlのproduction環境のところを以下のように書き換える。
production:
uri: <%= ENV['MONGOHQ_URL'] %>
追記: もしくは、 config/initializers/mongohq.rb のようなファイルを作り、 そこで指定する。
if ENV['MONGOHQ_URL']
# For Heroku (See: http://docs.heroku.com/mongohq)
Mongoid::Config.instance.from_hash({"uri"=> ENV['MONGOHQ_URL']})
end
5. 普通にHerokuへdeployする (具体的には、gitでHerokuにpushする)
これだけで、MongoHQのMongoDBを使うようになる。超簡単。
(ちなみに、ここ最近、RubyとMongoDB間のORMはMongoidしか使っていない。一時期、 MongoMapper を使っていたのだけど、Mongoid の使いやすさに負けた。機能的には大きく変わらないのだけど、ちょっとした細かいところとか、センスの良さが全然違う。)
気付いたところ
1. Heroku経由でMongoHQを使うとMongoHQにログインできない?
MongoHQにも管理画面的なのがあるっぽいのでこれはちょっと嫌だ。(何か方法ありそうだが)
2. ここ にあるように、MongoDBの接続情報を取得し、自分の環境からHerokuを通さずに直接接続も可能。
バックアップもmongodumpコマンドで普通に取れるし、 Mongoシェル でアクセスするのも問題ない。これは便利。
ただ、便利なのだけど、つまりMongoHQのMongoDBは全世界から接続可能なので、接続情報や、ID/パスワードの管理は慎重にする必要があるのがちょっと厳しい。例えば、Rubyアプリ側では、 ENV[“MONGOHQ_URL”] にID/パスワード含む接続情報がすべて入っているので、デバッグ目的などでENVを間違えて表示しちゃったりすると大惨事になりそう(これはHerokuのMySQLとかPostgreSQLとかも同じっぽいが)。
3. HerokuからMongoHQまでのlatencyは一桁ミリ秒だった。
なんとなく不安だったのだけど問題なさそう。
まとめ
RoRとMongoDB(Mongoid)のスキーマレスでの素早い開発と、簡単にデプロイできるHeroku+MongoHQの相性がとてもよい。ちょっとしたアプリケーションを作ったり、プロトタイプを作って色々な人に見せたい場合にとても向いていると感じた。もちろん、アクセス数やデータベース容量にあわせて、Heroku/MongoHQともに有料コースに切り替えて本番環境として使い続けるのも問題ないだろう。
また、「Heroku+MongoHQで動かす」と言っても、アプリケーション自体はもちろん普通のRuby(Rails)とMongoDBなので、Heroku/MongoHQが嫌になったら、他へ移ることも、自分で運用するのにも何の問題もない。「とりあえず作ってHeroku+MongoHQで動かしてある程度軌道に乗ったところ次を考える」というのが可能だ。これはかなり魅力的(今、世の中はロックインが流行ってるようだし!)。