はい、どうも、マコピーです。最近中学生と言われて気にしておりましたが、本日id:hisaichi5518に「小学生みたい」って言われました。記録更新です。
Kageって
Perl界のロックスターであり最近はポッドキャストなどで話題のmiyagawaさんが書かれたよくわからないモジュールなんですが、これってRubyなんですよね。しかもよく見たらcookpad/kageだし、そういえばmiyagawaさん、cookpadさんにいるんでしたね。
出た時になんか気になってドキュメント見たんですが、"shadow requests"とか書いてあって????ってなってよく分からずに閉じてしまっていたのでした。
その後、こんなツイートをいつぞやにしたんですが、
はぁ〜アプリも継続的デプロイしたいですな〜nginxに入ってきたリクエストを本番とテスト用のアプリサーバ2つに同じ物を投げてユーザには本番のが届くけれどテスト側と本番のレスポンス比較してコケたり変なリクエスト返さないか30分ぐらい監視して自動デプロイ〜みたいな〜
— マコピーさん (@mackee_w) 2013年3月1日
それに@nakashii_さんからリプライが飛んできて、
@nakashii_ そういえばKageがありました! Kage使ってみたい!!!1111
— マコピーさん (@mackee_w) 2013年3月1日
こんな感じでやっとKageの使い方というか正体がわかったんですね。なるほどです。
いろんな使い方があると思うんですが、僕は継続的デプロイの文脈上で使いたくて、僕のやってるソーシャルゲームなんかは、結構な頻度でデプロイする場面っていうのがあるんですね。だからデプロイを安全に、素早くやりたい。安全にというところで自動化という話が出るんですが、まあここはCinnamonなりCapistranoなり、Archerなりでがんばってもらうとして、でもそれでほんとうに安全にいけるの? 自動デプロイだとすぐにコケたりしてヤバくなるとかそんなこと無い? っていう不安があるわけで。
たいていは自動デプロイ掛かる前にテスト通してコケたらそこでデプロイ中止するはずなので大丈夫でしょうが、負荷かけると落ちるとか、本番の負荷とかを掛けないと出てこない問題もあるだろうと。
そこでKageでリクエストをコピーしてデプロイ候補のアプリに投げてレスポンスを見て比較して〜みたいなのが出来たらサイコーですね! っていうことです。
Kageの使い方
使い方といってもただドキュメントを写経してさらに1時間ぐらいしか使っていないわけですが、
例えばこういうRackのサーバがあったとして
require 'rack' class Sample def call(env) [200,{},["Hello, ruby"]] end end run Sample.new
こいつをrackupするわけですけれど、さらにもう一個、plackのサーバを用意する
plackup -e 'sub { [200, [], ["Hello, perl"]] }'
ワンライナー、ウェーイ!
さてruby版はポート9292番、perl版は5000番で立ち上がるわけです。
こいつらの間にKageをはさみます。
require 'kage' def compare(a, b) if a != b p 'Unmatch responses!' p a p b end end Kage::ProxyServer.start do |server| server.port = 8090 server.host = '0.0.0.0' server.debug = false server.client_timeout = 15 server.backend_timeout = 10 server.add_master_backend(:production, 'localhost', 9292) server.add_backend(:sandbox, 'localhost', 5000) server.on_select_backends do |request, headers| if request[:method] = 'GET' [:production, :sandbox] else [:production] end end server.on_munge_headers do |backend, headers| headers['X-Kage-Session'] = self.session_id headers['X-Kage-Sandobox'] = 1 if backend == :sandbox end server.on_backends_finished do |backends, requests, responses| compare(responses[:production][:data], responses[:sandbox][:data]) end end
ドキュメント通りです。ちょっとポート番号とか比較部分変えてますけれど。
これで8090番にアクセスする度にどちらのサーバにも配信されます。master_backendにはruby版を指定しているので常にruby版が返ってきます。
この場合は例えばperl版を「Hello, ruby」にしてもServerヘッダとかそのへんが違うので結局Unmatchになっちゃうんですが、どっちもruby版にすればUnmatch出ません。こんなかんじで次デプロイするやつがおかしくないかとかちゃんと挙動が一緒かとかチェックできるんですね!
素晴らしいですね!!!!
ちなみに今回がんばってRuby書きましたけれど、実はPerl版を@lestrratさんが書いています。
思い立ってKageをPerlで書いてみた : D-7 <altijd in beweging>
こっちは試していませんが、僕はPerlがメインなのでもうちょっと遊びたくなったらこっちも試してみます!
というわけでみなさん、もっと安全に継続的に本番化、してみませんか。
追記
どっちかっていうとこういうの、継続的デリバリーになるんですかね