Skip to content

Instantly share code, notes, and snippets.

@dokimyj
Last active March 24, 2022 01:31
Show Gist options
  • Select an option

  • Save dokimyj/348e4f75706579f8c93c71d08d32c9bc to your computer and use it in GitHub Desktop.

Select an option

Save dokimyj/348e4f75706579f8c93c71d08d32c9bc to your computer and use it in GitHub Desktop.
GSE 23.2~4

23.2~4

23.2 Google における CI

  • TAP(Test Automation Platform)
  • Google Takeout(データバックアップ・ダウンロードプロダクト) の CI 事例

TAP: Google のグローバル継続的ビルド

  • モノリポのおかげで、すべてのコード変更は TAP を通るようになっている
  • 日々5万件以上の修正+40億のテストケースを処理

リポジトリ提出前のテストの最適化

  • Continuous Build: 素早く、持続的に Issue を発見するために行われる
  • CBを通る意味: 各チームで作った提出前のテストを通過したら 95% 以上の CB テストを通過 (経験的)
  • TAPの非同期テスト: 提出後のテストが失敗したら早めに修正するG特有の文化確立(他チームを邪魔しないように)
  • Build Cop: ↑のために導入したバグフィックス担当官制度、バグを発見したら一先ずバグフィックスを(Rollback or 追加修正)
  • 実際: テスト通過前のコミット(+Build cop)で時短+妨害最小化

犯人探し

  • 大型テストの問題: どの修正より失敗したテストか(本来は解決が容易であるはず)
  • なぜ解決が難しいか: テストインフラの問題 + TAP が全ての変更に対して全てのテストを毎日回せない(変更関連部分のみテスト実行)
  • テスト失敗の原因探しに速度をつけよう
- TAP が失敗した Batch を修正部分別に分けて再びテスト実行
- 変更された部分に対し、バイナリー検索を提供(開発者が確認できるように)

失敗の管理

  • 失敗を発見したら早く復旧(Build Cop の役目) → その中1番効率的なのはロールバック
  • TAP の最新アップデート: 失敗の原因を分かった場合(+自動で可能であれば)自動ロールバック
  • 相互補完: テストなしには安全ロールバックもない、ロールバックがなければ失敗したテストも直せなく、システムの信頼度が下がる

リソース上の制約

  • Forge: 大半のビルド・テストはこのシステムで行われる(並列性の最大化のため) → 限られたリソースの問題が発生
  • テストの取捨選択: 全ての変化のダウンストリーム依存関係グラフを分析 → Forge/Blaze でほぼリアタイ分析・TAP 転送
  • TAP のテスト速度: 変化が小さくなるほどテストが早く進める → 開発者たちがコード変更を小さくこなす

23.2.1 CIケーススタディ:Google Takeout

  • データバックアップ・ダウンロード用のプロダクト(2011~)
  • 効果的な CI の価値: 肥大化された Takeout プロジェクトを健全に運用するようにできた

23.2.1.1 シナリオ1:継続的に破綻している dev 環境デプロイ

  • 問題
  1. 他サービスでバックアップ機能を連携し初めて、バックエンド化された
  2. 各サービスごとにバイナリーを少しずつ修正して提供
  3. フラグ Issue: 1インスタンスのフラグが他のところにも影響を与え、ビルドが失敗
  4. さらなる問題: 修正時に手動でテストを回すのが現実的に無理
  • 解決
  1. 各インスタンスをサンドボックス化 → そうしてもテストデータ・統合テスト環境の復旧が問題
  2. 提出前テストからサンドボックスの環境を引継ぎ使用(コミット後の環境に拡張できるように) → テストアカウントのセキュリティ防護基準の適用を可能にし、E2E テストが実行可能
  3. コミット後 CI 実行は 2時間ごとに、最新コード・設定を受け止め RC バージョンを生成しテスト
  • 教訓
  1. Takeout プロダクトのテストを提出前に移してから失敗が半分になった
  2. E2E を提出後 2時間へ移し、犯人の集まりを 1/12に削減した

