Railsバージョンアップを
段階的に⾏うために
Rails3/4並⾏稼動させる仕組み
を作ってる話
Rails Upgrade Casual Talks
2016/03/28
@minamijoyo
⾃⼰紹介
•  森⽥ 真之 (Masayuki Morita)
•  Twitter: @minamijoyo
•  GitHub: minamijoyo
•  CrowdWorks Inc.
•  インフラ周りの改善してる
•  最近はRai...
はじめに
•  今⽇お話すること
•  複数Railsバージョンを並⾏稼動させる取り組み
•  なぜ並⾏稼動させるのか
•  開発フロー(ブランチの運⽤)
•  並⾏稼動の仕組み
•  Gemfileの共存
•  リクエストの振分
•  Rai...
CrowdWorks
•  ⽇本最⼤級のクラウドソーシングサービス
•  2012年3⽉〜サービス開始
•  会員数85万⼈、発注クライアント数12万社
CrowdWorksシステム概要
Found
(Elasticsearch)
RDS
(MySQL)
ElastiCache
(memchached)
EC2ELB
•  システム構成はよくあるWebサービス
•  Railsはまだ3.2系が稼...
なぜ並⾏稼動させるのか
•  ひとことで⾔うと⼩さくリリースしていきたい
•  ⼀発バージョンアップはリスキー
•  問題の原因は特定できてもすぐ対応が難しいものもある
•  モンキーパッチしてる箇所など
•  バージョン依存のバグ修正を黙々し...
開発フロー
•  基本⽅針
•  Railsバージョンアップ対応の修正は互換性を保ち
つつどんどんmasterブランチに⼊れていく
•  差分が⼤きくなりすぎるとマージできなくなる
ブランチ運⽤
master
develop
rails4
feature-XXX
rails4-XXX
Production環境
staging環境
Rails3⽤テスト環境
⼀⽇数回マージ
してデプロイ
機能開発/バグ修正
バージョンアップ起...
CIによる⾃動テスト
•  master/develop/rails4ブランチ
•  Rails3/4両⽅でCIによる⾃動テストでクロスビルド
•  トピックブランチ
•  デフォルトRails3でビルド
•  CIのリソース効率化、実⾏時間短...
複数のGemfileを共存させる
•  Gemfileを複数⽤意してBUNDLE_GEMFILE変数で制御
•  Gemfile: Rails3⽤
•  gemfiles/rails4.gemfile: Rails3/4の差分
•  Rails...
gemfiles/rails4.gemfileの例
# Rails3⽤のGemfileを読み込み
eval_gemfile File.expand_path(File.join(File.dirname(__FILE__), '../Gemfi...
BUNDLE_GEMFILEの制御
•  ローカル開発環境は環境変数で切り替えが簡単
•  capistrano
•  現状remote_cacheで各サーバでbundle installしている
•  リモート側の~/.bundle/conf...
リクエストを振り分ける
•  サーバ単位
•  ロードバランサからトラフィックの⼀部を流すだけで簡単
•  問題あればとりあえずバランサから切り離す
•  機能的には全部⼀発リリース
•  ユーザ単位
•  社内ユーザだけ先⾏リリースができる
...
並⾏稼動のシステム構成
•  Rails3/4⽤のサーバ群をそれぞれ⽤意
•  前段にnginxによるリバプロ層を追加しURLで振り分け
Found
(Elasticsearch)
RDS
(MySQL)
ElastiCache
(memcha...
リバプロ層
•  基本はURLパスを⾒てどっちに振り分けるかを判断する
•  完全に10:0じゃなくて9:1とか⽐率はnginxのupstreamコ
ンテキストで調整できる
•  両バージョンで発⽣するかどうかの切り分け
•  Rails3しか...
nginx.confのイメージ
http {
resolver xxx.xxx.xxx.xxx valid=5s;
upstream rails4 {
server unix:/var/run/nginx_rails4.sock weight=...
nginxのtips
•  nginxでupstream先にELBを使う場合はDNS解決に注意
•  nginx起動時のIPアドレスがキャッシュされてしまう
•  serverコンテキストならset変数を使うハックで回避可能
•  upstre...
Rails3/4⽤のサーバ群
•  ELB/EC2/AutoScale/CloudWatch/CodeDeployなど必要な
AWSリソース⼀式をTerraformでモジュール化
•  同じようなサーバ群を簡単に並べて作れるようにする
•  デ...
並⾏稼動の考慮ポイント
•  Rails3.2/4.2を並⾏稼動させる上でのハマりポイントの
具体例
•  リクエスト/レスポンスの互換性
•  ルーティング
•  CSRFトークン
•  アセット
•  flash
•  データの互換性(デー...
リクエスト/レスポンスの互換性
•  ルーティング
•  PUT/PATCH
•  ActionDispatchでPUT/PATCH処理にモンキーパッチ
•  並⾏稼動のためRails3/4でPUT/PATCHを同じ扱いにする
•  CSRFト...
リクエスト/レスポンスの互換性
•  アセット
•  マニフェストの形式が変わった
•  依存ライブラリと結合したjsファイルが同じにならない
•  asset_hostを分けた
•  flash
•  rails_4_session_flas...
データの互換性
•  Cookie
•  cookies_serializerがmarshalからjson形式に
•  並⾏稼動中はmarshalに揃える
データの互換性
•  MySQL
•  明⽰的なシリアライズ
•  プレーンなHashとかなら問題ない
•  Modelとかparamsとかをシリアライズすると型が違って死ぬ
•  暗黙のシリアライズ
•  serialize宣⾔していないte...
データの互換性
•  Memcached
•  単純な数値や⽂字列とかなら問題ない
•  Modelとか突っ込むと(以下略
•  そんなこと良い⼦は普通(ry
•  ダメな⼦はキーを分ける
•  Elasticsearch
•  JSONコーダ...
まとめ
•  なぜ並⾏稼動させるのか
•  ⼩さくリリースしたい
•  開発フロー
•  バージョンアップ対応の修正はmaterに⼊れていく
•  並⾏稼動の仕組み
•  複数のGemfileを共存させてBUNDLE_GEMFILEで制御
• ...
We’re Hiring
•  クラウドワークスでは個⼈の働き⽅を変えたいRailsエン
ジニアを募集中です
•  https://www.wantedly.com/projects/42054
Upcoming SlideShare
Loading in …5
×

Railsバージョンアップを 段階的に行うために Rails3/4並行稼動させる仕組み を作ってる話

723
-1

Published on

Rails Upgrade Casual Talks 2016/03/28
Railsバージョンアップを 段階的に行うために Rails3/4並行稼動させる仕組み を作ってる話

Published in: Engineering
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
723
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
2
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Railsバージョンアップを 段階的に行うために Rails3/4並行稼動させる仕組み を作ってる話

  1. 1. Railsバージョンアップを 段階的に⾏うために Rails3/4並⾏稼動させる仕組み を作ってる話 Rails Upgrade Casual Talks 2016/03/28 @minamijoyo
  2. 2. ⾃⼰紹介 •  森⽥ 真之 (Masayuki Morita) •  Twitter: @minamijoyo •  GitHub: minamijoyo •  CrowdWorks Inc. •  インフラ周りの改善してる •  最近はRails3.2=>4.2アップ デートの検証中
  3. 3. はじめに •  今⽇お話すること •  複数Railsバージョンを並⾏稼動させる取り組み •  なぜ並⾏稼動させるのか •  開発フロー(ブランチの運⽤) •  並⾏稼動の仕組み •  Gemfileの共存 •  リクエストの振分 •  Rails3.2/4.2を並⾏稼動のハマりポイント •  リクエストの互換性、データの互換性 •  もうすぐproduction投⼊するので忘れてそうなのあれば教 えて下さい •  今⽇お話しないこと •  Rails5
  4. 4. CrowdWorks •  ⽇本最⼤級のクラウドソーシングサービス •  2012年3⽉〜サービス開始 •  会員数85万⼈、発注クライアント数12万社
  5. 5. CrowdWorksシステム概要 Found (Elasticsearch) RDS (MySQL) ElastiCache (memchached) EC2ELB •  システム構成はよくあるWebサービス •  Railsはまだ3.2系が稼働している
  6. 6. なぜ並⾏稼動させるのか •  ひとことで⾔うと⼩さくリリースしていきたい •  ⼀発バージョンアップはリスキー •  問題の原因は特定できてもすぐ対応が難しいものもある •  モンキーパッチしてる箇所など •  バージョン依存のバグ修正を黙々してると⾃信をなくす •  ⾃動テストで⾒つけづらいバグもある •  アセットの読み込みに起因する問題、データに起因する問題 •  最終的な確認としてある程度は⽬視で確認したい •  全機能を⼀度に稼働確認するの⼤変 •  アプリケーションとしては業務系システムに近い •  仕事マッチング以外にも細々した機能がたくさんある •  サービス開発を全部⽌めるわけにもいかない •  Railsバージョン上げる度に毎回開発⽌めるの?
  7. 7. 開発フロー •  基本⽅針 •  Railsバージョンアップ対応の修正は互換性を保ち つつどんどんmasterブランチに⼊れていく •  差分が⼤きくなりすぎるとマージできなくなる
  8. 8. ブランチ運⽤ master develop rails4 feature-XXX rails4-XXX Production環境 staging環境 Rails3⽤テスト環境 ⼀⽇数回マージ してデプロイ 機能開発/バグ修正 バージョンアップ起因のバグ修正 rebaseして追いつき マージ Rails4⽤テスト環境 •  master: production環境にデプロイされてるもの •  develop: メインの開発ブランチ •  rails4: Rails4対応⽤の作業ブランチ •  Rails3/4⽤テスト環境をそれぞれ⽤意し、同じリビジョンをデプ ロイして挙動を⽐較できるようにする •  随時developブランチでrebaseして最近の変更も取り込み •  修正の稼働確認できたら適宜developにマージ
  9. 9. CIによる⾃動テスト •  master/develop/rails4ブランチ •  Rails3/4両⽅でCIによる⾃動テストでクロスビルド •  トピックブランチ •  デフォルトRails3でビルド •  CIのリソース効率化、実⾏時間短縮のため •  ブランチ名の⼀部にrails4が含まれるとRails3/4両⽅でビルド •  Rails4対応の修正はマージ前にテストしたい
  10. 10. 複数のGemfileを共存させる •  Gemfileを複数⽤意してBUNDLE_GEMFILE変数で制御 •  Gemfile: Rails3⽤ •  gemfiles/rails4.gemfile: Rails3/4の差分 •  Rails3でしか使わないgemをリストから削除 •  Gitリポジトリをしているものはsourceからも削除 •  Rails4でしか使わないgemをリストに追加
  11. 11. gemfiles/rails4.gemfileの例 # Rails3⽤のGemfileを読み込み eval_gemfile File.expand_path(File.join(File.dirname(__FILE__), '../Gemfile')) # Rails3でしか使わないものをリストから削除 ignored_gems = %w( rails … ) dependencies.delete_if do |g| # Rails 4では:assetsグループは廃⽌される ignored_gems.include?(g.name) || g.groups.include?(:assets) End # git リポジトリを指定しているものはsourceからも削除 ignored_git_source_uris = %w( git://github.com/xxxxx/xxxxx.git ) @sources.git_sources.delete_if do |source| ignored_git_source_uris.include?(source.uri) end # Rails4でしか使わないgemをリストに追加 gem 'rails', '~> 4.2.6’ …
  12. 12. BUNDLE_GEMFILEの制御 •  ローカル開発環境は環境変数で切り替えが簡単 •  capistrano •  現状remote_cacheで各サーバでbundle installしている •  リモート側の~/.bundle/configに設定すればサーバ単位で 切り替え可能 •  whenever •  現状バッチはwhenever経由でcrontabを⽣成している •  job_templateでcronジョブごとにBUNDLE_GEMFILEの exportを出し分けする
  13. 13. リクエストを振り分ける •  サーバ単位 •  ロードバランサからトラフィックの⼀部を流すだけで簡単 •  問題あればとりあえずバランサから切り離す •  機能的には全部⼀発リリース •  ユーザ単位 •  社内ユーザだけ先⾏リリースができる •  現状振り分ける仕組みがないので何がしか作りこみが必要 •  問題あっても影響は⼀部ユーザに限定される •  機能的には全部⼀発リリース •  URL単位(機能単位)=>これを採⽤ •  稼働確認できた機能から段階的に新バージョンに振り分ける •  現状振り分ける仕組みがないので何らか作りこみが必要 •  機能ごとにちょっとずつテストしてリリースできる •  問題あっても機能ごとに切り戻しできる •  今後も同じような段階リリースしていくのに便利そう
  14. 14. 並⾏稼動のシステム構成 •  Rails3/4⽤のサーバ群をそれぞれ⽤意 •  前段にnginxによるリバプロ層を追加しURLで振り分け Found (Elasticsearch) RDS (MySQL) ElastiCache (memchached) EC2 ELB EC2 ELB ELB EC2 (nginx) Rails3 Rails4
  15. 15. リバプロ層 •  基本はURLパスを⾒てどっちに振り分けるかを判断する •  完全に10:0じゃなくて9:1とか⽐率はnginxのupstreamコ ンテキストで調整できる •  両バージョンで発⽣するかどうかの切り分け •  Rails3しか発⽣しない潜在的な問題があると切り戻しリスク
  16. 16. nginx.confのイメージ http { resolver xxx.xxx.xxx.xxx valid=5s; upstream rails4 { server unix:/var/run/nginx_rails4.sock weight=9 fail_timeout=60; server unix:/var/run/nginx_rails3.sock weight=1; } upstream rails3 { server unix:/var/run/nginx_rails3.sock; } server { listen xxxx; server_name example.com; ... location / { proxy_pass http://rails3; } location ^~ /hoge/ { proxy_pass http://rails4; } server { listen unix:/var/run/nginx_rails3.sock; set $elb_rails3 "xxxx"; ... location / { proxy_pass http://$elb_rails3:80; } server { listen unix:/var/run/nginx_rails4.sock; ... } }
  17. 17. nginxのtips •  nginxでupstream先にELBを使う場合はDNS解決に注意 •  nginx起動時のIPアドレスがキャッシュされてしまう •  serverコンテキストならset変数を使うハックで回避可能 •  upstreamコンテキストではresolveオプションは有償 •  upstreamコンテキストで必要な負荷分散しつつ、Unixドメイ ンソケットを1段挟んで、serverコンテキストでDNS解決すれ ば無償の範囲でも可能 •  (参考)nginxのupstreamコンテキストで有償のresolveオプション を使わずに動的にDNS解決する •  http://qiita.com/minamijoyo/items/183e51a28a3a9d79182f •  デバッグ⽤にカスタムHTTPヘッダを⾒てRails3/4を指定し て振り分けるようにしておくと便利 •  (参考)nginxでカスタムHTTPヘッダを⾒てproxy_passを振り分け る •  http://qiita.com/minamijoyo/items/3705ad7c9df70e87a953
  18. 18. Rails3/4⽤のサーバ群 •  ELB/EC2/AutoScale/CloudWatch/CodeDeployなど必要な AWSリソース⼀式をTerraformでモジュール化 •  同じようなサーバ群を簡単に並べて作れるようにする •  デプロイ⾃動化している箇所の修正とかも必要なので忘れず •  ホスト名の⼀部にRailsバージョン⼊れるとログが区別しやすい •  サーバを作って壊せる環境なら雑なネーミングが可能 •  パフォーマンス情報の収集 •  ActiveSupport::Notificationsで process_action.action_controllerのイベントをフックしてアク ションごとの実⾏時間などを取得 •  Railsバージョンのタグを付けてDatadogに送りつけておく •  トラフィック流して⼤幅に劣化してそうだったら、がんば る。。。
  19. 19. 並⾏稼動の考慮ポイント •  Rails3.2/4.2を並⾏稼動させる上でのハマりポイントの 具体例 •  リクエスト/レスポンスの互換性 •  ルーティング •  CSRFトークン •  アセット •  flash •  データの互換性(データが保存される場所ごとに考える) •  Cookie •  MySQL •  memcached •  Elasticsearch •  データの互換性は、並⾏稼動しなくても⼀発リリース失 敗で旧戻しする場合は考慮が必要 •  キャッシュ系は最悪は再⽣成できるけどDBだけはヤバイ
  20. 20. リクエスト/レスポンスの互換性 •  ルーティング •  PUT/PATCH •  ActionDispatchでPUT/PATCH処理にモンキーパッチ •  並⾏稼動のためRails3/4でPUT/PATCHを同じ扱いにする •  CSRFトークン •  Rails4.2で⽣成ロジックが変更されている •  breach-mitigation-railsをRails3側に⼊れると同じになる
  21. 21. リクエスト/レスポンスの互換性 •  アセット •  マニフェストの形式が変わった •  依存ライブラリと結合したjsファイルが同じにならない •  asset_hostを分けた •  flash •  rails_4_session_flash_backport •  移⾏⽤gemがあるんで⼤丈夫と思ってた時代が私にもありました •  Rails3.2=>4.2で使うと微妙に実装が変わってる?(確認中) •  移⾏系のgemはバージョン離れると注意
  22. 22. データの互換性 •  Cookie •  cookies_serializerがmarshalからjson形式に •  並⾏稼動中はmarshalに揃える
  23. 23. データの互換性 •  MySQL •  明⽰的なシリアライズ •  プレーンなHashとかなら問題ない •  Modelとかparamsとかをシリアライズすると型が違って死ぬ •  暗黙のシリアライズ •  serialize宣⾔していないtextカラムにHashを突っ込むとYAML だったのがJSONになってる •  そんなこと良い⼦は普通しないよね?油断してるとある •  delayed_job •  Modelをシリアライズするので型が違って死ぬ •  キュー名で分ける=>LIKE検索の負荷が重くて死ぬ •  delayed_jobにカラムを追加する •  時刻の精度 •  MySQL5.6 + Rails4.2で時刻がマイクロ秒精度に •  秒精度に統⼀
  24. 24. データの互換性 •  Memcached •  単純な数値や⽂字列とかなら問題ない •  Modelとか突っ込むと(以下略 •  そんなこと良い⼦は普通(ry •  ダメな⼦はキーを分ける •  Elasticsearch •  JSONコーダの実装が変わってる •  インデックスすると時刻がミリ秒精度に •  秒精度に統⼀ •  ActiveSupport::JSON::Encoding.time_precision = 0 •  JSON.dump(Time.now)した結果の時刻フォーマットが違う •  Ojとか別にJSONコーダを使う
  25. 25. まとめ •  なぜ並⾏稼動させるのか •  ⼩さくリリースしたい •  開発フロー •  バージョンアップ対応の修正はmaterに⼊れていく •  並⾏稼動の仕組み •  複数のGemfileを共存させてBUNDLE_GEMFILEで制御 •  URLパスベースでリクエストを振り分ける •  Rails3.2/4.2を並⾏稼動のハマりポイント •  並⾏稼動させる上でリクエストとデータの互換性は⼤事 •  特にデータは並⾏稼動しなくても旧戻しのために⼤事 •  並⾏稼動させるのに考えることいろいろあって⼤変 •  でも仕組みができれば継続的にバージョンアップしていける •  もうすぐproduction投⼊するので忘れてそうなことあれば教え て下さい
  26. 26. We’re Hiring •  クラウドワークスでは個⼈の働き⽅を変えたいRailsエン ジニアを募集中です •  https://www.wantedly.com/projects/42054

×