Your app goes down on Friday night. You don’t find out until Monday when a customer complains.

This doesn’t have to happen. The same SRE principles that keep large systems alive (observability, threat detection, and disaster recovery) work at any scale. They’re the same tools, just sized to your infrastructure.

This is the complete SRE stack: observe your cluster, catch security threats before they spread, and restore from backups in minutes. All open source. Deployable on any Kubernetes cluster.

What We’re Building

SRE has four pillars:

  1. Observability: Know what’s happening (metrics, logs, dashboards, alerts)
  2. Security: Know who’s doing bad things (threat detection, network policies)
  3. Incident Response: Know how to fix it (alerting, runbooks, debugging)
  4. Disaster Recovery: Know how to rebuild it (backups, recovery testing)

Here’s the stack:

┌──────────────────────────────────────────────────────────────────┐
│ Your Kubernetes Cluster                                          │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│ ┌─ OBSERVABILITY ──────────────────────────────────────────────┐│
│ │                                                              ││
│ │  Prometheus ◄── kube-state, node-exporter, app metrics     ││
│ │       │                                                     ││
│ │       ├──► Grafana (dashboards)                            ││
│ │       └──► Alertmanager                                    ││
│ │                                                              ││
│ │  Promtail ──► Loki (centralized logs)                      ││
│ │       │                                                     ││
│ │       └──► Grafana (log search)                            ││
│ │                                                              ││
│ │  Alertmanager ──► ntfy (notifications)                     ││
│ │                                                              ││
│ └──────────────────────────────────────────────────────────────┘│
│                                                                  │
│ ┌─ SECURITY ───────────────────────────────────────────────────┐│
│ │                                                              ││
│ │  Falco (runtime threat detection, DaemonSet on all nodes)  ││
│ │       │                                                     ││
│ │       └──► falcosidekick ──► notifications                 ││
│ │                                                              ││
│ │  Network Policies (Cilium CNI)                              ││
│ │       default-deny ingress + explicit allows               ││
│ │                                                              ││
│ └──────────────────────────────────────────────────────────────┘│
│                                                                  │
│ ┌─ DISASTER RECOVERY ──────────────────────────────────────────┐│
│ │                                                              ││
│ │  Velero (daily backups) ──► Cloud storage                  ││
│ │       schedule: daily at 2am                                ││
│ │       retention: 30 days                                    ││
│ │       namespaces: configurable per workload                 ││
│ │                                                              ││
│ │  Disaster recovery test: validate restore capability       ││
│ │                                                              ││
│ └──────────────────────────────────────────────────────────────┘│
│                                                                  │

When something breaks:

  1. Falco detects suspicious behavior (unauthorized process, privilege escalation)
  2. Prometheus detects metrics problems (node down, pod restarting, disk full)
  3. Alertmanager groups alerts, routes to your notification system
  4. You get a notification, check dashboards, debug via logs
  5. If catastrophic: Velero restores from yesterday’s backup

Let’s build each layer.


Part 1: Observability

The Foundation: Prometheus

Prometheus scrapes metrics from your cluster every 15 seconds and stores them for 15 days.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
prometheus:
  prometheusSpec:
    retention: 15d
    additionalScrapeConfigs:
      # Kubernetes built-ins
      - job_name: 'kube-state-metrics'
        static_configs:
          - targets: ['kube-state-metrics:8080']
      
      # Node metrics (CPU, memory, disk, network)
      - job_name: 'node-exporter'
        kubernetes_sd_configs:
          - role: node
      
      # External nodes (GPU machines, worker pools)
      - job_name: 'external-nodes'
        static_configs:
          - targets: ['192.168.1.110:9100']
            labels:
              node: external-gpu-worker
      
      # Batch jobs and external services
      - job_name: 'pushgateway'
        honor_labels: true
        static_configs:
          - targets: ['pushgateway.monitoring.svc.cluster.local:9091']
    
    # Persistent storage (block storage recommended)
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: fast-block-storage
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 15Gi

Why 15d retention? Retention is a tradeoff. 15 days of metrics typically requires 15-20Gi of storage at moderate scale. Long enough to spot trends and debug historical issues. Adjust based on your pod density and cardinality.

What gets scraped:

  • kube-state-metrics: Pod restarts, node conditions, PVC usage, deployment replicas
  • node-exporter: CPU, memory, disk I/O, network stats on each node
  • External nodes: Monitor external VMs, GPU workers, or other infrastructure
  • pushgateway: For cron jobs and batch operations that finish before Prometheus scrapes them

