96
あなたの安心を高速に守る Container-based CI 宮國 渡 (@gongoZ) 2015-4-18

あなたの安心を高速に守る Container-based CI

Embed Size (px)

Citation preview

Page 1: あなたの安心を高速に守る Container-based CI

あなたの安心を高速に守る

Container-based CI

宮國 渡 (@gongoZ)

2015-4-18

Page 2: あなたの安心を高速に守る Container-based CI

Agenda

� 背景 (過去にあった問題解決の話)

� 新たなる問題

� 振り返らない高速化が生んだ弊害

� 高速と安定の join

� まとめ

Page 3: あなたの安心を高速に守る Container-based CI

自己紹介

社会人

� 宮國 渡 (MIYAGUNI Wataru)

� 株式会社OCC

� PHP な Web アプリケーション開発・運用保守

� ↑ これにまつわる話します

プライベート

� github.com/gongo

� Just Do Eat

Page 4: あなたの安心を高速に守る Container-based CI

自己紹介

社会人

� 宮國 渡 (MIYAGUNI Wataru)

� 株式会社OCC

� PHP な Web アプリケーション開発・運用保守

� ↑ これにまつわる話します

プライベート

� github.com/gongo

� Just Do Eat

Page 5: あなたの安心を高速に守る Container-based CI

プロローグ(長いです)

Page 6: あなたの安心を高速に守る Container-based CI

Long long ago..

PHP 3, 4, 5 の時代を渡り歩いてきた、とある Web アプリケーションが居ました

� PHP がテンプレートエンジンであった頃

� HTML にビジネスロジックを書き始めた頃

� PHP がアクセス修飾子の無いオブジェクト指向を取り入れた頃

� 各人から生まれる複数のオレオレフレームワーク

�全部混ざってる!

�何よりテストが無い!

Page 7: あなたの安心を高速に守る Container-based CI

Long long ago..

PHP 3, 4, 5 の時代を渡り歩いてきた、とある Web アプリケーションが居ました

� PHP がテンプレートエンジンであった頃

� HTML にビジネスロジックを書き始めた頃

� PHP がアクセス修飾子の無いオブジェクト指向を取り入れた頃

� 各人から生まれる複数のオレオレフレームワーク

�全部混ざってる!

�何よりテストが無い!

Page 8: あなたの安心を高速に守る Container-based CI

Long long ago..

PHP 3, 4, 5 の時代を渡り歩いてきた、とある Web アプリケーションが居ました

� PHP がテンプレートエンジンであった頃

� HTML にビジネスロジックを書き始めた頃

� PHP がアクセス修飾子の無いオブジェクト指向を取り入れた頃

� 各人から生まれる複数のオレオレフレームワーク

�全部混ざってる!

�何よりテストが無い!

Page 9: あなたの安心を高速に守る Container-based CI

現代の PHP (Versions)

version initial release EOL

5.4 2012/03/01 2015/09/14

5.5 2013/06/20 2016/06/20

5.6 2014/08/28 2017/08/28

(new! →) 7.0 2015/11/xx

via PHP: Supported Versions

Page 10: あなたの安心を高速に守る Container-based CI

現代の PHP (周辺)

� PHP-FIG — PHP Framework Interop Group� PSR-FIG なるコミュニティが策定する規約� PSR-0 —Autoloading Standard� PSR-2 —Coding Style Guide� PSR-3 —Logger Interface など

� Composer� パッケージ依存管理ツール (Ruby でいう Bundler)

� Packagist� Composer リポジトリ (Ruby でいう RubyGems)

Page 11: あなたの安心を高速に守る Container-based CI

やりたいことは

� 例: PHP 5.5 に上げたい

� 例: もうメンテされてないライブラリから移行したい

� 例: リファクタしたい

Page 12: あなたの安心を高速に守る Container-based CI

でも今の僕たちの装備じゃ

現代への 快適でスムーズな移動 のクリア難しい

Page 13: あなたの安心を高速に守る Container-based CI

装備 = 自動テスト

「これまで」

� テスト仕様書 (Excel) を見ながら手動テスト

� 新機能開発であれば手動テストでも良い

� 自動テストの主流である回帰テストはあくまで 回帰

