Upgrade to Pro — share decks privately, control downloads, hide ads and more …

数時間かかる週一リリースを毎日何度も爆速でできるようにするまで / CI/CD Conference 2021

数時間かかる週一リリースを毎日何度も爆速でできるようにするまで / CI/CD Conference 2021

CI/CD Conference 2021

08d5432a5bc31e6d9edec87b94cb1db1?s=128

Takashi Kokubun

September 03, 2021
Tweet

Transcript

  1. 数時間かかる週一リリースを 毎日何度も爆速で できるようにするまで @k0kubun / Takashi Kokubun - CI/CD Conference

    2021
  2. 自己紹介 • GitHub, Twitter: @k0kubun • Treasure Data ◦ API:

    プラットフォーム 1年 ◦ SRE: デプロイ 1年 ◦ Backend: ストレージ 2年半
  3. None
  4. 今日話すこと • なぜ継続的にリリースすべきなのか • 継続的リリースのために必要なこと ◦ リリースのリスク最小化 ◦ オペレーションの自動化 ◦

    デプロイの高速化
  5. なぜ継続的にリリースすべきなのか

  6. 背景: 私が入社した時のリリースフロー • リリースマネージャが変更をcherry-pick • リリースノートにオペレーションを手動で記録 ◦ チケットにリリースタグを追加 ◦ stagingデプロイ後、最低2時間、通常1日待つ

    ◦ 定期実行される結合テスト結果を記録 • 全台sshか30分おき定期実行でのChefによるリリース
  7. 何が困るか • 面倒な手動オペレーションが多く、リリース頻度が減る ◦ 結果、毎回のリリースの変更粒度が大きく、問題の切り分けが困難に • リリースマネージャとのコミュニケーションコストが大きい ◦ 時差が分かれてると返事を見るのが1日後とかになる •

    様々な依存のあるChef実行はランダムで失敗し、時間もかかる
  8. 弊社のデプロイターゲット数 • productionのAutoScalingグループの数: 約600 • 手動作業が多いほど、本質的作業に費やせる時間が減る • サービスが多いほど、それぞれのリリースを安全にする必要性は高 まる

  9. 入社時のチームのリリース • 待ち時間: 2〜24時間 • デプロイ時間: 40分 • リリース頻度: 週1回

  10. 現在のチームのリリース • 待ち時間: 10分 • デプロイ時間: 5分 • リリース頻度: 週28回とか

    (週による)
  11. 継続的にリリースできると何が嬉しいのか • 要望に対応するまでの時間が短くなり、顧客満足度が上がる • リリースごとの影響範囲を小さくし、低リスク化しやすい • リリース待ちの変更が少なくなり、調整コストが減る

  12. 継続的リリースのために必要なこと • リリースのリスク最小化 • オペレーションの自動化 • デプロイの高速化

  13. リリースのリスク最小化

  14. デザインレビュー • アーキテクチャの改善によりリスクを早いフェーズで減らせる ◦ スケーラブルな設計、障害発生ポイントの最小化 • サービスが満たすべきチェックリストを作り、漏れを防ぐ • システムの本番投入はセキュリティデザインレビュー必須 ◦

    顧客情報流出を防ぐため
  15. タイムアウト、リトライ、サーキットブレーカー • タイムアウト: スレッドが1つの処理に占有されるのを避ける • リトライ: 一時的故障のクライアント影響の最小化 ◦ POST的な操作も含め、全てをリトライ可能なように作る •

    サーキットブレーカー: 故障時に望ましい挙動を実装する ◦ 旧実装に切り替えたり、低速化している依存先を呼ぶのを避けレイテンシを抑 える、等
  16. 結合テスト • 単体テストではサーバーの設定起因のバグをキャッチできない ◦ なので、stagingにデプロイしたサーバーに対してのテストを行なう • この仕組みは元からあったが、結合テストが一切ない機能などで障 害が起きる傾向にある ◦ 最近はQAチームがテスト要件のドキュメントを書き、そのレビューを行なったり

    している
  17. SLOとエラーバジェット • コンポーネントごとにService Level Objectiveを設定、監視 ◦ リリース品質に関する顧客満足度のプロキシになる ◦ 具体的な目標があると、その差分のための計画を立てられる ◦

    例えばSLOを満たしていない時はリリースを控えてリスクを減らすなど
  18. デプロイとリリースの分離 • デプロイには時間がかかるし、影響範囲の粒度も大きくなる • Feature Flagでコードの変更と機能追加のタイミングを分ける ◦ リスクの高い変更のリリース待ちで他がブロックされなくなる • フラグを増やすとテスト対象が増えることに注意

    ◦ フラグ同士で依存関係がある状態は避けるか、有効化順序を自動で強制
  19. 段階的リリース • 変更の影響範囲が大きい場合、デプロイ対象サーバー数やユー ザー数で範囲を絞り、徐々にリリースする ◦ テスト時に予期していなかった問題や、本番でのみ発生する問題は、リリース 対象を小さくすることでしか制御できない • 壊れるリスクが高い新機能は、それが欲しいユーザーにベータリ リースを検討

  20. リリース告知 • 非互換や、ダウンタイムが必要な変更は事前に通知 ◦ 無告知で非互換をいれると、クライアント側が壊れてそこが障害になることが ある

  21. アラート • SLO違反だけでなく、その要因となるメトリクスの劣化を自動検知 ◦ ユーザーより先に自分たちが問題に気付くことが大事 • サービスのタイプごとにアラートをパターン化し、新サービスでの漏 れをなくす ◦ HTTPサーバーではtoo

    many 5xx、too large p99 latencyなど
  22. ダッシュボード • false positiveがあるメトリクスの監視や、障害時のデバッグ用 ◦ 4xxレスポンスが増えても必ずしも障害とは限らないが、リリース時に増えると リリース関連の障害の可能性が高い ◦ モニターが多すぎると監視が大変になるので、リリース時に見るべきものとデ バッグ用のものはセクションを分ける

    • 依存しすぎるとモニタリングが属人化していくので、可能な限りア ラート化する
  23. オペレーションの自動化

  24. 結合テストの自動実行 • 2時間おきに定期実行される結合テストを、mainブランチのコミット からトリガーするように変更 ◦ 使うリソースにCIのジョブIDをいれるなど、並列実行しても動くように工夫が必 要 • 丸1日結合テストを流し続けてからテスト、をやめた ◦

    同じ実装に同じテストを何回も走らせる意義は薄い ◦ 社内検証時間はFeature Flagで社内へ公開する形で、より長く確保する
  25. リリースノート作成と通知の自動化 • コミット履歴からリリース対象チケットのタグ付けを自動化 ◦ パッケージ名にコミットのshaをいれ、diffに含まれるコミットメッセージからチ ケット名を抽出 • コンプライアンス上、各コミットにチケット名が入るのは必須になって いる •

    安易に手動のチェックリストを増やさない
  26. サービスクラスタ作成ツール • YAML 1枚書いてSlackにコマンドを書くと、クラスタができる ◦ SlackコマンドはAWS LambdaからPythonでAWS SDK (boto3) を叩く実装

    ◦ 現在のリソースとYAMLを比較し、必要な差分を作るようになっている ◦ ASG, Launch Config, Lifecycle Hook, ALB, Route53, CodeDeploy • 本番の作業と同じようにオンデマンドクラスタを作れる ◦ 開発中ブランチのテストやベンチマークに便利
  27. Terraform • オンデマンドクラスタに不要なリソースをTerraformで管理 ◦ 主に複数クラスタから共有されるリソース: IAM, Security Group, RDS, DynamoDB,

    Kinesis • モニターやアラートの定義も最近ほぼTerraform化された • 入社した時はこのあたりが大体手動管理だった
  28. CodeDeploy • S3にzipを置いて、各インスタンスのagentがpullしてシェルスクリプト がデプロイ ◦ 全台同時sshより安定する ◦ デプロイサーバーにあたる部分がマネージドなので便利 • 元々デプロイに使われていたChefの変わりに、mitamaeやChef

    Soloが使われることも
  29. ライフサイクルフック • 以前はインスタンス停止オペレーションは毎回手動だった • ローテーションの手間が増え、オートスケールの妨げになるので自 動化した ◦ ただし、48時間以内に強制停止されるので、それまでに安全に停止できるも のしか使えない

  30. オートスケール • ほぼ全てのサービスがAutoScalingグループを使っているので、 AutoScalingポリシーを設定するだけ ◦ APIベースのはALBのインスタンスあたりリクエスト数が一番安定する ◦ ワーカーベースのものはSQSベース ◦ 両方ハマらない時はCPUベースだが、外部依存の遅さやリトライでブロックし

    てる時にスケールアウトされない • キャパシティプランニングの労力やスケーリングの手間が軽減
  31. AMIの自動更新 • SREが全サービス向けのAMIをメンテナンス、結合テストが通ったら リリース • サービスによってはAMIを自動更新し、AutoScalingグループのMax Instance Lifetimeで自動ローテーション • システムライブラリの定期更新のために手動ローテーションすること

    がほぼなくなった
  32. デプロイの高速化

  33. なぜデプロイは速くなくてはならないか • モニタリングしなければいけない時間が長くなる • ロールバックにかかる時間が長くなり、障害のインパクトを大きくして しまう

  34. CodeDeploy: Traffic Controlは必要か • ALBのBlock/Allow TrafficがCodeDeployのボトルネックになる • とはいえ、サーバーのgraceful restartは意図しない状態が残りがち なので避ける

    • 適当に停止してデプロイ中意図的に502を出すことによって、クライ アントがリトライを適切にしているかのテストになる
  35. CodeDeploy: ALBヘルスチェック/タイムアウト変更 • Block/Allow Trafficにかかる最低時間はヘルスチェックやタイムア ウトの設定で決まる • 必要以上に安全にしようとすると、時間を浪費することになる

  36. CodeDeploy: 同時デプロイ割合の変更 • In-placeデプロイの場合、大きなクラスターでOneAtATimeデプロイ をすると時間がかかる • HalfAtATimeを利用したり、最大25%や10%デプロイするカスタム設 定を用意する

  37. CodeDeploy: Blue-Greenデプロイ • そもそもIn-placeデプロイは途中台数が少なくなったり、サーバーの 状態が使い回しになるのが不便 • Blue-Greenデプロイなら、台数を減らさずデプロイ可能 • AutoScalingグループの名前がデプロイの度に変わることに対応が 必要

  38. 今後の課題

  39. 結合テストのfalse positive/negative減らし • リリースの待ち時間を最小にするために、以下を両方減らす必要が ある ◦ false positive: 外部依存や外的要因による、actionableでないテスト失敗 ◦

    false negative: 書かれていないテストや、関連しているがリリース前確認に含 まれないテスト
  40. インターナルな結合テストの自動実行 • 自動でkickする結合テストは基本CircleCI上で行なっている • ストレージ最適化など、インターネット越しに観測が難しいテストはそ れが使えない ◦ 結合テストシステム自体はあるが、自動でkickしないと手動オペレーション増 加に繋がる

  41. デプロイツールのメンテコスト改善 • 自社デプロイツールのメンテコストが高い ◦ なるべくコミュニティが使うツールに寄せ、自社独自要件のみ実装するようにす る • 議論されたアイデア: ◦ Terraformだけでは達成できない要件も、Terraformを薄くラップして実現

    ◦ その他OSSのデプロイツール (Spinnakerなど) を利用
  42. AWS Lambda, KDA, EKSへのリリース自動化 • 一番スタンダードなデプロイ方法しか自動化できていない ◦ ほとんどのサービスはEC2 AutoScaling Groupにデプロイしているため

    • デプロイ基盤の整備具合から、新サービスのインフラに妥協が入る ことも ◦ CodeDeployにdocker saveしているものは、EKSの方が楽にデプロイでき、リ ソースも柔軟にコントロールできるようになる
  43. まとめ • リリースの安全性確保が第一 • あとは好きに自動化・高速化し、たくさんリリースする ◦ 高速な価値提供だけでなく、リリースの低リスク化にも繋る