apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: checkout
namespace: shop
labels:
release: kube-prometheus-stack
spec:
selector:
matchLabels:
app: checkout
endpoints:
- port: metrics
path: /metrics
interval: 30s
---
apiVersion: v1
kind: Service
metadata:
name: checkout
namespace: shop
labels:
app: checkout
spec:
selector:
app: checkout
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: checkout-alerts
namespace: shop
labels:
release: kube-prometheus-stack
spec:
groups:
- name: checkout
rules:
- alert: CheckoutErrorRateHigh
expr: |
sum(rate(http_requests_total{namespace="shop",service="checkout",code=~"5.."}[5m]))
/ sum(rate(http_requests_total{namespace="shop",service="checkout"}[5m])) > 0.05
for: 10m
labels:
severity: page
team: shop
annotations:
summary: More than 5% of checkout requests fail
---
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: shop-slack
namespace: shop
labels:
alertmanager: main
spec:
route:
receiver: slack
groupBy: ["alertname"]
matchers:
- name: severity
value: page
receivers:
- name: slack
slackConfigs:
- channel: "#shop-alerts"
apiURL:
name: slack-webhook
key: urlKubernetes graph
Prometheus Operator: ServiceMonitor, PrometheusRule and the path to an alert
How the Prometheus Operator's objects select each other by label: a Prometheus picks ServiceMonitors and PrometheusRules, a ServiceMonitor picks a Service and a named port, and a firing alert goes through Alertmanager to Slack.
With the Prometheus Operator you don't write a scrape configuration. You write small objects, and the operator builds the configuration from the ones a Prometheus object selects. Every hop is a label selector, and a selector that matches nothing is not an error. It is a target that never shows up.
This graph follows one application's metrics from its /metrics endpoint to a message in Slack, and marks each selector on the way.
Interactive graph
Click a resource to see what it does, or follow the setup step by step.
How it works
All 10 resources and what they do
- Prometheus k8smonitoring.coreos.com/v1
- Describes one Prometheus deployment. Its selectors decide which ServiceMonitors and PrometheusRules it loads, from which namespaces. The kube-prometheus-stack chart sets them to
release: <release name>by default. - StatefulSet prometheus-k8sapps/v1
- Created by the operator from the Prometheus object. Each Pod runs Prometheus and a config reloader that loads a new configuration without a restart.
- Secret prometheus-k8sv1
- The generated
prometheus.yaml.gz. The operator rewrites it whenever a selected ServiceMonitor or PodMonitor changes. Decompress it to see what a ServiceMonitor turned into. - ServiceMonitor checkoutmonitoring.coreos.com/v1
- Says which Services to scrape and how. Its own labels must match the Prometheus's
serviceMonitorSelector, itsselectormust match the Service's labels, andportis the name of a Service port. - Service checkoutv1
- Carries the label the ServiceMonitor selects and a port named
metrics. Prometheus doesn't send scrapes through the Service: it uses it to find the Pods behind it. - Pod checkout-…v1
- The scrape targets. Each Pod IP on port 9090 becomes one target, labelled with its namespace, Service and Pod name.
- PrometheusRule checkout-alertsmonitoring.coreos.com/v1
- Alerting and recording rules. Selected by label like a ServiceMonitor. The operator validates the expressions on admission and mounts the rules into the Prometheus Pods.
- Alertmanager mainmonitoring.coreos.com/v1
- Describes the Alertmanager cluster and which AlertmanagerConfigs it merges into its routing tree. It groups alerts, silences them and sends the notifications.
- AlertmanagerConfig shop-slackmonitoring.coreos.com/v1alpha1
- A team's own route and receiver. The operator adds a matcher for the object's namespace, so it only ever handles alerts whose
namespacelabel isshop. - Slack channel #shop-alerts
- Where the page lands, once the alert has fired for 10 minutes and passed the route's matchers.
Common mistakes
- A ServiceMonitor without the label the Prometheus selects is ignored, with no event anywhere. Compare
kubectl get prometheus -o yamlwith the ServiceMonitor's labels first. portis a port name, not a number. An unnamed Service port can't be referenced;targetPortexists for that and is rarely what you want.- The ServiceMonitor selects Services by the Service's labels, not by the Pod labels in its selector. A Service with no labels of its own is never matched.
- Prometheus needs RBAC to list Services, Endpoints and Pods in the target namespace. Without it the job exists and has no targets.
- An AlertmanagerConfig only sees alerts with its own namespace in the
namespacelabel. An alert whose expression drops that label never reaches the team's route.
The manifests you write
Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.
Keep going
More graphs
- Deployment, Service and Ingress: how a request reaches your Pods
- Gateway API: GatewayClass, Gateway and HTTPRoute with a canary split
- PVC, StorageClass and CSI: how a cloud disk ends up in your Pod
- RBAC: how a ServiceAccount gets its permissions
- cert-manager with Let's Encrypt: Certificate, CertificateRequest, Order and Challenge
- A private CA with cert-manager and trust-manager
- Istio traffic management: Gateway, VirtualService, DestinationRule and policies
- Flux dependencies: Git and OCI sources, Kustomizations and HelmReleases
- Argo CD: ApplicationSet, AppProject and the Applications it generates
- Inside an OCI image: tag, index, manifests, config and layers
- OCI artifacts: Helm charts, Flux artifacts and image volumes
- A Helm release: chart, values, revisions and the objects Helm owns
- Kustomize: a base, two overlays, a component and generated ConfigMaps
- A StatefulSet database: headless Service, per-Pod volumes, snapshots and restore
- Autoscaling end to end: KEDA, the HPA it creates and Karpenter adding nodes
- External Secrets Operator: from a cloud secret manager to a Pod, with rotation
- Kyverno CEL policies: ValidatingPolicy, MutatingPolicy, GeneratingPolicy and exceptions
- Cilium egress to a domain: CiliumNetworkPolicy, the DNS proxy and toFQDNs
- Istio ambient mode: ztunnel, waypoint proxies and authorization without sidecars
- Argo Rollouts canary: traffic weights on an HTTPRoute and analysis from Prometheus