-
Detect the stack. Run these read-only commands and record findings:
kubectl config current-context — confirm a Kubernetes cluster is addressable. No cluster → stop; this skill requires kubernetes.
kubectl get crd prometheuses.monitoring.coreos.com -o name 2>/dev/null — Prometheus Operator already present?
helm list -A 2>/dev/null | grep -Ei 'kube-prometheus-stack|prometheus-operator' — managed by Helm?
grep -l 'datadog\|newrelic\|dd-trace\|opentelemetry' package.json requirements.txt go.mod Cargo.toml pom.xml 2>/dev/null | head — a competing APM already instrumented?
ls monitoring/ observability/ .github/monitoring/ 2>/dev/null — existing dashboards/rules in the repo?
Conclude which stack applies. This skill supports only prometheus+grafana+k8s. If detection shows Datadog, New Relic, CloudWatch, Honeycomb, or any non-Prometheus backend as the primary, STOP and report the detected stack to the user; recommend a dedicated skill for that stack instead of forcing Prometheus config onto a mismatched environment.
-
Preflight. Run kubectl get nodes, kubectl version --short, and confirm the cluster has at least 4 vCPU and 8 GiB of free capacity. If another Prometheus Operator is already installed (detected in step 1), either reuse it or uninstall the old operator first — do not install a second one.
-
Add the Helm repo and create the namespace:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
kubectl create namespace monitoring --dry-run=client -o yaml | kubectl apply -f -
-
Render a values file kps-values.yaml that pins retention, storage, scrape interval, and routing. Key stanzas:
prometheus:
prometheusSpec:
retention: 30d
scrapeInterval: 30s
evaluationInterval: 30s
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
resources:
requests:
storage: 100Gi
serviceMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
grafana:
adminPassword: "__replace_me__"
defaultDashboardsEnabled: true
persistence:
enabled: true
size: 10Gi
alertmanager:
config:
route:
receiver: slack-warnings
group_by: ["alertname", "namespace", "severity"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- receiver: pagerduty-critical
matchers: ['severity="critical"']
continue: true
- receiver: slack-critical
matchers: ['severity="critical"']
- receiver: slack-warnings
matchers: ['severity="warning"']
- receiver: "null"
matchers: ['severity="info"']
receivers:
- name: "null"
- name: slack-warnings
slack_configs:
- api_url: "__SLACK_WARN_WEBHOOK__"
channel: "#alerts-warn"
send_resolved: true
title: '{{ template "slack.default.title" . }}'
text: '{{ template "slack.default.text" . }}'
- name: slack-critical
slack_configs:
- api_url: "__SLACK_CRIT_WEBHOOK__"
channel: "#alerts-critical"
send_resolved: true
- name: pagerduty-critical
pagerduty_configs:
- routing_key: "__PAGERDUTY_KEY__"
severity: critical
send_resolved: true
Replace the three placeholder tokens with real secrets from a sealed-secret, External Secrets Operator, or kubectl create secret.
-
Install or upgrade:
helm upgrade --install kps prometheus-community/kube-prometheus-stack \
--namespace monitoring --version 55.5.0 -f kps-values.yaml --wait --timeout 15m
-
Validate the install:
kubectl -n monitoring get pods
kubectl -n monitoring get servicemonitors
kubectl -n monitoring port-forward svc/kps-kube-prometheus-stack-prometheus 9090:9090 &
curl -s localhost:9090/api/v1/targets | jq '.data.activeTargets | length'
-
Apply baseline alerts. Copy references/alertmanager-rules-template.yaml, substitute the namespace label if required, validate with promtool check rules (after extracting the spec.groups with yq), then kubectl apply -f.
-
Write ServiceMonitors for each input service. Template:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: <app>-sm
namespace: monitoring
labels:
release: kps
spec:
namespaceSelector:
matchNames: ["<app-ns>"]
selector:
matchLabels:
app.kubernetes.io/name: <app>
endpoints:
- port: <metrics-port-name>
path: /metrics
interval: 30s
scrapeTimeout: 10s
Confirm up{job="<app>-sm"} == 1 in Prometheus.
-
Import dashboards. From Grafana UI or via ConfigMap with label grafana_dashboard: "1", apply references/grafana-dashboard-templates.json. Also import community dashboards: 1860 (node-exporter), 13332 (kube-state-metrics), 7249 (kubelet), 15661 (Kubernetes overview).
-
Fire a synthetic alert end-to-end:
kubectl -n monitoring run stress --image=polinux/stress --restart=Never -- \
stress --cpu 4 --timeout 600s
Watch #alerts-warn for the HighCPU notification. Remove the pod afterward.
-
Document. Emit a short report listing the Helm release name, chart version, active targets count, firing alerts count, dashboards imported, and the Alertmanager receivers configured. Store the values file and secrets source in the ops repo.