Slide 1

Slide 1 text

fourkeys基盤を構築した話 Kyash TechTalk #4 - Serversideと新しい挑戦 2022-09-12 @uncle__ko

Slide 2

Slide 2 text

自己紹介 kohei ouchi(@uncle__ko) 主にお金周りのシステムを作ってた 今はTechチームの生産力向上のために頑 張ってる プライベートでは5歳児のパパとして育児に励 んでる

Slide 3

Slide 3 text

Agenda ● 生産性の可視化 ● fourkeys基盤の概要 ● デプロイ頻度の計測 ● リードタイムの計測 ● Incident flowの整備 ● incidents view ● merged_pull_requests view ● 変更障害率の計測 ● サービス復元時間の計測 ● さいごに

Slide 4

Slide 4 text

生産性の可視化

Slide 5

Slide 5 text

そもそもなんで計測するの? KyashのTechチームでは生産力を3倍にするという目標を置いてる Techチームの価値は、最終的に「世の中=ユーザ」に何を届けたかだと思っている 技術的負債の解消、Incident件数の含めて生産力を上げていく 3倍にするにあたり、現状の課題や生産性を可視化する必要があると考えた

Slide 6

Slide 6 text

そもそもなんで計測するの? 計測するにあたり指標をどうするかを考えfourkeysを採用した 理由は下記 ● 定量的に計測できる ○ 定義を明確にすれば計測できる ● 世の中の水準で現状を評価できる ○ Google Cloudで実行されているDevOps組織の有効性を評価する にもあるように、それぞれの KeyごとにElite、High、Medium、Lowの4レベルで評価できる ● 自動化できる ○ GitHubやSlack、CircleCI等のAPIを使って自動計測が可能

Slide 7

Slide 7 text

Google Cloud で実行されている DevOps 組織の有効性を評価する より引用

Slide 8

Slide 8 text

計測対象 fourkeysのそれぞれの定義は各社・各Teamで決めてよいとされてるが、Kyashでは DORA(DevOps Research and Assessment)に合わせて下記のように定義してる 指標 概要 デプロイ頻度 組織による正常な本番へのリリース頻度 変更のリードタイム commitから本番環境稼働までの所要時間 変更障害率 デプロイが原因で本番環境で障害が発生する割合 (%) サービス復元時間 組織が本番環境での障害から回復するのに掛かる時間

Slide 9

Slide 9 text

詳しくはBlogを書いてるので、興味があれば読んでみてください https://blog.kyash.co/entry/2022/06/15/170000 そもそもなんで計測するの?

Slide 10

Slide 10 text

fourkeys基盤の概要

Slide 11

Slide 11 text

fourkeysの概要 Kyashでは https://github.com/GoogleCloudPlatform/fourkeys をforkして使っている 理由は下記 ● GCPのfourkeysが普通にイケてる ● GitHub,CircleCi,Tekton,Cloud Build,PagerDutyのイベントハンドリング処理がす でに用意されている ● Terraform管理されてる ● あまり工数を掛けずに自分たちで構築できそうであった

Slide 12

Slide 12 text

アーキテクチャ

Slide 13

Slide 13 text

Dashboard

Slide 14

Slide 14 text

あえてイケてないところをあげるなら ● 比較的あたらしいRepoなので小さなバグは多い ● チームメンバー含めてPRを5つくらい上げてるけど反応が遅い ● 今はShell Scriptとterraform二つ使っているが、terraform側に寄せようとしてい る?ようで、今後大きな変更が入る可能性が高い

Slide 15

Slide 15 text

デプロイ頻度の計測

Slide 16

Slide 16 text

デプロイ頻度の計測 デプロイ頻度とは本番環境へリリースした回数 以下の条件に合致するのもをデプロイと判断 ● branchがmain or master ● job名(GitHubActionsの場合はcheck_run.name、CircleCIの場合はjob.name)に Deploy or deployが含まれている

Slide 17

Slide 17 text

deployments View スキーマはこんな感じ

Slide 18

Slide 18 text

Query SELECT TIMESTAMP_TRUNC(time_created, DAY) AS day, COUNT(distinct deploy_id) AS deployments FROM four_keys.deployments GROUP BY day;

Slide 19

Slide 19 text

過去分のイベント 過去分のイベントが取れると生産性が上がりましたと言いやすい トランクベース開発はすでに始まっていたりする 期間を指定すると、その期間内のデプロイをfetchしてBigQueryにinsertするGoの Scriptを作ったりもした

Slide 20

Slide 20 text

リードタイムの計測

Slide 21

Slide 21 text

リードタイムの計測 リードタイムとはcommitが本番環境にデプロイされるまでの時間の中央値 Mergeでのpushイベントに、そのpushに含まれるcommit配列がある。それぞれの commitのpushした時刻との 差を取ればいい pushイベントのcommitsとはなにか? ● https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-paylo ads#push なので、deployments.changesにあるcommitはmainへのmerge用PRに出てくるdiffのcommitと同じ

Slide 22

Slide 22 text

changes View スキーマはこんな感じ

Slide 23

Slide 23 text

SELECT day, IFNULL(ANY_VALUE(med_time_to_change)/60, 0) AS median_time_to_change, # Hours FROM ( SELECT d.deploy_id, TIMESTAMP_TRUNC(d.time_created, DAY) AS day, PERCENTILE_CONT( # Ignore automated pushes IF(TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) > 0, TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE), NULL), 0.5) # Median OVER (PARTITION BY TIMESTAMP_TRUNC(d.time_created, DAY)) AS med_time_to_change, # Minutes FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.changes c ON changes = c.change_id ) GROUP BY day ORDER BY day; Query

Slide 24

Slide 24 text

Incident Flowの整備

Slide 25

Slide 25 text

KyashではwikiツールとしてKibelaを使っている https://kibe.la/ incidentはもともとKibelaにまとめられていた GoogleCloudPlatform/fourkeysはGitHub/GitLab/PagerDutyに対応してる Kibelaもparserさえ作れれば対応自体はできる が、KibelaのAPIでは更新された場合を考えると少し貧弱であったためGitHubのIssue にしたかった Incident Flowの整備

Slide 26

Slide 26 text

なにをしたのか 有識者を集めてIncidentフローにGitHub Issueをいれたい もしくは自動計測しやすいなにかにしたい旨のMTGを開催 理想はGitHub Issueへの統一だったが、Engineer以外がGitHubのアカウントをもって いないこともありKibelaに概要を、詳細はGitHub Issueにまとめる運用になった

Slide 27

Slide 27 text

実際に作ったIssue Template Kyash/incidentというIncident管理用のRepoを作成

Slide 28

Slide 28 text

実際に作ったIssue Template

Slide 29

Slide 29 text

incidents View

Slide 30

Slide 30 text

incidents View view自体はevents_rowから下記条件で取得 - sourceがgithub - repoがKyash/incident - actionがclose 正規表現で時刻やPRを習得している

Slide 31

Slide 31 text

incidents View 一応ReOpenの考慮も入れている マイクロサービスごとに集計するためにincident issueにlabelでマイクロサービス名を付 与してもらう運用 from句で下記のようなことをしたり select句でこんなことしたりしてる

Slide 32

Slide 32 text

incidents View スキーマはこんな感じ

Slide 33

Slide 33 text

merged_pull_requests View

Slide 34

Slide 34 text

merged_pull_requests View 本家ではIssueの中に原因となったcommit hashを含めよ的なノリ https://github.com/GoogleCloudPlatform/fourkeys/blob/main/queries/incidents.sql# L25 しかし、IncidentがIssueとKibelaに別れて面倒になってるのにcommit hashまで取って くるのはさすがに... 原因になったPRのリンクだけ貼ってもらいcommit hashは別途たどるために本家には ないviewを追加

Slide 35

Slide 35 text

merged_pull_requests View # Merged Pull Request Table SELECT JSON_EXTRACT_SCALAR(metadata, '$.pull_request.html_url') AS url, PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%SZ',JSON_EXTRACT_SCALAR(metadata, '$.pull_request.created_at')) AS time_created, PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%SZ',JSON_EXTRACT_SCALAR(metadata, '$.pull_request.merged_at')) AS time_merged, JSON_EXTRACT_SCALAR(metadata, '$.pull_request.merge_commit_sha') AS commit_sha, JSON_EXTRACT_SCALAR(metadata, '$.pull_request.base.repo.name') AS repository FROM `four_keys.events_raw` WHERE source = 'github' AND event_type = 'pull_request' AND json_extract_scalar(metadata, '$.pull_request.merged') = 'true' AND json_extract_scalar(metadata, '$.action') = 'closed' GROUP BY 1,2,3,4,5

Slide 36

Slide 36 text

merged_pull_requests View スキーマはこんな感じ

Slide 37

Slide 37 text

変更障害率の計測

Slide 38

Slide 38 text

変更障害率の計測 本家はcommit単位で計測している が、現状のKyashには明確なcommit単位の基準が存在しないので人によってブレる可 能性がある そのためKyashではDeploy単位での集計とした (incident数)/(本番へのdeploy数)

Slide 39

Slide 39 text

Query SELECT TIMESTAMP_TRUNC(d.time_created, DAY) as day, IF(COUNT(DISTINCT d.deploy_id) = 0, 0, SUM(IF(i.incident_id is NULL, 0, 1)) / COUNT(DISTINCT d.deploy_id)) as change_fail_rate, d.repository as metric, FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.merged_pull_requests m ON changes = m.commit_sha and m.repository = d.repository LEFT JOIN four_keys.incidents i ON i.cause_pr_url = m.url GROUP BY day, d.repository ORDER BY day

Slide 40

Slide 40 text

サービス復元時間の計測

Slide 41

Slide 41 text

サービス復元時間の計測 サービス復元時間とは障害の発生時間から収束時間までの中央値 この発生時間から収束時間というのは機械的に計測できる場合もあるが、パターンに よっては難しい場合もある(PRに起因してない障害等) そのため、Incidentレポート用のIssueに人の手で記載してもらう Incident IssueがCloseしたタイミングでIssueをParseして計測する

Slide 42

Slide 42 text

Query SELECT day, label as metric, daily_med_time_to_restore FROM ( SELECT TIMESTAMP_TRUNC(time_created, DAY) AS day, label, #### Median time to resolve PERCENTILE_CONT( TIMESTAMP_DIFF(time_resolved, time_created, HOUR), 0.5) OVER(PARTITION BY TIMESTAMP_TRUNC(time_created, DAY), label ) AS daily_med_time_to_restore, FROM four_keys.incidents, UNNEST(label_names) AS label ) GROUP BY day, label, daily_med_time_to_restore ORDER BY day

Slide 43

Slide 43 text

さいごに

Slide 44

Slide 44 text

さいごに やっと生産性を推測ではなく、計測できる状態が作れた GCPのfourkeysはイケてる部分が多いので、forkして自分たちに合うように微調整すれ ば使える 今後はこのfourkeys基盤をもとに分析していくフェーズ TryとしてSprintのはじめに分析する時間を設けるようにしている 可視化することで改めてわかってくることもある 推測ではなく計測した結果で生産性向上のための策を打っていく

Slide 45

Slide 45 text

ご清聴ありがとうございました