チームがデプロイをリリースした後、本当にスピードアップしているのか、それとも単に忙しくなっているだけなのか疑問に思ったことがあるなら——DORAメトリクスがその答えです。この4つの指標を追跡することで、どのDevOpsチームも継続的改善を具体的かつ再現性のある方法で計測できます。難しいのは数値を集めることではありません。すでに積み上がったバックログに余計な作業を増やさずに、数値を収集して活用する方法を見つけることです。
DORA(DevOps Research and Assessment)は、数千の組織にわたってソフトウェアデリバリーのパフォーマンスを一貫して予測する4つのメトリクスを特定しました:
- デプロイ頻度 — コードが本番環境に届く頻度
- 変更のリードタイム — 最初のコミットから本番デプロイまでの時間
- 平均復旧時間(MTTR) — 本番障害からの復旧速度
- 変更失敗率(CFR) — インシデントを引き起こすデプロイの割合
エリートチームは1日に複数回デプロイし、リードタイムと復旧時間はいずれも1時間未満、変更失敗率は15%未満に保っています。ほとんどのチームは「中程度」(週次デプロイ、数日のリードタイム)と「高パフォーマー」の間のどこかに位置しています。現時点でチームに適した計測アプローチはどれでしょうか?それはチームの規模、ツール環境、そしてセットアップにかける手間への許容度次第です。
DORAメトリクスを計測する3つのアプローチ
アプローチ1:スプレッドシートによる手動追跡
最も手間がかからず、ツールコストもゼロです。チームは各本番デプロイを記録し、インシデントの開始・終了時刻を記録し、デプロイとコミット範囲を共有スプレッドシートに紐付けます。4つのメトリクスはスプリントごとまたは四半期ごとのレトロスペクティブで手動計算します。自動化は不要——関係者全員の一貫した規律があればOKです。
アプローチ2:CI/CDパイプラインスクリプト
既存のパイプライン(GitHub Actions、GitLab CI、Jenkins)を計装して、各デプロイ時に構造化されたイベントを出力します。デプロイ成功時にスクリプトがトリガーされ、タイムスタンプとコミットSHAをログに記録します。PagerDutyのWebhookまたは手動入力で補完される別のインシデントログでMTTRを追跡します。軽量スクリプトで集計し、必要に応じてGrafanaやDatadogにメトリクスをプッシュします。
アプローチ3:専用DORAプラットフォーム
Sleuth、LinearB、Faros AIなどのツールは、GitHub/GitLab、デプロイツール(Argo CD、Heroku、ECS)、インシデントトラッカー(PagerDuty、OpsGenie)に直接接続します。4つのDORAメトリクスすべてが自動計算され、トレンドダッシュボードも提供されます。スクリプト不要です。Sleuthは小規模チーム向けに無料枠を提供しており、LinearBとFaros AIは開発者シート単位での料金体系です。
各アプローチのメリット・デメリット
手動追跡
- ✅ セットアップコストゼロ、初日から使える
- ✅ ツール依存もベンダー契約も不要
- ❌ 5〜6人を超えると信頼性が低下する
- ❌ データ品質はチームの規律に完全依存
- ❌ リアルタイムの可視性なし——誰かがスプレッドシートを更新したときのみ数値を確認できる
CI/CDパイプラインスクリプト
- ✅ 自動化された一貫性のあるデータ収集
- ✅「本番デプロイ」の定義を完全にコントロールできる
- ✅ チームが既に使用しているダッシュボードと統合できる
- ❌ 初期エンジニアリング投資として数時間が必要
- ❌ MTTRには別途インシデント管理の仕組みが必要
専用プラットフォーム
- ✅ 最小限のセットアップで、すぐにリッチなダッシュボードが利用可能
- ✅ デプロイとインシデントを自動的に関連付け
- ❌ ベンダーロックインとスケール時のシート単位コスト
- ❌ 非標準のデプロイワークフローへの柔軟性が低い
推奨セットアップ
2〜10名のエンジニアで始めたばかりのチームには、CI/CDパイプラインアプローチをお勧めします。午後一つでセットアップできる軽さで、新たなSaaSサブスクリプションも不要、自分たちが所有する正確な自動データが得られます。まずはデプロイ頻度とリードタイムから始めましょう——最も自動化しやすく、プロセスが正しい方向に向かっているかどうかをすぐに把握できます。
15名以上のエンジニアがいる場合、またはPagerDutyやOpsGenieをすでにインシデント管理に使用している場合は、Sleuth(無料枠あり)またはLinearBの評価をお勧めします。デプロイとインシデントを手動で関連付ける手間が省ける分の時間で、通常は最初の1か月以内にサブスクリプション費用の元が取れます。
実装ガイド
1. デプロイ頻度 — 本番デプロイすべてにタグを付ける
パイプライン内の各本番デプロイにタイムスタンプ付きのgitタグを作成します。ローリングウィンドウでそれらのタグをカウントすることで、曖昧さなく、追加ツールなしでデプロイ頻度を把握できます。
# CI/CDデプロイジョブに追加する(GitHub Actions、GitLab CIなど)
git tag "deploy-prod-$(date +%Y%m%d-%H%M%S)"
git push origin --tags
# 過去30日間の本番デプロイ数をカウントする(ローカルまたはcronジョブで実行)
CUTOFF=$(date -d '30 days ago' +%Y%m%d 2>/dev/null || date -v-30d +%Y%m%d)
git tag --list 'deploy-prod-*' | while read tag; do
tag_date=$(echo "$tag" | grep -oP '\d{8}')
[[ "$tag_date" -ge "$CUTOFF" ]] && echo "$tag"
done | wc -l
2. 変更のリードタイム — コミットから本番デプロイまで
リードタイムは、開発者がコミットをプッシュしてから本番環境に届くまでの時間差を計測します。このPythonスクリプトは、連続する2つのデプロイタグ間の平均リードタイムを計算します。prev_deploy_tagを渡すとコミット範囲を正確に絞り込めます。省略した場合はそのタグの直前30コミットにフォールバックします。
import subprocess
import datetime
def calculate_lead_time(deploy_tag: str, prev_deploy_tag: str = None) -> float:
"""デプロイに含まれるコミットの平均リードタイムを時間単位で返す。"""
deploy_ts = subprocess.run(
["git", "log", "-1", "--format=%aI", deploy_tag],
capture_output=True, text=True
).stdout.strip()
deploy_time = datetime.datetime.fromisoformat(deploy_ts)
if prev_deploy_tag:
commit_range = f"{prev_deploy_tag}..{deploy_tag}"
else:
commit_range = f"{deploy_tag}~30..{deploy_tag}"
commits = subprocess.run(
["git", "log", commit_range,
"--first-parent", "--format=%aI"],
capture_output=True, text=True
).stdout.strip().split('\n')
durations = []
for ts in commits:
if not ts:
continue
commit_time = datetime.datetime.fromisoformat(ts)
hours = (deploy_time - commit_time).total_seconds() / 3600
durations.append(hours)
return sum(durations) / len(durations) if durations else 0.0
tag = "deploy-prod-20260601-143000"
prev_tag = "deploy-prod-20260531-110000"
print(f"{tag} のリードタイム: {calculate_lead_time(tag, prev_tag):.1f} 時間")
3. MTTR — 復旧時間のログと計算
インシデントのシンプルなJSONログを管理します。各エントリにはインシデントの開始時刻と解決時刻を記録します。インシデント終了後に、オンコールエンジニアがresolved_atのタイムスタンプを入力します。
[
{
"id": "INC-042",
"started_at": "2026-05-20T09:15:00",
"resolved_at": "2026-05-20T10:02:00",
"triggered_by_deploy": "deploy-prod-20260520-091000"
}
]
import json
from datetime import datetime
def calculate_mttr(incidents_file: str) -> float:
"""インシデントの平均復旧時間を分単位で返す。"""
with open(incidents_file) as f:
incidents = json.load(f)
times = [
(datetime.fromisoformat(inc["resolved_at"]) -
datetime.fromisoformat(inc["started_at"])).total_seconds() / 60
for inc in incidents
]
return sum(times) / len(times) if times else 0.0
print(f"MTTR: {calculate_mttr('incidents.json'):.0f} 分")
4. 変更失敗率 — GitHub Actions連携
ワークフローイベントを通じて失敗したデプロイを自動的に追跡します。「失敗」を事前に明確に定義しておきましょう:ロールバックが必要になったデプロイ、インシデントを引き起こしたデプロイ、または1時間以内にホットフィックスが必要になったデプロイがカウントされます。ここが曖昧だと数値が歪みます。
# .github/workflows/record-deploy.yml
name: デプロイメトリクスの記録
on:
workflow_run:
workflows: ["Deploy to Production"]
types: [completed]
jobs:
record:
runs-on: ubuntu-latest
steps:
- name: デプロイ結果のログ
run: |
STATUS="${{ github.event.workflow_run.conclusion }}"
SHA="${{ github.event.workflow_run.head_sha }}"
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo "${TIMESTAMP},${STATUS},${SHA}" >> deployments.csv
- name: 変更失敗率の計算
run: |
TOTAL=$(wc -l < deployments.csv)
FAILED=$(grep -c ",failure," deployments.csv || true)
echo "総デプロイ数: $TOTAL"
echo "失敗数: $FAILED"
awk "BEGIN {printf \"変更失敗率: %.1f%%\\n\", $FAILED * 100 / $TOTAL}"
注意: deployments.csvはランナーの一時ファイルシステムに書き込まれるため、ワークフロー実行間で保持されません。信頼性の高い履歴追跡を行うには、各実行後にワークフローアーティファクトとしてアップロードするか、S3バケット、Postgresテーブル、または毎回コミットバックされるGitHubリポジトリファイルなどの外部ストアにデータを書き込んでください。
メトリクスを実際に活かすために
メトリクスを収集することは仕事の半分に過ぎません——それに基づいて行動することこそ、多くのチームが行き詰まるポイントです。四半期ごとに1つのメトリクスを選んで積極的に改善しましょう。リードタイムが3日の場合、それがレバーです。すべてを同時に修正しようとするのではなく、PRレビューのターンアラウンド、テストスイートの実行時間、パイプラインのボトルネックを一つずつ見ていきましょう。
DORAメトリクスは何を修正すべきかを教えてくれるのではなく、どこを見るべきかを教えてくれます。チーム拡大後に変更失敗率が上昇していれば、オンボーディングとコードレビュープロセスのギャップを示しています。「高速で進んでいる」スプリント中にデプロイ頻度が停滞していれば、リリースパイプラインに隠れた摩擦があるサインです。
シンプルに始めましょう:今日から本番デプロイにタグを付け、直近5回のリリースでリードタイムスクリプトを実行すれば、週末までに4つのメトリクスのうち2つが稼働します。次のスプリントでインシデントログを追加しましょう。最初の30日間で収集したデータは、ほぼ確実にそれまで追跡していなかった1〜2個の明らかな改善点を浮かび上がらせます——それこそがまさに目的です。

