32
継続的デリバリー読書会 第 5 デプロイメントパイプラインの解剖学 20120828 20120914 大崎的デリバリー @ts7i

継続的デリバリー読書会 第 5 章 デプロイメントパイプラインの解剖学

Embed Size (px)

Citation preview

継続的デリバリー読書会 第 5  章  デプロイメントパイプラインの解剖学

2012-­‐08-­‐28  2012-­‐09-­‐14  

大崎的デリバリー  @ts7i  

5.1  導入 •  CI  の採用により生産性と品質が向上する •  しかし CI  だけでは十分ではない

–  CI  は開発チームにフォーカス –  その後のプロセス:  テストとリリース

•  ここで問題が起きるとデプロイできない •  全体論的なエンドツーエンドのアプローチを採用して解決

–  ビルド・デプロイ・テスト・リリースを自動化 –  最終的にできあがるのは「プルシステム」

•  テストチームと運用チーム:  ボタンを押すだけでデプロイ •  開発者とマネージャ:  ビルドの進捗や問題が見える

•  デプロイメントパイプラインには一般的なパターンがある

5.2  デプロイメント  パイプラインとは何か?  #1  

•  概要 –  「ソフトウェアをバージョン管理から取り出してユーザの手に渡すまでのプロセスを自動化して表現したもの」

–  ビルド →  テスト →  デプロイメント –  さまざまなステージ、多くのメンバ、複数のチーム

•  バリューストリーム –  顧客の頭の中のフィーチャを引き出してその手に渡すまでのプロセス –  詳しくは『リーン開発の本質』を参照 –  本書で議論するのはバリューストリームの一部 (開発 →  リリース)  

•  変更がデプロイメントパイプラインを通り抜ける –  バージョンコントロール、ビルド &  ユニットテスト、自動受け入れテスト、ユーザ受け入れテスト、リリース

–  不適切なビルドを早期のうちに排除する •  リグレッションバグを避ける

–  リリースが反復の容易な「普通の」イベントになる •  最悪の場合も簡単に切り戻し可能

5.2  デプロイメント  パイプラインとは何か?  #2  

•  ステージ – コミットステージ

•  技術レベルで検証する •  コンパイル、ユニットテスト、コード解析

– 自動受け入れテストステージ •  機能および非機能レベルで検証する

– 手動テストステージ •  ユーザビリティと要件への適合度を検証する •  探索的テスト環境、インテグレーション環境、UAT  環境

– リリースステージ •  システムをユーザにデリバリーする •  対象:    パッケージ、ステージング環境、本番環境、…  

5.2.1  基本的なデプロイメント  パイプライン

•  P158  図 5-­‐4  •  第一ステージ:  コミットステージ – ユニットテスト、バイナリ生成、成果物リポジトリへ格納 – 並列実行可

•  第二ステージ:  自動受け入れテスト –  コミットステージより時間がかかる (1-­‐2  時間)  – 並列実行可

•  その後分岐:  UAT、キャパシティテスト、本番 – 各チームが自分でデプロイできるよう自動化

•  目的はできる限り素早くフィードバックを受け取ること –  CI  サーバでパイプラインのどこまで通ったか確認

5.3  デプロイメントパイプラインの  プラクティス

•  各ステージについてより詳細に見る前に

5.3.1  バイナリをビルドするのは  1  回限りとせよ

•  リコンパイルの問題 – 時間がかかる – バイナリの生成とリリースとの間に変更が紛れ込むリスクが発生する •  例:  コンパイラのバージョン、依存ライブラリのバージョン、…  

•  バイナリはコミットステージで 1  回ビルドすればいい – 派生物なのでバージョン管理には入れない –  CI  サーバが管理してくれる

•  各環境に対して単一のバイナリで対応する – そうでなければビルドシステムが不必要に複雑になる

5.3.2  あらゆる環境に対して  同じやり方でデプロイせよ