PromQL lets you ask questions:

1
2
3
4
5
6
7
8
# Which pods are restarting?
rate(kube_pod_container_status_restarts_total[1h]) > 0

# Is any node's disk > 80% full?
node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.2

# What's total CPU usage across cluster?
sum(rate(container_cpu_usage_seconds_total[5m])) / sum(machine_cpu_cores)

Grafana: Make It Visual

Prometheus has data. Grafana turns it into dashboards.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
grafana:
  enabled: true
  service:
    type: LoadBalancer
  persistence:
    enabled: true
    storageClassName: fast-block-storage
    size: 2Gi
  dashboardProviders:
    dashboardproviders.yaml:
      apiVersion: 1
      providers:
        - name: "default"
          type: file
          path: /var/lib/grafana/dashboards/default
          allowUiUpdates: true

kube-prometheus-stack provides 40+ pre-built dashboards:

  • Kubernetes Cluster: node count, total CPU, total memory, storage usage
  • Node Exporter: per-node view of CPU, memory, disk, network
  • Pod CPU/Memory: which workloads consume the most resources
  • Prometheus: is Prometheus itself healthy?

You’ll build custom dashboards specific to your applications:

  • Infrastructure Health At a Glance: Node count, pod count, resource usage, active alerts
  • Storage Utilization: PVC trends, growth rate, capacity planning
  • Pod Restarts: Which workloads are unstable, restart patterns
  • Application Metrics: Request rate, error rate, latency percentiles

Loki: Centralized Logs

Metrics tell you when something broke. Logs tell you why.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
loki:
  enabled: true
  persistence:
    enabled: true
    storageClassName: fast-block-storage
    size: 20Gi
  config:
    ingester:
      chunk_idle_period: 3m
      chunk_retain_period: 1m

promtail:
  enabled: true
  config:
    scrape_configs:
      - job_name: kubernetes-pods
        kubernetes_sd_configs:
          - role: pod
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_name]
            action: replace
            target_label: pod
          - source_labels: [__meta_kubernetes_namespace]
            action: replace
            target_label: namespace
          - source_labels: [__meta_kubernetes_pod_label_app]
            action: replace
            target_label: app

Promtail runs as a DaemonSet on every node. It tails pod logs and ships them to Loki. Logs are indexed by pod name, namespace, and app label: the same labels you use for orchestration.

In Grafana, search logs by their labels:

{namespace="production", app="api"}
| json
| level="error"

This finds all error-level JSON logs from the api app in production. 20Gi of storage typically holds 2-4 weeks of logs depending on verbosity. When a pod crashes with CrashLoopBackOff, query the logs to understand why.

Alertmanager + Notifications

Dashboards are useless if you have to remember to check them. Alerts are what actually save you.

When Prometheus detects a problem, Alertmanager groups related alerts and sends them to your notification system. We use ntfy (HTTP webhooks to push notifications), but you can route to Slack, PagerDuty, email, or any webhook receiver.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
alertmanager:
  enabled: true
  config:
    global:
      resolve_timeout: 5m
    route:
      group_by: ['alertname', 'cluster', 'service']
      group_wait: 10s
      group_interval: 10s
      repeat_interval: 12h
      receiver: 'notifications'
    receivers:
      - name: 'notifications'
        webhook_configs:
          - url: 'http://notification-service.monitoring.svc.cluster.local/alerts'
            send_resolved: true

When Prometheus fires an alert (node down, pod restarting, disk full), Alertmanager:

  1. Waits 10s to see if more related alerts fire
  2. Groups them by alert type
  3. Sends a single webhook to your notification system
  4. Your system routes to the right channel (on-call, team slack, etc.)

send_resolved: true means you also get notified when the alert clears:

[Infrastructure] Node Offline (1 active)
worker-3 - up == 0

[Infrastructure] RESOLVED: Node Offline (1 resolved)
worker-3 - up == 1

Part 2: Security

Observability tells you what’s happening. Security tells you if something malicious is happening.

Falco: Runtime Threat Detection

Falco is a runtime security engine. It watches for suspicious behavior: unauthorized process execution, privilege escalation, sensitive file access, container escape attempts.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
falco:
  driver:
    kind: kmod  # Kernel module for low overhead

  falcosidekick:
    enabled: true
    config:
      webhook:
        address: "http://notification-service/security-alerts"
        minimumpriority: "warning"

  falcoctl:
    artifact:
      install:
        refs:
          - falco-rules:5
      follow:
        refs:
          - falco-rules:5

  falco:
    json_output: true
    log_level: info

  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi

Falco runs as a DaemonSet on every node. It monitors syscalls using eBPF (kernel mode inspection). When suspicious behavior is detected, falcosidekick sends alerts to your notification system.

Example alerts Falco catches:

  • Shell spawned in container (usually indicates compromise or debugging)
  • Sensitive files read (/etc/passwd, host certificates, cloud credentials)
  • Privilege escalation attempts
  • Unauthorized port binding
  • Container attempting to escape to host

When you get an alert:

[Security] Sensitive file opened
pod: production/api
file: /etc/shadow
user: root
time: 2026-05-26T14:23:45Z

You know something’s suspicious immediately. Not after data exfiltration.

Network Policies: Default-Deny Access

Falco detects threats. Network policies prevent unauthorized traffic from flowing.

Using Cilium CNI, your cluster enforces explicit network policies:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Default: block all ingress traffic
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
    - Ingress

---
# Explicit allow: ingress controller can reach this namespace
kind: NetworkPolicy
metadata:
  name: allow-from-ingress-nginx
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

---
# Explicit allow: pods in same namespace can talk to each other
kind: NetworkPolicy
metadata:
  name: allow-intra-namespace
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector: {}

Apply this to sensitive namespaces: production applications, databases, identity services. Each namespace can only receive traffic from:

  • Its own ingress controller (for external HTTP/HTTPS)
  • Kube-system (for DNS, kubelet healthchecks)
  • Itself (pod-to-pod communication within the namespace)

Result: If a compromised application tries to SSH to another service or exfiltrate data, the network drops it. Traffic never leaves the namespace.


Part 3: Disaster Recovery

Observability + security prevent most problems. But catastrophe happens. Hardware fails. Storage corrupts. You get compromised. You need backups.

Velero: Automated Daily Backups

Velero is a backup tool for Kubernetes. It snapshots your cluster’s desired state and stores it off-cluster.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-backup
  namespace: velero
spec:
  schedule: "0 2 * * *"  # 2am UTC every day
  template:
    ttl: 720h  # Keep for 30 days
    includedNamespaces:
      - production
      - monitoring
      - ingress-system
    includedResources:
      - '*'

Every night at 2am, Velero:

  1. Snapshots all Kubernetes resources (Deployments, StatefulSets, ConfigMaps, Secrets, PVCs)
  2. Exports PVC data (if configured with snapshots)
  3. Uploads to cloud storage (S3, GCS, B2, or compatible service)
  4. Keeps a rolling 30-day retention

What gets backed up:

  • Kubernetes manifests: All resource definitions in YAML
  • ConfigMaps: Application configuration
  • Secrets: API keys, TLS certificates (encrypted at rest in cloud storage)
  • PVC data: Databases, file storage (if snapshots are enabled)
  • Velero metadata: Backup history and restore plans

Disaster recovery scenario:

Your primary region goes down. Data corruption detected. Or ransomware hits and you need to restore from a clean state.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# List available backups
velero backup get

# Restore from specific backup
velero restore create --from-backup daily-backup-2026-05-25

# Monitor restore progress
velero restore describe daily-backup-2026-05-25-restore-<id> --details

# Verify restored resources
kubectl get deployments -A
kubectl get pvc -A

Complete recovery: 10-30 minutes depending on cluster size and data volume. Without backup: hours of manual reconfiguration, or total data loss.


Real Scenario: The Alert That Saved Your Recovery Time

Worker node fails unexpectedly. Hardware issue, drive error, or kernel panic. The node is unreachable.

Without Monitoring

6 hours later, your team notices deployment failures. Pods keep pending: “node selector can’t find a matching node.” Someone starts investigating. The failed node has been down for hours. Manual recovery takes 2+ hours. In the meantime, your SLA is breached.

With Monitoring

2 minutes after node goes down:

Prometheus scraper fails. After 1 minute of missed scrapes, Alertmanager fires:

[Infrastructure] Node Offline
worker-3 - up == 0

You get notified and check Grafana:

  • Node CPU/memory graphs show the node went dark
  • Pods scheduled there show NodeNotReady status
  • Affected deployments have pending pods

You immediately:

  1. Check the node status: kubectl get node worker-3 → NotReady
  2. Decide: Hardware issue → replace node, or use spare capacity
  3. If critical: restore workloads via Velero backup
  4. If capacity-constrained: scale other nodes or update node selector

