| name | monitoring-setup |
| description | Set up monitoring stack with Prometheus, Grafana, alerts |
| shortcut | ms |
| category | devops |
| difficulty | advanced |
| estimated_time | 3 minutes |
Monitoring Stack Setup
Generates production-ready monitoring infrastructure with Prometheus, Grafana, and AlertManager including dashboards, alerts, and exporters.
When to Use This
- Setting up monitoring for new application
- Need observability for Kubernetes cluster
- Want pre-configured dashboards and alerts
- Production deployment requires monitoring
- Using managed monitoring (CloudWatch, Datadog, etc.)
- Simple application (overkill for toy projects)
How It Works
You are a monitoring and observability expert. When user runs /monitoring-setup or /ms:
-
Identify monitoring needs:
- Infrastructure: Kubernetes, VMs, containers?
- Applications: Custom metrics needed?
- Dashboards: What to visualize?
- Alerts: Critical thresholds?
-
Generate monitoring stack:
- Prometheus: Metrics collection and storage
- Grafana: Visualization dashboards
- AlertManager: Alert routing and grouping
- Exporters: Node, kube-state-metrics, application metrics
-
Create dashboards:
- System metrics (CPU, memory, disk, network)
- Application metrics (requests, latency, errors)
- Custom business metrics
-
Define alert rules:
- Critical: Immediate attention (paging)
- Warning: Requires investigation
- Info: Awareness only
-
Provide deployment guide:
- Installation steps
- Configuration
- Testing and validation
Output Format
## Deployment
### Install monitoring stack:
```bash
[Installation commands]
Access dashboards:
## Example
**User:** `/ms`
**Request:** Set up monitoring for Kubernetes cluster with Node.js API
**Output:**
```yaml
# prometheus-stack.yaml
# Complete monitoring stack for Kubernetes
---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
---
# Prometheus ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: monitoring
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
# AlertManager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
# Load alert rules
rule_files:
- /etc/prometheus/rules/*.yml
# Scrape configurations
scrape_configs:
# Prometheus itself
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Kubernetes API server
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
# Kubernetes nodes
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
# Kubernetes pods
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
# Scrape only pods with prometheus.io/scrape annotation
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
# Alert Rules
alerts.yml: |
groups:
- name: critical
interval: 30s
rules:
# Pod down alert
- alert: PodDown
expr: up{job="kubernetes-pods"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} is down"
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been down for more than 1 minute."
# High error rate
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High 5xx error rate"
description: "Error rate is {{ $value }}% (threshold: 5%)"
# High latency
- alert: HighLatency
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "High p95 latency"
description: "p95 latency is {{ $value }}s (threshold: 1s)"
# High memory usage
- alert: HighMemoryUsage
expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage on {{ $labels.pod }}"
description: "Memory usage is {{ $value | humanizePercentage }} (threshold: 90%)"
# Disk space low
- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Low disk space on {{ $labels.instance }}"
description: "Available disk space is {{ $value | humanizePercentage }} (threshold: 10%)"
---
# Prometheus Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
serviceAccountName: prometheus
containers:
- name: prometheus
image: prom/prometheus:v2.45.0
args:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=15d'
ports:
- containerPort: 9090
volumeMounts:
- name: config
mountPath: /etc/prometheus
- name: storage
mountPath: /prometheus
volumes:
- name: config
configMap:
name: prometheus-config
- name: storage
emptyDir: {} # Use PVC for persistence in production
---
# Prometheus Service
apiVersion: v1
kind: Service
metadata:
name: prometheus
namespace: monitoring
spec:
selector:
app: prometheus
ports:
- port: 9090
targetPort: 9090
---
# Grafana Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
containers:
- name: grafana
image: grafana/grafana:10.0.0
ports:
- containerPort: 3000
env:
- name: GF_SECURITY_ADMIN_PASSWORD
value: "admin" # CHANGE THIS!
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "false"
volumeMounts:
- name: storage
mountPath: /var/lib/grafana
volumes:
- name: storage
emptyDir: {} # Use PVC for persistence
---
# Grafana Service
apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: monitoring
spec:
selector:
app: grafana
ports:
- port: 3000
targetPort: 3000
type: LoadBalancer # Or use Ingress
---
# AlertManager ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-config
namespace: monitoring
data:
alertmanager.yml: |
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'slack'
routes:
- match:
severity: critical
receiver: 'pagerduty'
receivers:
- name: 'slack'
slack_configs:
- api_url: 'YOUR_SLACK_WEBHOOK_URL'
channel: '#alerts'
title: 'Alert: {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty'
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_KEY'
---
# AlertManager Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: alertmanager
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: alertmanager
template:
metadata:
labels:
app: alertmanager
spec:
containers:
- name: alertmanager
image: prom/alertmanager:v0.26.0
args:
- '--config.file=/etc/alertmanager/alertmanager.yml'
ports:
- containerPort: 9093
volumeMounts:
- name: config
mountPath: /etc/alertmanager
volumes:
- name: config
configMap:
name: alertmanager-config
---
# AlertManager Service
apiVersion: v1
kind: Service
metadata:
name: alertmanager
namespace: monitoring
spec:
selector:
app: alertmanager
ports:
- port: 9093
targetPort: 9093
---
# Prometheus ServiceAccount (for Kubernetes API access)
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: monitoring
---
# ClusterRole for Prometheus
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups:
- extensions
resources:
- ingresses
verbs: ["get", "list", "watch"]
---
# ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
Deployment Instructions:
kubectl apply -f prometheus-stack.yaml
kubectl get pods -n monitoring
kubectl port-forward -n monitoring svc/prometheus 9090:9090 &
kubectl port-forward -n monitoring svc/grafana 3000:3000 &
kubectl port-forward -n monitoring svc/alertmanager 9093:9093 &
Application Instrumentation (Node.js):
const express = require('express');
const promClient = require('prom-client');
const app = express();
const register = new promClient.Registry();
promClient.collectDefaultMetrics({ register });
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.5, 1, 2, 5]
});
const httpRequestTotal = new promClient.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status']
});
register.registerMetric(httpRequestDuration);
register.registerMetric(httpRequestTotal);
app.use( {
start = .();
res.(, {
duration = (.() - start) / ;
httpRequestDuration.(req., req.?. || req., res.).(duration);
httpRequestTotal.(req., req.?. || req., res. >= && res. < ? : ).();
});
();
});
app.(, (req, res) => {
res.(, register.);
res.( register.());
});
app.(, {
res.({ : });
});
app.(, {
res.({ : [] });
});
app.(, {
.();
.();
});
Kubernetes Pod Annotation (for auto-discovery):
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs-api
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "3000"
prometheus.io/path: "/metrics"
spec:
containers:
- name: api
image: myregistry/nodejs-api:latest
ports:
- containerPort: 3000
Key Metrics to Monitor
Infrastructure:
- CPU usage (per node, per pod)
- Memory usage (per node, per pod)
- Disk space (per node)
- Network I/O (per node)
- Pod restarts
Application:
- HTTP request rate
- HTTP request duration (p50, p95, p99)
- HTTP error rate (4xx, 5xx)
- Active connections
- Queue depth (if using queues)
Business:
- Orders per minute
- Revenue per hour
- User signups
- Active sessions
Pro Tips
Use Helm chart for easier deployment: helm install prometheus prometheus-community/kube-prometheus-stack
Set up persistent volumes for Prometheus and Grafana (don't lose metrics!)
Configure retention period based on storage (default: 15 days)
Use Alertmanager routes for critical vs warning alerts
Import community dashboards from https://grafana.com/dashboards
Alert Configuration Best Practices
Critical Alerts (Page oncall):
- Pod/service down
- Error rate >5%
- Disk space <10%
- Memory usage >95%
Warning Alerts (Slack/email):
- High latency (p95 >1s)
- Memory usage >80%
- Disk space <20%
- Unusual traffic patterns
Info Alerts (Monitoring only):
- Deployment events
- Pod restarts (if infrequent)
- Configuration changes