•  リリースのリスク低減 – 本番リリース実施までにデプロイメントプロセスが数百回テストできる

•  設定を分ける方法 – 環境ごとに別々のプロパティファイル準備する

•  バージョン管理対象 – その他 LDAP  やデータベース +  ESCAPE  など

•  詳しくは P79  を参照 •  もしうまくいかなかった場合は以下のいずれがが原因 – アプリケーションに含まれる環境や固有のファイルの設定 – アプリケーションが依存しているやサービスの問題 – 環境の設定

5.3.3  デプロイメントを  スモークテストせよ

•  (補足)  スモークテストの定義 –  hEp://www.atmarkit.co.jp/aig/04biz/smoketest.html  

•  デプロイ時にアプリケーション稼働を確認するスモークテストを自動スクリプトで実行

•  シンプルなもので可 – アプリケーションを起動 →  メイン画面に期待通りの内容が表示されていることを確認

•  アプリケーションが依存しているサービスが全て稼働していることを確認 – データベース、メッセージバス、外部サービス

•  ユニットテストスイートの次に書くべき重要なテスト – アプリケーション起動しない場合の原因を診断できる

5.3.4  本番のコピーに  デプロイせよ

•  テストと CI  を本番環境にできるだけ似せた環境で行う必要がある

•  構成管理的に同一性を保証すべき項目 – 基盤 (ネットワークトポロジー、ファイアウォール設定、…)  –  OS  設定 (パッチ含む)  – アプリケーションスタック – アプリケーションのデータ

•  詳しくは 12  章 を参照 •  プラクティスやツール – ディスクイメージング、仮想化 –  Puppet、Install  Shield  (+  バージョン管理)  

•  詳しくは 11  章を参照

5.3.5  各変更は直ちにパイプライン全体を通り抜けなければならない

•  CI  以前:  プロセスの各部分をバラバラにスケジューリング –  hourly  ビルド、daily  受け入れテスト、weekly  キャパシティテスト、…  

•  デプロイメントパイプライン:  各ステージ成功をトリガに次のステージ –  CI  サーバのスケジューリング機能重要

•  ビルドとユニットテストの全てに対して自動受け入れテストを実行するわけではない

•  ただし完全に自動化されたステージのみ – 手動テストなどは対象外

5.3.6  パイプラインのどの部分であっても、失敗したらラインを止めよ

•  素早く反復可能で信頼できるリリースを達成するために最も重要なプロセス

– コードのチェックイン →  ビルド成功とテスト通過をチームが確認すること

– デプロイメントが失敗したら責任はチーム全体で持つ

5.4  コミットステージ

•  5  分以内が理想 •  ステップ – コンパイル – コミットテスト一式 – 後続ステージ向けバイナリ生成 – コード解析実行 •  カバレッジ、重複コード、複雑度、結合度、警告数、コードスタイル

– 後続ステージ向け成果物生成

5.4.1  コミットステージの  ベストプラクティス

•  開発者はコミットステージが完了するのを待つ

– コミットステージさえ終われば以降のステージは待つ必要なし

•  「デプロイメントパイプライン」用語由来 –  CPU  のパイプライン命令並列実行 –  新しいフィーチャの開発と並行して実行

5.5  自動受け入れテスト  という関門

•  ユニットテストだけでは検出できない問題がある

– ユニットテストは開発者視点 •  受け入れテストステージの検証 – 顧客の期待する価値をシステムがデリバリーできていること

– 受け入れ基準を満たしていること

5.5.1  自動受け入れテストの  ベストプラクティス

•  本番環境を想定 –  本番環境が複雑もしくは効果な場合はスケールダウン版の環境を使う

–  外部サービスはテストダブルで代替する •  詳しくは第 8  章

–  本番環境が複数ある場合はビルドグリッドを使う •  クライアントアプリケーションなど

•  受け入れテストはチーム全体のもの –  プロダクションコードとテストスイートの保守チームを分けるべきではない

