見出し画像

GoogleCloudPlatform/fourkeys を使って Four Keys を計測する

こんにちは。 Showcase Gig の EM dai です。 本エントリは、 Showcase Gig Advent Calendar 2022 並びに、 Engineering Manager Advent Calendar 2022 の10日目の記事です。

本エントリでは、 Showcase Gig のエンジニアリング組織でも利用している GoogleCloudPlatform/fourkeys を使用して、 Four Keys を計測する方法を紹介します。

Four Keys とは

Four Keys とは、 DevOps Research and Assessment (DORA) が提唱したソフトウェア開発チームのパフォーマンスを計測する4つの指標です。 Four Keys 指標を用いることで、ソフトウェアデリバリの「スピード」と「安定性」を測定できます。

  • デプロイの頻度: 本番環境にリリースする頻度

  • 変更のリードタイム: コードの変更がコミットされてから本番環境稼働までの所要時間

  • 変更障害率: デプロイが原因となり本番環境で障害が発生する割合

  • サービス復元時間: 本番環境での障害から復旧までにかかる時間

また、 Accelerate State of DevOps 2021 では、5つ目の指標として「信頼性」が追加され、「Software Delivery and Operational (SDO) Performance」と呼ばれています。

GoogleCloudPlatform/fourkeys を使う

GoogleCloudPlatform/fourkeys は、 Four Keys を簡単に計測できるようにするためのツールです。 2022年11月22日に、 Version 1.0.0 がリリースされました 🎉

ツールの構成は以下のとおりで、コミットなどの各種イベントを収集して、ダッシュボードに表示します。

  1. GitHub などのイベントを Webhook でイベントハンドラに送信する。

  2. イベントハンドラはすべてのイベントを Pub/Sub にパブリッシュする。

  3. Pub/Sub から Cloud Run にパブリッシュされた後、軽いデータ変換をして BigQuery にデータを登録する

  4. BigQuery でデータ変換をして、 Grafana のダッシュボード表示する

ダッシュボードは、次のような表示になります。

各項目の見方は次ようになります。収集した各種イベントをもとに、 Four Keys が可視化されています。

セットアップする

Installation guide に従ってセットアップを行います。

諸設定をして terraform apply を実行したら GCP のセットアップ完了です。簡単ですね。

続いて、イベントの通知設定をします。 GoogleCloudPlatform/fourkeys は、いくつかのツールを連携できます。 本稿では、 GitHub と連携してみましょう。

イベントを収集したいリポジトリの Webhooks にイベントハンドラの URL とシークレットを設定します。それぞれの値は、以下のコマンドで取得できます。

$ export PROJECT_ID="YOUR_PROJECT_ID"
$ gcloud run services list --project $PROJECT_ID | grep event-handler | awk '{print $4}'
$ gcloud secrets versions access 1 --secret=event-handler --project $PROJECT_ID

Webhook からはすべてのイベントを通知するように設定しましょう。

Webhook の設定

GitHub でイベントが発生( push, create issue など )すると、次のようなデータが BigQuery に登録されます。 なお、 Installation guide に記載の Generating mock data を実行することで、各種イベントのモックデータ作成もできます。

events_row テーブル

deployment を収集する

GoogleCloudPlatform/fourkeys は、 commit から deploy までのリードタイムを計測します。 したがって、 commit id に紐づく deployment を収集しなければなりません。

GitHub では、 Deployments API を使用して、 deployment を収集できます。

Deployments API は、特定の ref (ブランチ、SHA、タグ)を deployment event にディスパッチします。 これにより、 GoogleCloudPlatform/fourkeys で commit から deploy までのリードタイム、および障害率などがトレースできます。

Deployments API のフロー

deployment ツールから Deployments API をコールすることで、 Create Deployment します。 ほかにも、 GitHub Actions で特定ブランチがマージされたら Deployments API をコールすることで Create Deployment もできるので、環境に合わせて設定しましょう。

incident を収集する

incident の収集は、 GitHub Issues を用います。

Incident というラベルを付けた issue が、 incident イベントとして扱われます。 また、issue 本文に障害の原因となった commit id を書き込むことで、どの deploy によって障害が発生したかをトレースできるのです。 commit id は、以下のフォーマットで issue の本文、あるいはコメントに入力します。

root cause: {SHA of the commit}
root cause を書き込まないと changes に hash が入らない
root cause を書き込むと changes に hash が入る

issue を close すると、 incident が解消したとマークされます。

issue close の時刻が time_resolved に登録される

以上をまとめると、 GoogleCloudPlatform/fourkeys における incident 管理プロセスは次のような運用が必要になるでしょう。

  1. incident 発生: GitHub Issue を作成する

  2. incident 原因特定: 障害が入り込んだcommit idを、Issueの本文に記載する

  3. incident 復旧: GitHub Issue をクローズする

Grafana dashboard

ダッシュボードは Grafana を使用します。

fourkeys-grafana-dashboard というダッシュボード用の Cloud Run が構築されているので、エンドポイントにアクセスすると次のようなダッシュボードが表示されます。

Grafana の認証

