Post on 02-Aug-2020
Docker時代の
分散RSpec環境の作り方@joker1007
self.inspect@joker1007
Repro inc. CTO (要は色々やる人)
Ruby/Rails
�uentd/embulk
Docker/ECS ← 今日はこの辺
Bigquery/EMR/Hive/Presto
Reproのサービスモバイルアプリケーションの行動トラッキング
分析結果の提供と、それと連動したマーケティングの提供
大体Ruby・RailsでほぼAWS上で稼動している
Dockerやterraform等も活用している
会社規模の割にデータ量が多い。
フレンズ(エンジニア)を募集中です
Railsがとくいなフレンズ
Hadoopがとくいなフレンズ
JavaScriptがとくいなフレンズ
等々、様々なフレンズを募集しております
なんちゃらRuby会議歴東京Ruby会議スピーカー
関西Ruby会議スピーカー x2 (+CFP応募)
TokyuRuby会議 LT王
RubyKaigi日本酒スーパーバイザー
東京Ruby会議日本酒仕入れ
RubyKaigi LT x3
名古屋Ruby会議スピーカー
大江戸Ruby会議Ninja (NEW!!)
本題へ
皆さんCI回してますか?
Docker使ってますか?
この2つに該当する人なら、
明日からでもRSpecを分散実行し
高速化できます(いや、もうちょいかかるかも)
RailsアプリケーションのCIにおける障壁
独立したDBの準備
テスト毎にクリーンな環境
関連ミドルウェアの準備
マルチコアを使えない
parallel_test ? 中々辛いですね……。
Docker(コンテナ)と相性が良い
コンテナ化のメリットアプリケーション起動環境の再現性
一時利用のミドルウェアを簡単に用意できる
mysql, postgresql
redis
elasticsearch
�uentd
複数プロセスでテスト範囲を分割しても、環境の独立性が確保できる
コンテナでテストを実行できると、起動した時点で全てのミドルウェアが揃っている
しかもそれぞれが独立している
つまり
spec_helperで子プロセスを起動
とかやらなくていい!
Railsコンテナ化Tipsproductiontとテストの共用は止めた方がいい
起動時に実行するprehookを用意する
環境変数を元にcon�gを切り替える
本番環境での秘匿情報の取得・複合化等を行う
シグナルハンドルに気を付けること
子プロセスまでシグナルが届かないと操作できない
shellを噛ます場合はexecすること
ビルドサーバーはあった方が良い
RSpec分散実行に必要なもの実行のキューイング
ポーリングするワーカー
テストレポートの収集と統合
レポートの表示
これらはほとんど
作る必要は無い
Amazon ECSの活用ECSはEC2インスタンスをバックエンドにしたコンテナ管理サービス複数のコンテナをセットにして1ノードで起動できる。各コンテナが利用するリソースの量を定義でき、空いているインスタンスを自動的に検索してそこでコンテナを起動できる。
つまりAPIを叩くだけで、必要なノードで勝手にタスクを実行して終わったら空けるということが簡単に実現できる。
GKEやkubernetes、docker-swarm等でも可
CIサービスの部分的活用PullReqのフック受信
JUnitフォーマットの結果表示
テストレポートの格納先俺達にはS3(GCS)がある
作る必要があったものRSpecのレポートをS3にストアするもの
rspecの実行コマンドを渡すとECSのAPIに変換して実行してくれるもの
作ったrspec-storage
wrapbox
rspec-storage-oオプションを拡張して任意のストレージに出力できる用にした。
$ rspec -r rspec/storage spec/example_spec.rb \ -f doc \ -f json -o s3://your-bucket/spec_result.json
URIのスキーマと表現により、アダプターを書けば何にでも出力できる。(rspec-coreの実装が行儀悪いので一部モンキーパッチが……)
wrapboxコマンドを渡すとECSのAPIリクエストを構築して、よしなにコンテナを起動してくれるヘルパー。
default: cluster: ecsr-test runner: ecs region: ap-northeast-1 container_definition: image: joker1007/wrapbox cpu: 512 memory: 1024 essential: true
$ wrapbox ecs run_cmd -f config.yml -e RAILS_ENV=test \ "bundle exec rspec spec/models"
二つの簡単なgemを組み合わせる
1. specファイルを適当に分割してwrapboxに投げれば、勝手にECSがコンテナをEC2上で分散実行してくれる。
2. wrapboxで実行したRSpecの出力はrspec-storageによってS3に収集される。
3. 終了した後でjsonを収集してjunit format形式に変換すれば良い。
簡単!しかもメンテフリー!
コンテナでテストを行うメリット
リソースが抽象化される
ノード毎のマシンスペックを気にしなくてよい
テスト実行に必要なリソースを1ユニットとして、一つのノード内に共存できる
スポットインスタンスと相性が良い
特にスポットフリート
スポットフリート複数のインスタンスタイプに対して、まとめてスポットインスタンスのリクエストを出せる。リソースの割合を決めておけば、複数のインスタンスタイプの中で必要なリソースに対して最も安いインスタンスを利用できる。
m4.large (weight 1): $0.03/1 = 0.03
c4.large (weight 1): $0.025/1 = 0.025
c4.xlarge (weight: 2): $0.04/2 = 0.02 ←Use
もし必要なユニット数が8ならc4.xlargeが4台起動c4.xlargeが高騰したら自動で変動する
スポットフリート (続き)価格が高騰しても、別のインスタンスタイプからノードを起動して自動的に補充されるので計算リソースを確保できる。
AutoScaleと大きく異なるのは複数のインスタンスタイプを組み合わせて自動的に調節してくれる点。
スポットフリートでECSのクラスタを構成する
常にスポットインスタンスの低価格を利用して、一定の並列度でテスト実行できるクラスタが手に入る。複数のインスタンスタイプを組み合わせて、性能は余り変わらないし並列度の調節もコンテナのリソース定義で自動的に行われる。
APIでリソース数を調節できるので、夜間だけ減らす、とかも割と簡単。
コスト削減とテスト時間の短縮に成功元々はCircleCIだったが、
並列度を3倍ぐらいまで上げて、
テスト実行時間を短縮
しかも、コストは月100$以上も安くなった
コンテナ化のメリットは環境再現性だけではない
独立したミドルウェア環境
ミドルウェアや言語処理系のバージョン管理
計算リソースの抽象化
コンテナ化するにはある程度の手間と苦労が必要だが、やる価値はある。
Let's containerize your app!!
まずはテストから