# ============================================================================= # Prometheus main config (prometheus.yml) — TASK-0135, phase-15 §Observability # # Source of truth. The monitoring-namespace ConfigMap # (infrastructure/kubernetes/observability/kustomization.yaml, # configMapGenerator key `prometheus.yml`) is generated FROM this file — do # not hand-edit the rendered ConfigMap. # # Targets — every app serves /metrics (the worker's is its ONLY port, 4003): # factory-api api.factory.svc.cluster.local:4000/metrics # factory-worker worker pods:4003/metrics (pod SD — the worker has no # ClusterIP Service; its health server binds the pod IP) # factory-realtime realtime.factory.svc.cluster.local:4001/metrics # (the app's local ws_* registry + OTel text, merged) # factory-web web.factory.svc.cluster.local:3000/api/metrics # (Next.js route — the path differs from the others) # node-exporter expected-present daemonset (pod SD by container name; # the DiskUsageHigh alert reads it — no data until a # node exporter is installed in the cluster) # # Label strategy: each job sets a `service_name` static label, so EVERY # series from that target carries service_name="factory-" (including the # app-local realtime ws_* series, which carry no label of their own). The # `target_info{service_name=...}` gauge (always emitted by the OTel exporter) # is the belt-and-braces proof of identity. # # Naming contract (classic text format, exporter-prometheus 0.57.0): # counters expose with a `_total` suffix that is NOT in the instrument name — # http_request_count → http_request_count_total; ws_messages_total / # storage_ops_total / ai_tokens_total / error_total already end in _total and # are unchanged. Recording rules + alerts use the EXPOSED names. # ============================================================================= global: scrape_interval: 15s evaluation_interval: 15s rule_files: # sibling files, mounted into /etc/prometheus/rules/ by the Deployment - /etc/prometheus/rules/recording-rules.yaml - /etc/prometheus/rules/alerts.yaml alerting: alertmanagers: - static_configs: - targets: ["alertmanager.monitoring.svc.cluster.local:9093"] scrape_configs: # --- the four factory apps -------------------------------------------------- - job_name: factory-api metrics_path: /metrics static_configs: - targets: ["api.factory.svc.cluster.local:4000"] labels: service_name: factory-api # The worker exposes /metrics only on its pod IP (no ClusterIP Service in # worker.yaml) → pod SD, keep the worker container, pin port 4003. - job_name: factory-worker metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_namespace] regex: "factory" action: keep - source_labels: [__meta_kubernetes_pod_container_name] regex: "worker" action: keep - source_labels: [__meta_kubernetes_pod_ip] target_label: __address__ replacement: "$1:4003" - target_label: service_name replacement: factory-worker - job_name: factory-realtime metrics_path: /metrics static_configs: - targets: ["realtime.factory.svc.cluster.local:4001"] labels: service_name: factory-realtime # web serves the exposition at /api/metrics (Next.js app route). - job_name: factory-web metrics_path: /api/metrics static_configs: - targets: ["web.factory.svc.cluster.local:3000"] labels: service_name: factory-web # --- node exporter (expected-present; see header) --------------------------- - job_name: node-exporter kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_container_name] regex: "node-exporter" action: keep - source_labels: [__meta_kubernetes_pod_node_name] target_label: node - target_label: service_name replacement: node-exporter # --- self ------------------------------------------------------------------- - job_name: prometheus static_configs: - targets: ["localhost:9090"]