ストーリー
佐
佐藤CTO
50%ルールを達成するための最大の敵がある。それがトイル(Toil)だ
あなた
うちのSREチームの日報を分析した。手動デプロイ、証明書の更新、ログの手動確認、アカウント作成…全体の業務時間の70%が手作業で占められていた
あ
あなた
70%は多すぎますね。自動化すべき作業が山積みということですか
あ
佐
佐藤CTO
まさにそうだ。ただし、すべての手作業がトイルというわけではない。トイルの定義を正確に理解し、優先順位をつけて効率的に削減していこう
トイルの定義
トイルとは
トイルとは、以下の特徴を全て持つ作業のことです。
| 特徴 | 説明 | 例 |
|---|
| 手動的(Manual) | 人間が手作業で実施する | サーバーへの手動SSH、手動デプロイ |
| 繰り返し(Repetitive) | 同じ作業を何度も繰り返す | 毎週のログローテーション |
| 自動化可能(Automatable) | 原理的に自動化できる | 定期的なDB容量チェック |
| 戦術的(Tactical) | 長期的な価値を生まない | 一時的なフラグの切り替え |
| サービス成長に比例(O(n)) | サービスの拡大に伴い線形に増加 | 新規テナント追加時の手動設定 |
| 永続的な価値がない | 実施後に残る成果物がない | 手動での健全性チェック |
トイルではないもの
| 作業 | トイルか? | 理由 |
|---|
| オンコール対応 | 部分的にトイル | 調査はエンジニアリング、手動復旧はトイル |
| ドキュメント作成 | トイルではない | 永続的な価値がある |
| アーキテクチャ設計 | トイルではない | 創造的・戦略的 |
| 自動化ツールの開発 | トイルではない | トイルを削減するエンジニアリング |
| 1回限りの手動作業 | トイルではない | 繰り返しではない |
| ポストモーテムの実施 | トイルではない | 学びと改善という永続的な価値がある |
トイルの分類(タクソノミー)
カテゴリ別分類
graph TD
Title["トイルのカテゴリ"]
Title --- Deploy["デプロイ関連<br/>・手動デプロイ<br/>・手動ロールバック<br/>・設定変更"]
Title --- Infra["インフラ関連<br/>・サーバー設定<br/>・証明書更新<br/>・ディスク容量管理"]
Title --- Data["データ関連<br/>・手動DB移行<br/>・バックアップ確認<br/>・データ修正<br/>・レポート生成"]
Title --- Access["アクセス管理<br/>・アカウント作成/削除<br/>・権限変更<br/>・APIキー発行"]
Title --- Monitor["モニタリング<br/>・手動ログ確認<br/>・手動アラート対応<br/>・手動ヘルスチェック"]
Title --- Comm["コミュニケーション<br/>・ステータス報告<br/>・手動チケット更新<br/>・定例会議での手動<br/>ステータス収集"]
classDef title fill:#1a1a2e,stroke:#e94560,color:#fff
classDef category fill:#e94560,stroke:#c23050,color:#fff
class Title title
class Deploy,Infra,Data,Access,Monitor,Comm category
トイルの測定
測定方法
interface ToilEntry {
id: string;
description: string;
category: 'deploy' | 'infra' | 'data' | 'access' | 'monitoring' | 'communication';
timeSpentMinutes: number;
frequency: 'daily' | 'weekly' | 'monthly' | 'per_event';
occurrencesPerMonth: number;
automatable: boolean;
automationEffort: 'low' | 'medium' | 'high'; // 自動化の難易度
}
interface ToilReport {
totalToilHoursPerMonth: number;
totalWorkHoursPerMonth: number;
toilPercentage: number;
topToilItems: ToilEntry[];
automationCandidates: ToilEntry[];
}
function analyzeToil(entries: ToilEntry[], teamSize: number): ToilReport {
const totalWorkHoursPerMonth = teamSize * 160; // 月160時間/人
const entriesWithMonthlyHours = entries.map(entry => ({
...entry,
monthlyHours: (entry.timeSpentMinutes * entry.occurrencesPerMonth) / 60,
}));
const totalToilHours = entriesWithMonthlyHours.reduce(
(sum, e) => sum + e.monthlyHours,
0
);
const sorted = entriesWithMonthlyHours.sort(
(a, b) => b.monthlyHours - a.monthlyHours
);
const automationCandidates = sorted.filter(
e => e.automatable && e.monthlyHours > 2
);
return {
totalToilHoursPerMonth: totalToilHours,
totalWorkHoursPerMonth: totalWorkHoursPerMonth,
toilPercentage: (totalToilHours / totalWorkHoursPerMonth) * 100,
topToilItems: sorted.slice(0, 5),
automationCandidates,
};
}
トイル計測テンプレート
# トイル計測シート
team: "SRE Team"
period: "2026-01"
members: 4
toil_entries:
- description: "手動デプロイ作業"
category: deploy
time_per_occurrence: 30min
frequency: "1日3回"
monthly_occurrences: 66
monthly_hours: 33
automatable: true
automation_effort: medium
- description: "SSL証明書の更新"
category: infra
time_per_occurrence: 45min
frequency: "月4回"
monthly_occurrences: 4
monthly_hours: 3
automatable: true
automation_effort: low
- description: "新規ユーザーアカウント作成"
category: access
time_per_occurrence: 15min
frequency: "週5回"
monthly_occurrences: 20
monthly_hours: 5
automatable: true
automation_effort: low
- description: "手動ログ調査(インシデント以外)"
category: monitoring
time_per_occurrence: 20min
frequency: "1日2回"
monthly_occurrences: 44
monthly_hours: 14.7
automatable: true
automation_effort: high
# サマリー
summary:
total_toil_hours: 55.7
total_work_hours: 640 # 4人 × 160時間
toil_percentage: 8.7%
target_percentage: 5%
自動化戦略
自動化の優先順位付け
| 評価軸 | 重み | 説明 |
|---|
| 月間時間消費 | 高 | 最も時間を消費しているトイルを優先 |
| 自動化の容易さ | 中 | Quick Winを先に達成 |
| エラーリスク | 高 | 手動ミスが障害につながるものを優先 |
| スケーラビリティ | 中 | サービス成長で増加するものを優先 |
ROI計算
interface AutomationROI {
toilItem: string;
currentMonthlyHours: number;
automationDevelopmentHours: number;
maintenanceHoursPerMonth: number;
paybackMonths: number;
yearlyTimeSaved: number;
}
function calculateAutomationROI(
toilItem: string,
monthlyToilHours: number,
developmentHours: number,
monthlyMaintenanceHours: number = 1
): AutomationROI {
const monthlySaving = monthlyToilHours - monthlyMaintenanceHours;
const paybackMonths = developmentHours / monthlySaving;
const yearlyTimeSaved = monthlySaving * 12 - developmentHours;
return {
toilItem,
currentMonthlyHours: monthlyToilHours,
automationDevelopmentHours: developmentHours,
maintenanceHoursPerMonth: monthlyMaintenanceHours,
paybackMonths: Math.ceil(paybackMonths),
yearlyTimeSaved: Math.round(yearlyTimeSaved),
};
}
// 例: 手動デプロイの自動化
const deployAutomation = calculateAutomationROI(
'手動デプロイ作業',
33, // 月33時間のトイル
40, // CI/CDパイプライン構築に40時間
2 // 月2時間のメンテナンス
);
// paybackMonths: 2ヶ月で元が取れる
// yearlyTimeSaved: 332時間/年の節約
自動化のレベル
レベル0: 完全手動
└─ 手順書に従い人間が全ステップを実行
レベル1: 支援ツール
└─ スクリプトやツールが一部のステップを自動化
人間がトリガーし、結果を確認
レベル2: 半自動
└─ 人間が承認するだけで、残りは自動実行
ロールバックも自動
レベル3: 完全自動
└─ トリガーから完了まで全自動
人間は結果の通知を受けるだけ
レベル4: 自律的
└─ システムが自ら異常を検知し、自動で修復
人間の介入は不要
自動化の落とし穴と対策
| 落とし穴 | 説明 | 対策 |
|---|
| 自動化の過信 | 自動化したから安全と思い込む | 自動化自体の監視・テストを実施 |
| 複雑性の増大 | 自動化ツール自体が複雑になる | シンプルに保ち、段階的に改善 |
| 属人化の移動 | トイルの属人化が自動化ツールの属人化に | ドキュメントとコードレビュー |
| ROIの無視 | 自動化に時間をかけすぎる | ROI計算で投資対効果を確認 |
| メンテナンス負債 | 自動化ツールのメンテナンスが放置される | 定期的なレビューと更新 |
トイル削減の実践例
例1: SSL証明書の自動更新
# cert-manager による自動証明書管理
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: sre@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-tls
namespace: production
spec:
secretName: api-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- api.example.com
- "*.api.example.com"
renewBefore: 720h # 30日前に自動更新
例2: ユーザーアカウント管理の自動化
// セルフサービスAPI: ユーザーがSlackコマンドでアカウントを管理
import { SlackApp } from '@slack/bolt';
const app = new SlackApp({ token: process.env.SLACK_BOT_TOKEN });
app.command('/create-account', async ({ command, ack, respond }) => {
await ack();
const { text: targetService } = command;
const requestor = command.user_id;
// 承認フロー
const approval = await requestApproval({
requestor,
service: targetService,
approvers: await getServiceOwners(targetService),
});
if (approval.approved) {
// 自動アカウント作成
const account = await createServiceAccount({
service: targetService,
user: requestor,
role: 'developer',
expiresIn: '90d', // 90日で自動失効
});
await respond({
text: `アカウントを作成しました: ${account.username}\n有効期限: ${account.expiresAt}`,
});
// 監査ログ
await auditLog.record({
action: 'ACCOUNT_CREATED',
requestor,
target: targetService,
approvedBy: approval.approver,
});
}
});
まとめ
| ポイント | 内容 |
|---|
| トイルの定義 | 手動的・繰り返し・自動化可能・戦術的・O(n)・永続的価値なし |
| トイルの測定 | カテゴリ分類し、月間時間と比率を可視化する |
| 自動化の優先順位 | ROI計算で投資対効果が高いものから着手 |
| 自動化のレベル | 完全手動→支援ツール→半自動→完全自動→自律的 |
| 目標 | チーム全体のトイル比率を50%以下に維持する |
チェックリスト
次のステップへ
次は「演習:SRE原則を適用しよう」です。ここまで学んだSREの基本原則、信頼性メトリクス、エラーバジェット、トイル削減を実際のシナリオに適用してみましょう。
推定読了時間: 30分