23.2.1.2 シナリオ2:テストの解読不能なログ

  • 問題
  1. Takeout PF化 → 各プラダクトがプラグインを追加
  2. プラグインが多すぎてテスト失敗のログが複雑になった
  • 解決
  1. パラメタ化されたテストの実行で動的・設定ベースへテストをリファクタ
  2. 失敗ログの情報表示を改善(ログへのリンク、エラーメッセージ) → デバッグ・ログ転送を自動化
  • 教訓: CIのアクセス可能・行動可能なフィードバックは生産性を向上

23.2.1.3 シナリオ3:「全Google」のデバッグ

  • 問題
  1. 結局 G全社の Issue を掴めるテストベッド化
  2. 失敗を切り分けるプレセス(Takeout 内か外か)を改善する必要が発生
  • 解決: 本番にもコミット後 CI のようなテストを実行(Gの他サービスリリースなど)
  • 教訓: 失敗を切り分けるに効率的な方法は本番にもコミット後 CI テストを行うこと
  • 課題: 他サービスが複雑になる程 CI と本番の主導比較はコストが高くなる
  • 将来の改善: コミット後 CI での密閉テストで Takeout のテストを安定化

23.2.1.4 シナリオ4:グリーンに保つ

  • 問題
  1. 他プロダクトのバグのせいで Takeout のテストがほぼ全部失敗
  2. 優先順位が高いバグがビルドを失敗させ、そのテストコードをコメントアウトし始めた
  3. 環境(機能が追加されたか否か)により、手動でテストの実行・スキップを決定するように
  • 解決
  1. 他チームのバグはバグ内容をタグし、該当チームに転送
  2. タグされたバグは Suppress し、テストは成功させる
  3. 機能追加の問題: 環境による結果値を開発者たちから募集、各環境を全部テスト
  4. バグが解決されたらタグを除去
  5. テスト自体が信頼不能(Flaky)ならテストが通ってもタグを剥がさない
  • 教訓
  1. すぐ解決し難しいバグのテストを「除外」するのは、テスト失敗より解放され、(プロダクトへの)自信を堤高
  2. 機能追加の管理を含めるテストのメンテナンス自動化はテスト環境を整理する且つ技術負債を予防 (DevOps 用語で MTTCU: Mean Time To Clean Up)
  • 改善: バグ報告とタグつけを自動化

  • さらなる課題: 稀に発生する上流のシステムエラーを切り分ける → セキュリティアップデートなどのせいでファイルの復号化が進んでしまう問題など → 上流のシステムは自主テストを行い、Takeout の CI でチェックする方法がない → 上流のシステムのステージング環境を構築するのも互換性の問題でメンテ難しい

23.2.2 だが CI を行う余裕がない

  • 本番で跳ねた問題を解決するコスト: ユーザーの被害、チームのストレス蓄積・行き込み低下
  • 初期に導入するほど ↑ の費用を払うことが減る

23.3 結論

  • Gの CI プロセスと自動化が「完璧」とは言えない
  • CI 自体もソフトウェアであり、完結されたものではなく、進化する要求により調整されるもの
  • Takeout の CI と、今後の改善点を通して確認した

23.4 要約

  • CI は「どのテストを」、「いつ使うか」を決定
  • CI はコードベースが成熟となり、スケールアップされるほど益々必要となる
  • CI は素早かで安定的なテストを提出前に、遅くて比較的に「非決定性」を持ったテストは提出後におくべき→テストを最適化
  • アクセス可能であり、行動可能なフィードバックは CI を更に効率的にする
感想
- Gの CI は Alerting と言ったことが理解できるほど、CI の説明でテストの比率が高い
- CI でのテストを「提出前テスト」と「提出後テスト」に分割する文化、テスト時間による分類など色々考え直すきっかけになった

23.2~4

23.2 Google における CI

  • TAP(Test Automation Platform)
  • Google Takeout(データバックアップ・ダウンロードプロダクト) の CI 事例

TAP: Google のグローバル継続的ビルド

  • モノリポのおかげで、すべてのコード変更は TAP を通るようになっている
  • 5만 건 이상의 수정+40억 테스트 케이스를 처리