Result: You fixed it within 10 minutes. No SLA breach. No customer notice.

That’s what SRE monitoring is for: knowing when something breaks before it impacts your customer.


How It All Deploys (GitOps)

Your entire SRE stack is version-controlled and deployed via Flux CD (or your GitOps tool of choice).

Directory Structure

your-gitops-repo/
├── clusters/prod/
│   └── flux-system/
│       ├── kustomization.yaml     # Root entry point
│       ├── infrastructure.yaml     # Kustomization reference
│       └── monitoring.yaml         # Kustomization reference
├── infrastructure/prod/
│   ├── falco/
│   │   ├── helmrelease.yaml
│   │   ├── namespace.yaml
│   │   └── kustomization.yaml
│   ├── cilium/
│   │   └── helmrelease.yaml
│   └── velero/
│       ├── helmrelease.yaml
│       ├── schedule.yaml
│       └── kustomization.yaml
├── monitoring/prod/
│   ├── kube-prometheus-stack-helmrelease.yaml
│   ├── loki-helmrelease.yaml
│   ├── ntfy/ntfy.yaml
│   ├── network-policies/
│   │   ├── default-deny-ingress.yaml
│   │   ├── allow-from-ingress-nginx.yaml
│   │   └── kustomization.yaml
│   └── kustomization.yaml
└── .sops.yaml                      # SOPS encryption config

To deploy:

1
2
3
4
5
6
7
8
9
# Bootstrap Flux pointing to your GitOps repo
flux bootstrap github \
  --owner=your-org \
  --repo=infrastructure-gitops \
  --branch=main

# Flux auto-applies everything
flux get kustomizations --watch
flux get helmreleases -A --watch

All changes are git commits. Auditing is git log. Rolling back is git revert. Every config change is tracked forever.

Storage Backend

Prometheus and Loki both need fast, persistent storage. NFS is too slow for time-series databases. Use:

  • Cloud block storage: EBS, GCP Persistent Disks, Azure Managed Disks
  • iSCSI: TrueNAS, NETAPP, or compatible
  • Local volumes: For on-premise deployments (with replication)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
prometheus:
  storageSpec:
    volumeClaimTemplate:
      spec:
        storageClassName: ebs-fast  # or your storage class
        resources:
          requests:
            storage: 15Gi

loki:
  persistence:
    storageClassName: ebs-fast
    size: 20Gi

Quick Start: Deploy This Yourself

You need:

  1. A Kubernetes cluster (1.20+)
  2. Persistent storage (fast block storage, not NFS)
  3. A LoadBalancer or Ingress controller
  4. Helm 3.x

Step 1: Add Helm Repos

1
2
3
4
5
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm repo update

Step 2: Create Namespaces & Secrets

1
2
3
4
5
6
7
8
kubectl create namespace monitoring
kubectl create namespace falco
kubectl create namespace velero

# Create secret for cloud credentials (Velero backup location)
kubectl create secret generic velero-creds \
  --from-literal=cloud-credentials=YOUR_CLOUD_CREDENTIALS \
  -n velero

Step 3: Deploy Monitoring Stack

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# Create HelmRelease for kube-prometheus-stack
cat <<EOF | kubectl apply -f -
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: kube-prometheus-stack
  namespace: monitoring
spec:
  interval: 10m
  chart:
    spec:
      chart: kube-prometheus-stack
      version: ">=55.0.0"
      sourceRef:
        kind: HelmRepository
        name: prometheus-community
        namespace: monitoring
  values:
    prometheus:
      prometheusSpec:
        retention: 15d
        storageSpec:
          volumeClaimTemplate:
            spec:
              storageClassName: fast-storage
              resources:
                requests:
                  storage: 15Gi
    grafana:
      enabled: true
      persistence:
        enabled: true
        storageClassName: fast-storage
        size: 2Gi
    alertmanager:
      enabled: true
EOF

# Deploy Loki
cat <<EOF | kubectl apply -f -
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: loki-stack
  namespace: monitoring
spec:
  interval: 10m
  chart:
    spec:
      chart: loki-stack
      sourceRef:
        kind: HelmRepository
        name: grafana
        namespace: monitoring
  values:
    loki:
      enabled: true
      persistence:
        enabled: true
        storageClassName: fast-storage
        size: 20Gi
    promtail:
      enabled: true
EOF

Step 4: Deploy Falco

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat <<EOF | kubectl apply -f -
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: falco
  namespace: falco
