SLO tracking, error budget calculation, and burn-rate alerting for Kubernetes services β built on the Google SRE workbook model. Runs as an in-cluster daemon or standalone CLI.
π Edit in Excalidraw β open the
.excalidrawfile at excalidraw.com to edit interactively.
Kubernetes Services
βββ api-service βββΊ Prometheus (scrape)
βββ auth-service βββΊ β
βββ ml-service βββΊ β PromQL queries
βΌ
SLO Manager
βββ evaluator.py (good/total events ratio)
βββ burn_rate.py (fast: 2% in 1h / slow: 5% in 6h)
βββ reporter.py (weekly Markdown/JSON report)
β
βββββββββββββ΄βββββββββββ
βΌ βΌ
Grafana Dashboard Slack / PagerDuty
(live error budget) (burn-rate alerts)
- What are SLOs and why this tool
- Quick Start (CLI)
- Deploy as In-Cluster Daemon
- Defining SLOs
- Burn Rate Alerts
- CLI Reference
- Grafana Dashboard
- PrometheusRule Integration
- Configuration Reference
- Extending SLO Types
- Troubleshooting
SLI (Service Level Indicator) β a quantitative measure of service behaviour. Example: ratio of HTTP requests returning 2xx.
SLO (Service Level Objective) β a target for an SLI. Example: 99.9% of requests return 2xx over a 30-day window.
Error Budget β how much unreliability you're allowed. A 99.9% SLO gives you 43 minutes of downtime per month. Spend it wisely.
Burn Rate β how fast you're spending the error budget. A burn rate of 1.0 means you'll exactly exhaust the budget by end of window. 14.4Γ means you'll exhaust it in 5% of the time (2 hours for a 30-day window).
This tool implements the multi-window burn-rate alert from Google's SRE Workbook Chapter 5:
| Alert | Window | Burn Rate | Budget consumed |
|---|---|---|---|
| Page (fast) | 1h + 5m | β₯ 14.4Γ | 2% in 1h |
| Page (slow) | 6h + 30m | β₯ 6Γ | 5% in 6h |
| Ticket | 3d + 6h | β₯ 3Γ | 10% in 3d |
| Warning | 3d + 6h | β₯ 1Γ | on track |
# Install
pip install k8s-slo-manager
# or from source:
git clone https://github.com/ashiq-ali/k8s-slo-manager
cd k8s-slo-manager && pip install -e .
# Point at Prometheus
export PROMETHEUS_URL=http://localhost:9090 # or your cluster Prometheus
# Check SLO status
slo status --config examples/slos.yaml
# Generate weekly error budget report
slo report --config examples/slos.yaml --output report.md
# Continuous monitoring (daemon mode)
slo daemon --config examples/slos.yaml --interval 60# 1. Create ConfigMap with your SLO definitions
kubectl create configmap slo-config \
--from-file=slos.yaml=examples/slos.yaml \
-n monitoring
# 2. Set Slack/PagerDuty credentials
kubectl create secret generic slo-alerts \
--from-literal=slack-webhook-url=https://hooks.slack.com/... \
--from-literal=pagerduty-routing-key=... \
-n monitoring
# 3. Deploy
kubectl apply -f k8s/deployment.yaml
# 4. Verify
kubectl logs -n monitoring deployment/slo-manager -fThe daemon evaluates all SLOs every 60 seconds, fires alerts when burn thresholds are crossed, and exposes metrics on :8080/metrics for Prometheus to scrape.
SLOs are defined in a YAML file. See examples/slos.yaml for full examples.
slos:
- name: api-availability
description: "API service returns 2xx for 99.9% of requests"
service: api-service
window_days: 30
target: 0.999 # 99.9%
indicator:
type: ratio
good_query: |
sum(rate(http_requests_total{service="api-service",code=~"2.."}[5m]))
total_query: |
sum(rate(http_requests_total{service="api-service"}[5m])) - name: api-latency-p99
description: "99th percentile latency under 500ms for 95% of requests"
service: api-service
window_days: 30
target: 0.95 # 95% of requests
indicator:
type: ratio
good_query: |
sum(rate(http_request_duration_seconds_bucket{
service="api-service",
le="0.5"
}[5m]))
total_query: |
sum(rate(http_request_duration_seconds_count{service="api-service"}[5m])) - name: ml-pipeline-success
description: "95% of ML pipeline runs complete successfully"
service: ml-pipeline
window_days: 7
target: 0.95
indicator:
type: ratio
good_query: |
sum(increase(pipeline_runs_total{status="success"}[5m]))
total_query: |
sum(increase(pipeline_runs_total[5m]))When a burn-rate threshold is crossed, the alerter fires:
Slack (fast burn β page-worthy):
π΄ CRITICAL: api-availability SLO burn rate alert
Service: api-service
Current burn rate: 18.3Γ (threshold: 14.4Γ)
Error budget remaining: 43% (17 days left in window)
At this rate, budget exhausted in: 1h 22m
Runbook: https://wiki.company.com/slo/api-availability
Slack (slow burn β ticket):
π‘ WARNING: api-latency-p99 SLO budget consumption
Service: api-service
Current burn rate: 4.1Γ (threshold: 3Γ)
Error budget remaining: 71%
Estimated exhaustion: 8 days 14 hours
Configure alert destinations in examples/slos.yaml:
alerting:
slack:
webhook_url: ${SLACK_WEBHOOK_URL}
channels:
critical: "#platform-oncall"
warning: "#platform-alerts"
pagerduty:
routing_key: ${PAGERDUTY_ROUTING_KEY}
severity_map:
fast_burn: critical
slow_burn: warning
ticket: infoslo status [--config PATH] [--service NAME] [--json]
Show current SLO compliance, error budget remaining, and burn rate
slo report [--config PATH] [--window DAYS] [--output PATH] [--format md|json]
Generate error budget report for the last N days
slo check [--config PATH] [--fail-on-breach]
Exit 1 if any SLO is breaching (useful in CI/CD gates)
slo daemon [--config PATH] [--interval SECONDS]
Run continuous evaluation loop
slo validate [--config PATH]
Validate SLO definitions and test PromQL queries
Example slo status output:
SLO Status Report (2024-01-15 14:32 UTC)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SERVICE TARGET CURRENT BUDGET LEFT BURN STATUS
api-availability 99.90% 99.94% 87.3% 0.58Γ β
OK
api-latency-p99 95.00% 96.12% 115.2% 0.0Γ β
OK
ml-pipeline-success 95.00% 92.11% 0.0% β π΄ BREACHING
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Import k8s/grafana-dashboard.json into Grafana. The dashboard shows:
- Error budget gauge β how much budget remains per SLO (color-coded green/amber/red)
- Burn rate graph β time-series of burn rate with alert threshold lines
- SLO compliance timeline β was the target met at each point in the window?
- Top error sources β breakdown of what's causing good-event failures
# Import via Grafana API
curl -X POST http://grafana:3000/api/dashboards/import \
-H "Content-Type: application/json" \
-d @k8s/grafana-dashboard.jsonk8s/prometheusrule.yaml creates Prometheus alerting rules for the multi-window burn rate model:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: slo-burn-rate-alerts
spec:
groups:
- name: slo.burn_rate
rules:
- alert: SloBurnRateFast
expr: |
(
slo:error_budget_burn_rate:1h > 14.4
and
slo:error_budget_burn_rate:5m > 14.4
)
for: 2m
labels:
severity: critical
annotations:
summary: "Fast burn rate detected for {{ $labels.slo }}"Apply with:
kubectl apply -f k8s/prometheusrule.yaml| Environment Variable | Default | Description |
|---|---|---|
PROMETHEUS_URL |
http://prometheus:9090 |
Prometheus server URL |
SLO_CONFIG_PATH |
slos.yaml |
Path to SLO definitions |
EVAL_INTERVAL_SECONDS |
60 |
How often to evaluate SLOs |
SLACK_WEBHOOK_URL |
β | Slack incoming webhook URL |
PAGERDUTY_ROUTING_KEY |
β | PagerDuty Events API v2 routing key |
REPORT_SCHEDULE |
0 9 * * 1 |
Weekly report cron (Monday 9am) |
LOG_LEVEL |
INFO |
DEBUG / INFO / WARNING / ERROR |
The evaluator.py base class is designed for extension:
from slo_manager.evaluator import SLOEvaluator
class CustomSLOEvaluator(SLOEvaluator):
def good_events(self, window_seconds: int) -> float:
# Query your custom data source
return my_custom_query(window_seconds)
def total_events(self, window_seconds: int) -> float:
return my_total_query(window_seconds)Built-in evaluator types: ratio, threshold, windowed_mean
PromQL query returned no data
Verify the query works directly in Prometheus:
curl 'http://prometheus:9090/api/v1/query' \
--data-urlencode 'query=sum(rate(http_requests_total[5m]))'If it returns nothing, the metric may not exist or the label selectors are wrong.
Burn rate shows inf or nan
This means total events is zero β no traffic to the service. The burn rate is mathematically undefined. SLO Manager will show N/A rather than alerting.
Error budget shows > 100%
This is correct and expected β it means the SLI is performing better than the target. A budget of 115% means you have a 15% surplus.
Alert fired but Slack message not received
kubectl logs -n monitoring deployment/slo-manager | grep -i slack
# Test the webhook manually:
curl -X POST $SLACK_WEBHOOK_URL \
-H 'Content-type: application/json' \
--data '{"text":"SLO Manager webhook test"}'Built to demonstrate the Google SRE workbook burn-rate model, from hands-on SLO/SLI work at Amadeus where availability SLOs governed production airline booking systems.