•  受け入れテストはビジネスの言葉で表現されるべき –  実装の詳細に依存しない

•  バッドプラクティスに従うとコストの増大により自動化を断念することに

5.6  後に続くテストステージ

•  多くの場合は手動テストを行う場合が望ましい – 自動デプロイメントに進むことも可能だが

•  各種環境へのデプロイ – 他システム統合テスト環境、キャパシティテスト環境、探索的テスト環境、ステージング環境、本番環境、…  

– パイプラインの一環として各環境へのデプロイを管理 •  テスターが任意のビルドを任意の環境へデプロイできる

5.6.1  手動テスト

•  受け入れ基準が満たされていることを手作業で証明 – リグレッションテストではない

•  人間のほうが優れている種類のテストに集中 – 探索的テスト – ユーザビリティテスト – 各プラットフォームでのルックアンドフィールの確認 – システム障害発生時の異常系テスト

•  自動受け入れテストによってテスターが自由に使える時間を作る

5.6.2  非機能のテスト

•  非機能要件 – キャパシティ、セキュリティ、SLA、…  

•  非機能要件のテストは自動化可能 – 詳しくは第 9  章

•  即時失敗 OR  人が判断 – 多くの場合は人が判断したほうが良い

5.7  リリースに備える •  本番環境リリースのビジネスリスク – 作業時の深刻な問題発生 – 切り戻し計画の不備

•  デプロイメントパイプラインによる対応 – 全員でリリース計画 – 自動化でミスの影響を最小化 – 擬似本番環境でプロセスやテクノロジーを繰り返しデバッグ

– バックアウトできるようにしておく – 設定とデータ移行を更新と切り戻しのプロセスに組み込む •  詳しくは第 10  章

5.7.1  デプロイメントと  リリースを自動化する

•  デプロイメントのコントロールを妨げる制約 –  運用環境を完全にコントロールすることができない

•  クライアントアプリなど •  →  対象環境の代表的なサンプルを用意して緩和

–  恩恵以上にコストがかかると見なされがち •  →  本来は逆

•  本番環境の変更は自動化されたプロセスのみに限定すべき –  詳しくは第 11  章

•  本番環境を管理するプロセスは他の環境にも使うべき •  リリースプロセスの完成度が高まるとリスクが確実に低くなる –  デプロイの繰り返しによる裏付け

5.7.2  変更をバックアウトする •  リリース失敗のリスクをバックアウト戦略で緩和する •  最善の戦略 – ひとつ前のバージョンをリリースの間も使えるようにしておく •  詳しくは第 10  章 •  データ移行の問題については第 12  章

•  次善の戦略 – 以前の適切なバージョンをデプロイし直す

•  まずい戦略 – デプロイ時と違う方法でのバックアウト – インクリメンタルなデプロイメントやロールバック

5.7.3  成功を積み重ねる •  本番デプロイまでに以下が実現 – コンパイルできる – 開発者の期待通りに動く ←  ユニットテスト – アナリストやユーザの期待通りに動く ←  受け入れテスト

– 環境の設定が適切に管理されている ←  本番と同様のテスト

– コンポーネントが揃っている ←  デプロイ可能 – 本番に正常にデプロイ可能 ←  以前のステージでのデプロイ実績

– 手作業での操作が不要 ←  各環境でのデプロイ繰り返し

5.8  デプロイメントパイプラインを  実装する

•  インクリメンタルなアプローチ – バリューストリームをモデル化して、動くスケルトンを作成する

– ビルドとデプロイプロセスを自動化する – ユニットテストとコード解析を自動化する – 受け入れテストを自動化する – リリースを自動化する

5.8.1  バリューストリームをモデリングし、動くスケルトンを作成する

•  バリューストリームマップを書く – チェックインからリリースまで

•  CI  プロセスとリリース管理ツールをモデル化する

•  実際に動かす – 新規プロジェクトの場合は「動くスケルトン」を作る • 最もシンプルな形式でコミットステージから受け入れテストステージまで通す

•  イテレーション 0  で実施する

5.8.2  ビルドとデプロイメント  プロセスを自動化する

•  ビルド – ソースコードからバイナリ (多義的)  を生成 – 誰かがチェックインするたびに CI  サーバによって実行

– バイナリの格納場所には CI  サーバ経由でアクセス •  デプロイメント – デプロイ先環境構築 – パッケージング – インストールと設定の自動化 – デプロイ結果検証の自動化 –  1  ボタンデプロイ化

5.8.3  ユニットテストと  コード解析を自動化する

•  コミットステージ全体を実装 – チェックインのたびに、ユニットテスト、コード解析、…を実行

•  ユニットテスト – 高速に実行

•  静的解析ツール – コーディングスタイル、コードカバレッジ、サイクロマチック複雑度、結合度

•  アプリケーションの複雑化に従って肥大化 – 並列実行で対応可能

5.8.4  受け入れテストを  自動化する

•  テスト環境にデプロイするのに使ったスクリプトを再利用する

•  加えてスモークテスト後に受け入れテストフレームワークを起動する – 結果レポートを集積して分析する

•  受け入れテストの分類 – 機能テスト – 非機能テスト

•  キャパシティ、スケーリング、…  •  詳しくは第 9  章

•  少なくとも 1-­‐2  項目はプロジェクトの初期に自動化すべき

5.8.5  パイプラインを進化させる •  プロジェクトの複雑化 →  バリューストリームの進化 –  コンポーネント

•  各コンポーネントのミニパイプライン →  組み合わせパイプライン •  詳しくは 13  章

– ブランチ •  詳しくは 14  章

•  パイプライン構築のポイント – パイプライン全体を一度に実装する必要はない – プロセスのタイムスタンプと進捗を記録する – パイプライン自体を継続的に改善していく

5.9  メトリクス •  フィードバックを改善する方法

–  サイクルを短くし、結果を見えるようにする –  Informa^on  Radiators  

•  何を計測すべきなのか –  ホーソン効果:  計測対象がチームのふるまいに影響を与える –  サイクルタイムが最も重要 –  ToC  を使って改善

•  制約条件 =  ボトルネックを特定する •  ボトルネック箇所のスループットを最大化する •  他のプロセスを制約に従属させる •  制約の限界を上げる •  最初に戻る

–  その他のメトリクス例 •  カバレッジ、コードベースの特徴、欠陥数、ベロシティ、コミット数、ビルド数、ビルド失敗数、ビルド時間、…  

•  Panop^code  による可視化の例 –  チェックイン →  レポート生成 →  内部 Web  サイトで公開

5.10  まとめ

•  デプロイメントパイプラインの目的 – 関係者全員にビルドの進捗を見えるようにすること

•  リリースプロセスのどこが非効率なのかがわかる

– プロセスの最適化に取り組める •  基盤や規律の整備が必要 – 構成管理、自動スクリプト、自動テスト、…  – 変更リリース手法の縛り

•  詳しくは第 15  章

感想

•  序盤にデプロイメントパイプラインの全体像が簡潔にまとまっている –  使えそうな図いくつかあり

•  重要かつ軽視されがちなプラクティス –  バイナリをビルドするのは 1  回限りとせよ –  あらゆる環境に対して同じやり方でデプロイせよ –  デプロイメントをスモークテストせよ

•  受け入れテストに関する記述は 8  章で具体的なコードを見てから読み返すとわかりやすくなるはず

•  TODO:  メトリクスに関する良い本を探す •  サイクルタイム最重要を共通認識にできるか

–  そもそもたった数行修正してのリリースに数日のリードタイムがあることを問題だと感じていない開発者が多そう

•  残念ながら相変わらずクドい –  同じ章内ですら繰り返しが多い