kube-prometheus-stack es el chart de Helm de la comunidad Prometheus que instala, en un solo paso, Prometheus Operator, Prometheus, Alertmanager, Grafana, node-exporter y kube-state-metrics, junto con paneles y reglas de alerta ya preparados para Kubernetes. En este tutorial lo desplegarás en un clúster existente, accederás a Prometheus y Grafana, harás que Prometheus recoja las métricas de tu propia aplicación con un ServiceMonitor, crearás una regla de alerta y enviarás las alertas a Slack.
Requisitos previos
Para seguir esta guía necesitas:
- Un clúster de Kubernetes 1.28 o superior con al menos 2 nodos y unos 4 GB de RAM libres entre todos ellos, por ejemplo un clúster Kubernetes gestionado de CubePath.
kubectlconfigurado contra ese clúster en tu equipo o en un servidor de administración con Ubuntu 24.04.- Helm 3 o superior.
- Una
StorageClassque permita crear volúmenes persistentes, si quieres que los datos de Prometheus sobrevivan a un reinicio del pod.
Comprueba que kubectl llega al clúster y que ves los nodos:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
worker-1 Ready <none> 12d v1.31.4
worker-2 Ready <none> 12d v1.31.4
Paso 1: Instalar Helm
Si todavía no tienes Helm, en Ubuntu 24.04 puedes instalarlo con el snap oficial:
sudo snap install helm --classic
helm version
version.BuildInfo{Version:"v3.x.y", ...}
Añade el repositorio de charts de la comunidad Prometheus y actualiza el índice:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
Paso 2: Preparar el archivo de valores
En lugar de pasar opciones con --set, guarda la configuración en un archivo de valores que puedas versionar:
nano kps-values.yaml
Este archivo fija la contraseña de Grafana, la retención y el almacenamiento de Prometheus, y hace que Prometheus recoja cualquier ServiceMonitor y PrometheusRule del clúster, no solo los creados por el propio chart. Sustituye your_strong_password y your_storage_class:
grafana:
adminPassword: your_strong_password
prometheus:
prometheusSpec:
retention: 15d
serviceMonitorSelectorNilUsesHelmValues: false
podMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: your_storage_class
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
Consulta las clases de almacenamiento disponibles con kubectl get storageclass. Si no tienes ninguna, elimina el bloque storageSpec: Prometheus usará un volumen temporal y perderá los datos al reiniciarse.
Notaen los clústeres gestionados el plano de control (etcd, kube-scheduler, kube-controller-manager) no es accesible desde los nodos, y esos objetivos aparecerán como caídos en Prometheus. Para no generar alertas falsas, añade al archivo
kubeEtcd.enabled: false,kubeScheduler.enabled: falseykubeControllerManager.enabled: false, cada uno como bloque de primer nivel.
Paso 3: Desplegar kube-prometheus-stack
Instala el chart en un namespace propio llamado monitoring:
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
-f kps-values.yaml
NAME: kube-prometheus-stack
NAMESPACE: monitoring
STATUS: deployed
...
Espera uno o dos minutos y comprueba que todos los pods están en Running:
kubectl get pods -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-kube-prometheus-stack-alertmanager-0 2/2 Running 0 2m
kube-prometheus-stack-grafana-6d9f8c7b5d-x2k9p 3/3 Running 0 2m
kube-prometheus-stack-kube-state-metrics-5c8b7d9f4-7hq2m 1/1 Running 0 2m
kube-prometheus-stack-operator-7f9c6d8b5-m4n8s 1/1 Running 0 2m
kube-prometheus-stack-prometheus-node-exporter-4xk2l 1/1 Running 0 2m
kube-prometheus-stack-prometheus-node-exporter-9vj7w 1/1 Running 0 2m
prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 2m
Hay un pod de node-exporter por nodo (es un DaemonSet). Si configuraste almacenamiento, confirma que el volumen de Prometheus está enlazado:
kubectl get pvc -n monitoring
NAME STATUS VOLUME CAPACITY ...
prometheus-kube-prometheus-stack-prometheus-db-prometheus-kube-prometheus-stack-prometheus-0 Bound pvc-... 20Gi ...
Paso 4: Acceder a Prometheus y comprobar los objetivos
Los servicios del chart son de tipo ClusterIP, así que no quedan expuestos fuera del clúster. Para acceder a Prometheus abre un reenvío de puertos:
kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9090:9090
Visita http://localhost:9090/targets en el navegador. Deberías ver objetivos como apiserver, kubelet, node-exporter y kube-state-metrics en estado UP.
En la pestaña Graph prueba algunas consultas PromQL útiles. Uso de CPU por pod en el namespace default:
sum by (pod) (rate(container_cpu_usage_seconds_total{namespace="default", container!=""}[5m]))
Memoria de trabajo por pod:
sum by (pod) (container_memory_working_set_bytes{namespace="default", container!=""})
Pods que se han reiniciado en la última hora:
increase(kube_pod_container_status_restarts_total[1h]) > 0
Pulsa Ctrl+C en la terminal para cerrar el reenvío cuando termines.
Paso 5: Acceder a Grafana
Abre un reenvío de puertos al servicio de Grafana, que escucha en el puerto 80 dentro del clúster:
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
Visita http://localhost:3000 e inicia sesión con el usuario admin y la contraseña que pusiste en kps-values.yaml. Prometheus ya está configurado como fuente de datos.
En Dashboards encontrarás los paneles que instala el chart. Los más útiles para empezar son:
- Kubernetes / Compute Resources / Cluster: CPU y memoria de todo el clúster, desglosadas por namespace.
- Kubernetes / Compute Resources / Namespace (Pods): consumo de cada pod de un namespace.
- Node Exporter / Nodes: CPU, memoria, disco y red de cada nodo.
Paso 6: Recoger las métricas de tu aplicación con un ServiceMonitor
Prometheus Operator no usa un archivo prometheus.yml editado a mano: descubre qué recoger a partir de recursos ServiceMonitor. Para este ejemplo supondremos una aplicación en el namespace default con un Service etiquetado app: my-app que expone métricas en un puerto llamado metrics en la ruta /metrics. El puerto debe tener nombre en el Service:
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
selector:
app: my-app
ports:
- name: metrics
port: 8080
targetPort: 8080
Crea el ServiceMonitor:
nano my-app-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: default
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics
path: /metrics
interval: 30s
Aplícalo:
kubectl apply -f my-app-servicemonitor.yaml
Gracias a serviceMonitorSelectorNilUsesHelmValues: false no hace falta añadir la etiqueta release: kube-prometheus-stack. En menos de un minuto aparecerá un objetivo serviceMonitor/default/my-app/0 en http://localhost:9090/targets. Si no aparece, revisa que la etiqueta del Service y el nombre del puerto coinciden exactamente con los del ServiceMonitor.
Paso 7: Crear una regla de alerta
El chart ya incluye decenas de alertas (KubePodCrashLooping, KubeNodeNotReady, NodeFilesystemSpaceFillingUp...). Para añadir las tuyas crea un recurso PrometheusRule. Este ejemplo avisa cuando un pod del namespace default usa más del 90 % del límite de memoria de su contenedor durante 10 minutos:
nano custom-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: custom-rules
namespace: monitoring
spec:
groups:
- name: custom.rules
rules:
- alert: ContainerMemoryNearLimit
expr: |
sum by (namespace, pod, container) (container_memory_working_set_bytes{namespace="default", container!=""})
/
sum by (namespace, pod, container) (kube_pod_container_resource_limits{namespace="default", resource="memory"})
> 0.9
for: 10m
labels:
severity: warning
annotations:
summary: "El contenedor {{ $labels.container }} de {{ $labels.pod }} está cerca de su límite de memoria"
Aplica la regla y comprueba que existe:
kubectl apply -f custom-rules.yaml
kubectl get prometheusrules -n monitoring custom-rules
NAME AGE
custom-rules 10s
Con el reenvío de puertos de Prometheus abierto, la regla aparecerá en http://localhost:9090/alerts dentro del grupo custom.rules.
Paso 8: Enviar las alertas a Slack
Alertmanager agrupa las alertas y las envía a sus receptores. Crea un webhook entrante en tu espacio de Slack y añade la configuración de Alertmanager al final de kps-values.yaml. Sustituye your_slack_webhook_url y el canal:
alertmanager:
config:
global:
resolve_timeout: 5m
route:
group_by: ["namespace", "alertname"]
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
receiver: slack
routes:
- receiver: "null"
matchers:
- alertname = "Watchdog"
receivers:
- name: "null"
- name: slack
slack_configs:
- api_url: your_slack_webhook_url
channel: "#alerts"
send_resolved: true
title: '{{ .CommonLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ .Annotations.description }}{{ "\n" }}{{ end }}'
La alerta Watchdog está siempre activa a propósito para comprobar que la cadena de alertas funciona; la ruta anterior la descarta para que no llegue a Slack cada 12 horas.
Aplica los cambios con helm upgrade:
helm upgrade kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring -f kps-values.yaml
Comprueba que Alertmanager ha cargado la nueva configuración:
kubectl port-forward -n monitoring svc/kube-prometheus-stack-alertmanager 9093:9093
En http://localhost:9093/#/status verás la configuración activa con el receptor slack.
Solución de problemas
- Pods en
Pending:kubectl describe pod -n monitoring <pod>. Suele deberse a falta de recursos en los nodos o a que laStorageClassindicada no existe. - Objetivos del plano de control en DOWN: normal en clústeres gestionados; desactívalos como se explica en el paso 2.
- Un
ServiceMonitorno genera objetivos:kubectl logs -n monitoring deploy/kube-prometheus-stack-operatory revisa que elServicetiene endpoints conkubectl get endpoints my-app. - Las alertas no llegan a Slack: revisa
kubectl logs -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0 -c alertmanager.
Conclusión
Tienes Prometheus, Grafana y Alertmanager monitorizando el clúster, recogiendo las métricas de tu aplicación con un ServiceMonitor y avisando en Slack. Como siguientes pasos, publica Grafana con un Ingress y HTTPS en lugar de usar port-forward, crea paneles propios para las métricas de tu aplicación y guarda kps-values.yaml en un repositorio para desplegar el stack con GitOps.