� 新規のバグは発見できない。経験と勘が必要

「これから」

� 中身が変わっても外側が変わらないことを保証したい

� 古いライブラリからの引越しのたびに全手動テスト?

� PHP バージョンアップのたびに全手動テスト?

Page 14: あなたの安心を高速に守る Container-based CI

まずは装備を整える

手動人海戦術はプラン B

via http://migo0110.blog.jp/archives/7187299.html

安心に満たされた穏かな日々を過ごすため

テストの自動化を目指してみることに

Page 15: あなたの安心を高速に守る Container-based CI

前提条件

Resource

� 仕様書はない (ERD 含む)

� 手動テストで使っていた Excel ならある

Policy

� 仕様/UI の変更は無い想定とする

Page 16: あなたの安心を高速に守る Container-based CI

Unit Test ?

テスト書き辛さ問題

� クラスベースなコードの方が少ない

� グローバル関数、グローバル変数が主流

� そもそも <html> の中にビジネスロジックが…

古い PHP に縛られる

� 綺麗に書けなくてイライラ 問題

� trait 使いたいし array(’a’) を [’a’] って書きたい

� バージョンアップに影響をうける

� 本体コード、テストコード両方同時に手を…?

Page 17: あなたの安心を高速に守る Container-based CI

End-to-End test ?

ブラウザ操作してその結果 (画面)をチェック系

� Excel から、ある程度機械的にテストケース作成可能

テストコードが サーバーサイドに依存しない

� 将来的にも使い続けていける可能性が高い

PHP に拘らずに 書ける

� バージョンを気にするのは本体のコードだけ

� テスト環境は現代のツールを導入できる

Page 18: あなたの安心を高速に守る Container-based CI

というわけで

現状の仕様を保ちつつ サーバーサイドの

現代化を行うにはEnd-to-end テストの自

動化が最適と判断

Page 19: あなたの安心を高速に守る Container-based CI

Environment ofintegration testing

簡潔に書けそうな Ruby 製を選択

� ブラウザの操作

� Selenium - Web Browser Automation

� Selenium Ruby binding� RubyBindings - selenium

� Selenium Ruby binding のラッパー� jnicklas/capybara

� Ruby テストフレームワーク� RSpec: Behaviour Driven Development for Ruby

Page 20: あなたの安心を高速に守る Container-based CI

Example (Capybara)

Page 21: あなたの安心を高速に守る Container-based CI

構成(個人バージョン)

Page 22: あなたの安心を高速に守る Container-based CI

Next stage after testautomation

テスト実行するのに疲れてしまう (人間だもの)

Page 23: あなたの安心を高速に守る Container-based CI

続けなければ意味がない

自動テストも手動で実行し続けるのはつらい

� たかが「ポチッ」されど「ポチッ」

つらくなるとテストしなくなる

� 「これぐらいの修正なら大丈夫だろう」

自動テストも動かなければただのテキスト

� 動かさないテストは無いほうが良い (メンテ含む)

Page 24: あなたの安心を高速に守る Container-based CI

僕たちがやりたかったのは

テストを実行することなの?

Page 25: あなたの安心を高速に守る Container-based CI

僕たちの力は

テストを動かすためではなく

価値を生み出すため に使うべき

Page 26: あなたの安心を高速に守る Container-based CI

価値を生み出す力を

継続して支えるためには

(機械的な)新たな仕組みを入れるべき

Page 27: あなたの安心を高速に守る Container-based CI

Continuous Integration

継続したいことは

� コードが commit (push) される度にテスト走るとか

� 深夜に、その日 commit されたコードでテストとか

� 他にもいろいろ定型的な作業とか

via Jenkins CI

Page 28: あなたの安心を高速に守る Container-based CI

構成 -Prologue version-

Page 29: あなたの安心を高速に守る Container-based CI

構成 -Prologue version-

Page 30: あなたの安心を高速に守る Container-based CI

構成 -Prologue version-

Page 31: あなたの安心を高速に守る Container-based CI

構成 -Prologue version-

Page 32: あなたの安心を高速に守る Container-based CI

構成 -Prologue version-

Page 33: あなたの安心を高速に守る Container-based CI

構成を組んだあとは

以下のことが実現

� 深夜に 1回、全 Integration test を実行� 前日に master branch にマージされたコードに対して

� 朝、出勤してテストが通ったかどうかチェックできる

� テスト失敗した瞬間のスクショをまとめたレポート

隙があまり生じぬ二段構え

� 「定時内の開発 and レビュー and テスト」

� 「深夜に全テスト」

コアな部分の修正にも安心感が増した

Page 34: あなたの安心を高速に守る Container-based CI

プロローグ

Page 35: あなたの安心を高速に守る Container-based CI

本編

Page 36: あなたの安心を高速に守る Container-based CI

テストを書いて

コードを書いて

を繰り返していたある日

Page 37: あなたの安心を高速に守る Container-based CI
Page 38: あなたの安心を高速に守る Container-based CI
Page 39: あなたの安心を高速に守る Container-based CI

速さが足りない!

テストに

1時間半も掛かってる!!

Page 40: あなたの安心を高速に守る Container-based CI

What happened?

テストケースの増大

� テストケースが 600 越えてきた

� 1テストケース 10秒で終わるものもあれば 1分かかるものもある

� ログインして 3画面ぐらい遷移してフォーム入力して…

テストが遅いこと自体は問題ない

 

Page 41: あなたの安心を高速に守る Container-based CI

What happened?

テストケースの増大

� テストケースが 600 越えてきた

� 1テストケース 10秒で終わるものもあれば 1分かかるものもある

� ログインして 3画面ぐらい遷移してフォーム入力して…

テストが遅いこと自体は問題ない

テストが実行されていれば

Page 42: あなたの安心を高速に守る Container-based CI

遅いフルテストの

真の弊害

テスト実行するのに疲れてしまう (みんな人間だもの)

Page 43: あなたの安心を高速に守る Container-based CI

CI に任せてるから大丈夫だよね?

深夜に 1回走らせてはいるけど

1時間半も掛かるテストを定時前に走らせるとか無理

Page 44: あなたの安心を高速に守る Container-based CI

僕たちは安心を求めていた

� フルテストによってそれを担保していたはずだった

� フルテストが億劫になると

� 最小限のテストだけ走らせるようになる

� 見ないふりし始める ( まあ大丈夫だろ 問題)� 深夜のテスト実行まで待てないし手元で動かすのもめ

んどくさい。リリースが大事だろ ( 任務遂行絶対 問題)

� その結果

� エンバグ、デグレード多発

� その他いろいろな事故リスク増大

「これでは駄目だ」

僕たちは安心を取り戻すために高速化を開始した

Page 45: あなたの安心を高速に守る Container-based CI

まず最初に思いついたのは高速化と言えば並列実行

Page 46: あなたの安心を高速に守る Container-based CI

並列実行 (RSpec)

現状

� Test runner である RSpec を並列実行したい

� 参考: The Ruby Toolbox - Distributed Testing

今回は test-queue を採用

� GitHub 本体のテストにも使われているライブラリ

� 既存 (RSpec)の環境をほぼそのまま使える� 実行コマンドが rspec-queue に変わるだけ

� 暇なプロセスを作らず、テストをいい感じに分配

Page 47: あなたの安心を高速に守る Container-based CI

実行例

$ bundle exec rspec-queue spec/

※ 数値はてきとうです

Page 48: あなたの安心を高速に守る Container-based CI

並列実行 (Browser)

Page 49: あなたの安心を高速に守る Container-based CI

\ Selenium Grid /

See: Grid2 SeleniumHQ/selenium Wiki

Page 50: あなたの安心を高速に守る Container-based CI

Selenium Grid

Page 51: あなたの安心を高速に守る Container-based CI

Selenium Grid

Page 52: あなたの安心を高速に守る Container-based CI

Selenium Grid

Page 53: あなたの安心を高速に守る Container-based CI

Selenium Grid

Page 54: あなたの安心を高速に守る Container-based CI

構成 -test-queue +selenium grid-

Page 55: あなたの安心を高速に守る Container-based CI

構成 -test-queue +selenium grid-

Page 56: あなたの安心を高速に守る Container-based CI

3 プロセスで実行したら3倍の早さで終わった

10 プロセスで実行したら8倍ぐらい早く終わった

Page 57: あなたの安心を高速に守る Container-based CI

