1# ============================================================================= 2# Grafana (TASK-0135, phase-15) — Deployment + Service, ns `monitoring`. 3# 4# Provisioning + dashboards are generated into ConfigMaps by kustomization.yaml 5# FROM infrastructure/observability/grafana/ (single source of truth): 6# /etc/grafana/provisioning/datasources/datasource.yaml (uid factory-prometheus) 7# /etc/grafana/provisioning/dashboards/dashboards.yaml (provider → folder "Factory") 8# /var/lib/grafana/dashboards/*.json (the six dashboards) 9# 10# The admin password comes from the `grafana-admin` secret (key 11# admin-password) — create it before applying (like factory-secrets): 12# kubectl -n monitoring create secret generic grafana-admin \ 13# --from-literal=admin-password='$(openssl rand -base64 18)' 14# Image pinned: grafana/grafana:10.4.0. 15# ============================================================================= 16apiVersion: apps/v1 17kind: Deployment 18metadata: 19 name: grafana 20 namespace: monitoring 21 labels: 22 app.kubernetes.io/name: grafana 23 app.kubernetes.io/part-of: ai-software-factory 24spec: 25 replicas: 1 26 selector: 27 matchLabels: 28 app.kubernetes.io/name: grafana 29 strategy: 30 type: Recreate 31 template: 32 metadata: 33 labels: 34 app.kubernetes.io/name: grafana 35 spec: 36 containers: 37 - name: grafana 38 image: grafana/grafana:10.4.0 39 imagePullPolicy: IfNotPresent 40 ports: 41 - containerPort: 3000 42 name: http 43 env: 44 - name: GF_SECURITY_ADMIN_USER 45 value: admin 46 - name: GF_SECURITY_ADMIN_PASSWORD__FILE 47 value: /etc/grafana-secret/admin-password 48 - name: GF_USERS_ALLOW_SIGN_UP 49 value: "false" 50 - name: GF_ANALYTICS_REPORTING_ENABLED 51 value: "false" 52 - name: GF_ANALYTICS_CHECK_FOR_UPDATES 53 value: "false" 54 volumeMounts: 55 - name: datasources 56 mountPath: /etc/grafana/provisioning/datasources 57 readOnly: true 58 - name: dashboards-provider 59 mountPath: /etc/grafana/provisioning/dashboards 60 readOnly: true 61 - name: dashboards 62 mountPath: /var/lib/grafana/dashboards 63 readOnly: true 64 - name: admin-secret 65 mountPath: /etc/grafana-secret 66 readOnly: true 67 - name: data 68 mountPath: /var/lib/grafana 69 readinessProbe: 70 httpGet: 71 path: /api/health 72 port: 3000 73 initialDelaySeconds: 10 74 periodSeconds: 10 75 livenessProbe: 76 httpGet: 77 path: /api/health 78 port: 3000 79 initialDelaySeconds: 30 80 periodSeconds: 15 81 resources: 82 requests: 83 cpu: 100m 84 memory: 256Mi 85 limits: 86 cpu: 500m 87 memory: 1Gi 88 securityContext: 89 allowPrivilegeEscalation: false 90 runAsNonRoot: true 91 # the grafana image runs as `grafana` (uid 472) by default 92 runAsUser: 472 93 runAsGroup: 472 94 seccompProfile: 95 type: RuntimeDefault 96 terminationGracePeriodSeconds: 20 97 volumes: 98 - name: datasources 99 configMap: 100 name: grafana-datasources # hashed name substituted by kustomize 101 - name: dashboards-provider 102 configMap: 103 name: grafana-dashboards-provider # hashed name substituted by kustomize 104 - name: dashboards 105 configMap: 106 name: grafana-dashboards # hashed name substituted by kustomize 107 - name: admin-secret 108 secret: 109 secretName: grafana-admin # created out-of-band (see header) 110 - name: data 111 emptyDir: {} 112--- 113apiVersion: v1 114kind: Service 115metadata: 116 name: grafana 117 namespace: monitoring 118 labels: 119 app.kubernetes.io/name: grafana 120 app.kubernetes.io/part-of: ai-software-factory 121spec: 122 selector: 123 app.kubernetes.io/name: grafana 124 ports: 125 - name: http 126 port: 3000 127 targetPort: 3000 128