デフォルトでは、 Grafana には認証がかかっていません。 認証を設定するには、 dashboard ディレクトリにある grafana.ini を編集します。

たとえば、 GSuite で認証する場合は次のようになるでしょう。

[server]
root_url = https://<your-grafana-endpoint>

[security]
cookie_secure = true

[auth.google]
enabled = true
client_id = CLIENT_ID
client_secret = CLIENT_SECRET
scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
auth_url = https://accounts.google.com/o/oauth2/auth
token_url = https://accounts.google.com/o/oauth2/token
allowed_domains = mycompany.com mycompany.org
allow_sign_up = true

repository をフィルタする

GoogleCloudPlatform/fourkeys は、複数の repository を管理できますが、ダッシュボードで出し分けができません。 この問題は、 Support multiple teams #281 でも議論されていますが、まだ解決にはいたっていません。

そこで、ダッシュボードを表示するクエリを改修して、 repository のフィルタを作ってみましょう。 まず、ダッシュボードの設定からフィルタと変数を設定します。

repository をフィルタするための変数を設定
repository のフィルタ

設定した変数をクエリに反映します。クエリはすべてで6つあるので、 Lead Time to Change Bucket を例にします。 repository の情報は events_raw にしかないため、結合してからフィルタをかけます。

WITH repo_data AS (
  SELECT
    id, SAFE.PARSE_JSON(metadata) AS github_json 
  FROM `four_keys.events_raw`
  WHERE `event_type` = 'deployment_status' 
)

SELECT 
 CASE
  WHEN median_time_to_change < 24 * 60 then "One day"
  WHEN median_time_to_change < 168 * 60 then "One week"
  WHEN median_time_to_change < 730 * 60 then "One month"
  WHEN median_time_to_change < 730 * 6 * 60 then "Six months"
  ELSE "One year"
 END as lead_time_to_change
FROM (
 SElECT
  IFNULL(ANY_VALUE(med_time_to_change), 0) AS median_time_to_change
 FROM (
   SELECT
   PERCENTILE_CONT(
    IF(TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) > 0, TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE), NULL), # Ignore automated pushes
    0.5) # Median
    OVER () AS med_time_to_change, # Minutes
  FROM four_keys.deployments d, d.changes
  LEFT JOIN four_keys.changes c ON changes = c.change_id
  WHERE d.time_created > TIMESTAMP(DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH))
  AND d.deploy_id IN (SELECT repo_data.id FROM repo_data WHERE JSON_VALUE(github_json.repository, '$.name') IN ($repositories)) # ripository filter
 )
)

environment をフィルタする

Create Deployment は、 environment ごとにデータを分かれています。一般に、 production や staging などの環境ごとに deploy を行うことが多いでしょう。 これをフィルタしないと、 staging での deploy が production に影響を与えてしまいます。

先程のクエリに、 environment のフィルタを追加します。

WITH repo_data AS (
  SELECT
    id, SAFE.PARSE_JSON(metadata) AS github_json 
  FROM `four_keys.events_raw`
  WHERE `event_type` = 'deployment_status' 
)

SELECT 
 CASE
  WHEN median_time_to_change < 24 * 60 then "One day"
  WHEN median_time_to_change < 168 * 60 then "One week"
  WHEN median_time_to_change < 730 * 60 then "One month"
  WHEN median_time_to_change < 730 * 6 * 60 then "Six months"
  ELSE "One year"
 END as lead_time_to_change
FROM (
 SElECT
  IFNULL(ANY_VALUE(med_time_to_change), 0) AS median_time_to_change
 FROM (
   SELECT
   PERCENTILE_CONT(
    IF(TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) > 0, TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE), NULL), # Ignore automated pushes
    0.5) # Median
    OVER () AS med_time_to_change, # Minutes
  FROM four_keys.deployments d, d.changes
  LEFT JOIN four_keys.changes c ON changes = c.change_id
  WHERE d.time_created > TIMESTAMP(DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH))
  AND d.deploy_id IN (
   SELECT repo_data.id FROM repo_data 
   WHERE JSON_VALUE(github_json.deployment_status, '$.environment') = "production" 
   AND JSON_VALUE(github_json.repository, '$.name') IN ($repositories)
  ) # repository filter and environment filter
 )
)

これで、 repository と environment のフィルタができました。

dashboard を更新する

最後に、ダッシュボードを更新します。 Grafana は Cloud Run で動作しており、データは保存されません。 そのため、 dashbord/fourkeys_dashboard.json を更新して、再度 deploy します。 この deploy によって、 grafana.ini も更新されます。

詳細な手順は以下を参照ください。

さいごに

これで GoogleCloudPlatform/fourkeys の設定ができました 🎉

 2019 State of DevOps Report では、ハイパフォーマンス組織(Elite)の Four Keys が公開されています。 Elite 組織を目標値として、 Four Keys の値を改善するという運用もできるでしょう。

GoogleCloudPlatform/fourkeys は、 Version 1.0.0 もリリースされたので、今後の更新も楽しみですね!

この記事が気に入ったらサポートをしてみませんか?