ぼくたちは

速さを手に入れた

Page 58: あなたの安心を高速に守る Container-based CI

その代わりに

失なったものがある

Page 59: あなたの安心を高速に守る Container-based CI

安定しなくなった

Page 60: あなたの安心を高速に守る Container-based CI

いろいろ原因はあったが

主な原因は、(テストデータの入った)DB の同一テーブルを閲覧・変更・削除するテストケースが複数あり、それらが

同時に実行されていたため

Application Server と書いてたが実は全部入っていたのさ

Page 61: あなたの安心を高速に守る Container-based CI

主な失敗パターン

Page 62: あなたの安心を高速に守る Container-based CI

主な失敗パターン

Page 63: あなたの安心を高速に守る Container-based CI

主な失敗パターン

Page 64: あなたの安心を高速に守る Container-based CI

回避策思案 -App いっぱい-「App + DB」で 1組のサーバを一杯立てれば?

Page 65: あなたの安心を高速に守る Container-based CI

回避策思案 -App いっぱい-

なんとなくいけそう

� test-queue の各プロセス毎に「この URL にアクセスして」と固定できるので、使えそう

� See: 参考ページ

サーバ管理めんどくさい

� 構築だけでなく起動や終了も

� テストデータが更新されたら全サーバに rsync してrestore して..

Page 66: あなたの安心を高速に守る Container-based CI

「App + DB」を持ってて

テストデータの更新もすぐにできて

遅くてもいい時は3台だったり

早く終わって欲しいときは20台だったり

好きに起動したり停止できる環境を

お手軽にポチッって操作できる

便利なものないかなー

Page 67: あなたの安心を高速に守る Container-based CI
Page 69: あなたの安心を高速に守る Container-based CI

Docker

Docker(ドッカー)はソフトウェアコンテナ内のアプリケーションのデプロイメントを自動化する

オープンソースソフトウェアである。

Linuxカーネルにおける LXCと呼ばれる Linuxコンテナ技術と Aufsという特殊なファイルシステムを利用してコンテナ型の仮想化を行う。

� Docker - Wikipedia

� What Is Docker? An open platform for distributed apps

Page 70: あなたの安心を高速に守る Container-based CI

Docker を採用した理由はただひたすら「手軽」に起動できる

� 環境 (コンテナ)の起動や停止が速い� 「テストしたい時」「特に必要ない時」でカジュアルに

ON/OFF できる (数秒規模)

� やろうと思えば複数プロセス動かせる (※)� 僕たちが望んだ「App + DB」の 1環境ができる

※ 「1コンテナ 1プロセス」とよく言われるけど

� 起動して数分で消えるテスト環境のために「web」「app」「db」に分割するのはコストが高すぎる

� 手軽な使い捨て環境 だし全部入りコンテナで良い

Page 71: あなたの安心を高速に守る Container-based CI

構成 -Docker 導入-

Page 72: あなたの安心を高速に守る Container-based CI

構成 -Docker 導入-(Cont’d 1st)

Dockerfile を作成する

# Dockerfile

FROM centos:centos6

COPY scripts/* /opt/scripts

RUN sh /opt/scripts/install_dependency_libraries.sh \

&& sh /opt/scripts/install_application.sh \

&& sh /opt/scripts/restore_test_data.sh

CMD service postgresql start \

&& service httpd start \

&& tail -f /var/log/httpd/access_log

EXPOSE 80

$ # Docker コンテナイメージをビルド

$ docker build -t app-php55 .

Page 73: あなたの安心を高速に守る Container-based CI

構成 -Docker 導入-(Cont’d 2nd)

Fig (現 Docker Compose) を使う

# fig.yml

app:

image: app-php55

ports:

- "80"

$ fig scale app=5 # 5台起動

$ fig scale app=10 # 5台追加で *計 10台* 起動

$ fig scale app=3 # 7台減らして *計 3台* 起動

Page 74: あなたの安心を高速に守る Container-based CI

アプリコンテナを Dockerで動かしてると

� selenium node も fig scale でぱぱっと起動したい

� この時点では オレオレ.sh で起動してた

Page 75: あなたの安心を高速に守る Container-based CI

探してみた

Docker Hub

� docker build で作成されたイメージが置かれている

� Ubuntu 公式 だったり 個人で作ったもの だったり

� Dockerfile 公開してないとちょっと心配になる

ありました

� registry.hub.docker.com/repos/selenium/

� Selenium 開発コミュニティが出しているイメージ

� Dockerfile も GitHub に公開 されている

Page 76: あなたの安心を高速に守る Container-based CI
Page 77: あなたの安心を高速に守る Container-based CI

最終形態 (準備)

# fig.yml

app:

image: app-php55

ports:

- "80"

node:

image: selenium/node # <= Docker Hub にあるやつ

links:

- hub

hub:

image: selenium/hub

ports:

- "4444:4444"

Page 78: あなたの安心を高速に守る Container-based CI

最終形態 (召喚)

$ fig up -d hub

$ fig scale app=15 node=15

Page 79: あなたの安心を高速に守る Container-based CI

最終形態

Page 80: あなたの安心を高速に守る Container-based CI

最終形態

Page 81: あなたの安心を高速に守る Container-based CI

最終形態

Page 82: あなたの安心を高速に守る Container-based CI

最終形態

Page 83: あなたの安心を高速に守る Container-based CI

最終形態の実行結果

Page 84: あなたの安心を高速に守る Container-based CI

最終形態の実行結果

Page 85: あなたの安心を高速に守る Container-based CI

最終形態の実行結果

Page 86: あなたの安心を高速に守る Container-based CI

エンディング

以下を両立した Container-Based CI の誕生

� テスト 10分以内に終わる手軽さ

� 「なぜか失敗する」という暗黒の排除

僕たちは

安心と速度の両方を手にした

Page 87: あなたの安心を高速に守る Container-based CI

エピローグ

Page 88: あなたの安心を高速に守る Container-based CI

近況報告

無事 PHP のバージョン上げられました

1 PHP 5.X と PHP 5.Y それぞれの Docker コンテナを用意して検証

2 両方でテストが通るか。通らないなら何が原因か

� バージョンの違いによるものか、潜在的なバグか

複数バージョンを高速にチェックできてよかった

Page 89: あなたの安心を高速に守る Container-based CI

近況報告 (Cont’d)

開発期間の変化 (高速化する前から取り組んでいましたが)

� 以前までは 3ヶ月 - 6ヶ月などの長期間

� 現在は 2、3週間スプリントで回している� 開発 (1、2週間。この間はレビュー & 自動テストチェックをメインに)

� 検証 (4日間。メインの CHANGE に対する手動テスト)� ふりかえり (1日。本スプリントでの KPT)

テストの高速化、および安定化の維持は良い効果

Page 90: あなたの安心を高速に守る Container-based CI

現在の開発フロー

1 手元で開発

2 git push

3 GitHub で Pull Request (以下、PR) を作成

4 Jenkins Master が PR(commit) を検知し、そのブランチを Jenkins Slave に教える

5 Jenkins Slave が教えられたブランチを元に Docker のアプリコンテナを起動

� ついでに Selenium Hub/Node も起動 (停止していれば)

6 Integration test に加えて Unit Test も実行

7 約 10分ぐらいでフルテスト完了

8 もし fail だったら修正を commit 。以後 4 - 7 を繰り返す

Page 91: あなたの安心を高速に守る Container-based CI

後輩のコメント

Page 92: あなたの安心を高速に守る Container-based CI

ずっと目指していた

via full test also want to end within 50ms // Speaker Deck

Page 93: あなたの安心を高速に守る Container-based CI

まとめ

Page 94: あなたの安心を高速に守る Container-based CI

手持ちのリソースにあった

パターンを

今回は高スペックなワークステーションがあったので

Docker コンテナを大量召喚できた

� 低スペックだがマシンが大量にあるなら、並列化だけ

ではなく 分散化 も考えるべき

Page 95: あなたの安心を高速に守る Container-based CI

勘違いしてはいけないのは

高速化を目指すことでテストが安定しないのであれば

高速化を諦めてテストの安定に集中すべき

� × 目指すはテストの高速化

� ○ 開発者に心の安らぎを

Page 96: あなたの安心を高速に守る Container-based CI

おわり

PEACE OF MIND

安らぎが力になる