リポジトリ提出前のテストの最適化

  • Continuous Build: 빠르고 지속적으로 이슈를 발견하기 위해
  • CB를 통하는 의미: 각 팀에서 만든 제출전 테스트 통과=95% 이상 CB테스트 통과
  • TAP의 비동기 테스트: 제출 후 테스트, 실패는 빠르게 고치는 G 문화(다른 사람에게 방해가 되지 않게)
  • Build Cop: ↑를 위해 도입한 버그픽스 담당 제도, 버그 발견 시 픽스(롤백 or 추가 수정)
  • 실제: 테스트 통과 전 커밋(+Build cop)으로 시간 단축+방해 최소화

犯人探し

  • 대형 테스트의 문제: 어느 수정에 기인한 테스트 실패인가(원래는 해결이 쉬워야 함)
  • 왜 해결이 어려운가: 테스트 인프라의 문제+TAP가 모든 변경에 모든 테스트를 매일 돌리지는 못함(변경 부분 테스트만 실행)
  • 테스트 실패 원인의 탐색 속도 높이기
- TAP 가 실패한 배치를 수정 부분 별로 나눠서 다시 테스트 실행
- 변경된 부분에 대한 바이너리 검색을 제공(개발자가 확인할 수 있게)

失敗の管理

  • 실패를 발견하면 빨리 복구(Build Cop 의 역할) → 가장 효율적인 건 롤백
  • TAP 최신 업데이트: 실패의 원인을 찾으면 자동 롤백
  • 상호보완: 테스트 없이는 안전한 롤백도 없으며, 롤백이 없으면 실패 테스트를 고칠 수 없어 시스템 신뢰도가 하락

リソース上の制約

  • Forge: 대부분의 빌드/테스트는 이 시스템에서 함(병렬성의 최대화를 위해)→한정된 리소스의 문제 발생
  • 테스트의 取捨選択: 모든 변화의 하방의존성 그래프 분석→Forge/Blaze 에서 거의 실시간으로 분석, TAP 에 전송
  • TAP 의 테스트 속도: 변화가 작을수록 테스트가 빨리 실행됨→개발자들이 코드 변경을 소규모로 분할

23.2.1 CIケーススタディ:Google Takeout

  • 데이터 백업/다운로드용 프로덕트(2011~)
  • 효과적 CI 의 가치: 비대해진 Takeout 프로젝트를 건전하게 운영할 수 있게 함

23.2.1.1 シナリオ1:継続的に破綻している dev 環境デプロイ

  • 문제
  1. 타 서비스에서 백업 기능을 연계하면서 백엔드화 되어버림
  2. 각 서비스마다 바이너리를 약간씩 수정해서 제공
  3. 플래그 이슈: 한 인스턴스의 플래그가 다른 곳에 영향을 끼쳐 빌드 실패
  4. 더 큰 문제: 수정할 때마다 수동 테스트를 돌리는 게 현실적으로 불가능
  • 해결
  1. 각 인스턴스를 샌드박스화 → 그래도 테스트 데이터나 통합 테스트 환경 복구가 문제
  2. 제출 전 테스트에서 샌드박스 환경 재사용(커밋 후 환경으로 확장 가능하도록) →테스트 계정의 시큐리티 防護基準 적용이 가능하도록 하여 E2E 실행 가능
  3. 커밋 후 CI 실행은 2시간마다, 최신 코드/설정을 받아 RC버전을 생성하고 테스트
  • 교훈
  1. 각 Takeout 프로덕트의 테스트를 제출 전으로 옮기면서 실패가 절반으로
  2. E2E 를 제출 후 2시간으로 옮겨 犯人の集まり를 1/12로 줄임

23.2.1.2 シナリオ2:テストの解読不能なログ

  • 문제
  1. Takeout 플랫폼화 → 각 프로덕트가 플러그인 추가
  2. 플러그인이 너무 많아져서 테스트 실패 로그가 복잡해짐
  • 해결
  1. 파라미터화된 테스트 실행으로 동적/설정 기반으로 테스트 리팩터링
  2. 실패 로그 정보 개선(로그에의 링크, 에러 메시지) → 디버깅 자동화/로그 전송 자동화
  • 교훈: CI의 액세스 가능하고 행동 가능한 피드백이 생산성을 향상