spec:
  interval: 10m
  chart:
    spec:
      chart: falco
      version: ">=4.0.0"
      sourceRef:
        kind: HelmRepository
        name: falcosecurity
        namespace: falco
  values:
    driver:
      kind: kmod
    falcosidekick:
      enabled: true
      config:
        webhook:
          address: "http://your-webhook-endpoint"
EOF

Step 5: Deploy Velero

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat <<EOF | kubectl apply -f -
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: velero
  namespace: velero
spec:
  interval: 10m
  chart:
    spec:
      chart: velero
      sourceRef:
        kind: HelmRepository
        name: vmware-tanzu
        namespace: velero
  values:
    configuration:
      backupStorageLocation:
        provider: aws
        bucket: your-backup-bucket
      schedules:
        daily:
          schedule: "0 2 * * *"
          template:
            ttl: 720h
            includedNamespaces:
              - production
              - monitoring
EOF

Step 6: Verify Everything Works

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Check Prometheus is scraping
kubectl port-forward -n monitoring svc/prometheus 9090:9090
# Visit http://localhost:9090/targets

# Check Grafana
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
# Visit http://localhost:3000 (get admin password from secret)

# Check Loki is receiving logs
kubectl logs -n monitoring -l app.kubernetes.io/name=promtail --tail=5

# Check Falco is running
kubectl logs -n falco -l app=falco --tail=10

# Check Velero backup schedule
velero backup-location get
velero schedule get

Lessons Learned

Retention Tuning

Prometheus retention is a tradeoff: longer history requires more storage. Start with 15d, monitor disk usage, adjust based on your pod density. Higher cardinality (many unique label combinations) drives more storage.

Alert Fatigue

Define alert thresholds carefully. Too sensitive = 100 alerts a day (ignored). Too loose = missing real issues. Start conservative, adjust as you understand your baseline.

Network Policy Debugging

“Pod X can’t reach Pod Y” is hard to debug with network policies enabled. Test connectivity before enforcing policies:

1
2
3
kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -- bash
# Inside the pod:
curl pod-ip:port  # Should fail if blocked by policy

Storage Backend Matters

We benchmarked: NFS writes are 10-50x slower than block storage for time-series databases. Use cloud block storage, iSCSI, or local volumes with replication. Don’t use NFS for Prometheus or Loki.

Backup Testing

Backups only matter if you can restore. Test quarterly: restore Velero backup to a dev cluster and verify everything works. A backup you’ve never tested is not a backup. It’s a hope.


What’s Next

This covers the core SRE stack. From here, you’ll build:

Custom Alerts

Define SLOs for your applications. Example for an API service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
- alert: HighErrorRate
  expr: rate(http_requests_total{job="api",status=~"5.."}[5m]) > 0.001
  for: 5m
  annotations:
    summary: "API error rate > 0.1%"

- alert: HighLatency
  expr: histogram_quantile(0.99, http_request_duration_seconds_bucket) > 0.5
  for: 5m
  annotations:
    summary: "API p99 latency > 500ms"

Custom Dashboards

Build dashboards specific to your applications: request rate, error rate, latency percentiles, cache hit ratio, database connection pool size.

Incident Runbooks

For each alert type, document the recovery steps:

Alert: PodCrashLooping

  1. Get pod logs: kubectl logs -n NAMESPACE POD
  2. Check recent events: kubectl describe pod -n NAMESPACE POD
  3. Check resource requests: kubectl get pod -o json | jq .spec.containers[].resources
  4. If OOMKilled: increase memory request
  5. If ImagePullBackOff: check registry credentials and image availability

Regular Testing

Quarterly: restore a Velero backup to a staging cluster. Verify all workloads come back correctly. Fix any issues before you need a real disaster recovery.


Summary

You now have a production-grade SRE stack:

  • Observability: Metrics, logs, dashboards, alerts that wake you up when things break
  • Security: Runtime threat detection, network policies, zero-trust access control
  • Disaster Recovery: Automated daily backups, tested restores, clear recovery procedures
  • Auditability: GitOps version control of all infrastructure code

This works whether you’re running 10 nodes or 1000. The principles scale. The tools scale. The practices scale.

When the next crisis hits (hardware fails, a deployment goes bad, or security is questioned) you won’t scramble. You’ll have observability telling you exactly what happened. Backups letting you restore. And a runbook telling you what to do.

That’s what production SRE looks like.


Building out your SRE stack? We take on short-term infrastructure engagements and platform work.

Connect on LinkedIn →