23.2.1.3 シナリオ3:「全Google」のデバッグ

  • 문제
  1. 결국 전 Google 이슈를 잡아내는 테스트베드가 되었다
  2. 실패를 분별하는 프로세스(Takeout 내부인지 외부인지)를 개선할 필요가 발생함
  • 해결: 本番에도 커밋 후 CI처럼 테스트 실행(구글의 타 서비스 릴리즈 등)
  • 교훈: 실패를 분별하기에 효율적인 방법은 本番에도 커밋 후 CI 테스트를 하는 것
  • 과제: 타 서비스가 복잡해질수록 CI와 本番 수동 비교는 코스트가 커질 것
  • 추가 개선: 커밋 후 CI에서의 폐쇄 테스트로 Takeout 테스트 안정화

23.2.1.4 シナリオ4:グリーンに保つ

  • 문제
  1. 타 프로덕트의 버그로 테스트가 거의 실패
  2. 우선순위가 높은 버그가 빌드를 실패시켜 그 테스트 코드를 코멘트 아웃하기 시작
  3. 환경(기능 추가/미추가 버전)에 따라 수동으로 테스트의 스킵/실행을 결정하게 됨
  • 해결
  1. 타팀 버그는 버그 내용을 태그해서 해당 팀으로 전송
  2. 태그된 버그는 Suppress 해서 테스트는 성공하도록 함
  3. 기능 추가 문제: 환경에 따른 결과값을 개발자들에게서 받아 각 환경을 모두 테스트
  4. 버그가 해결되면 태그를 제거
  5. 테스트 자체가 信頼不能(Flaky)이면 태그를 제거하지 않도록 함
  • 교훈
  1. 바로 해결하기 어려운 버그의 테스트를 제외하는 것은 테스트 실패로부터 해방되어 자신감을 제고
  2. 기능 추가 관리를 포함한 테스트의 메인터넌스 자동화는 테스트 환경을 정리하고 기술부채를 예방 (DevOps 용어로 MTTCU: Mean Time To Clean Up)
  • 개선: 버그 신고와 태깅을 자동화

  • 추가과제: 드물게 발생하는 상류 시스템 오류를 분별하는 것 → 시큐리티 업데이트 때문에 파일의 복호화가 풀려버리는 문제 등 → 상류 시스템은 자체 테스트이기 때문에 Takeout CI에서 체크할 방법이 없음 → 상류 시스템 스테이지 환경을 구축하는 것도 호환성 문제 때문에 유지보수가 어렵다

23.2.2 だが CI を行う余裕がない

  • 本番에서 터진 문제를 해결하는 데 드는 비용: 유저의 피해, 팀의 스트레스 축적/意気込み 저하
  • 초기에 도입할수록 위 비용을 지불하는 일이 줄어들 것

23.3 結論

  • G의 CI 프로세스와 자동화가 완벽하다고는 할 수 없다
  • CI 자체도 소프트웨어이며 완결된 것이 아닌, 진화하는 요구에 따라 조정되어야 한다
  • Takeout 의 CI와 향후 개선점을 통해 알아보았다

23.4 要約

  • CI는 어떤 테스트를 언제 쓸 것인 지 결정한다
  • CI는 코드베이스가 성숙해지고 스케일업 될수록 점점 필요해진다
  • CI는 빠르고 안정적인 테스트를 제출 전 테스트에, 느리고 덜 결정적인 테스트를 제출 후 테스트에 최적화해야 한다
  • 액세스 가능하고 행동 가능한 피드백은 CI를 더 효율적으로 만든다
감상
- G의 CI가 Alerting이라고 한 말이 와닿을 정도로 검증, 테스트의 비중이 크다
- CI에서의 테스트를 제출 전 테스트(PR테스트?)와 제출 후 테스트(마스터에서의 테스트)로 분리하는 문화, 테스트 시간에 따른 분류 등을 다시 생각해 보는 계기
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment