2026-07-11 19:17:28 -07:00
|
|
|
# logging/grafana-values.yaml
|
|
|
|
|
# Grafana — dashboarding and log/metrics exploration UI.
|
|
|
|
|
# Deployed in the logging namespace alongside Loki and Promtail.
|
|
|
|
|
#
|
2026-08-18 15:08:02 -07:00
|
|
|
# Secrets provided by ArgoCD SOPS CMP plugin:
|
|
|
|
|
# adminPassword — mounted from the grafana-admin K8s Secret (admin.existingSecret)
|
2026-07-11 19:17:28 -07:00
|
|
|
# OAuth client secret — mounted from the grafana-oidc K8s Secret (envFromSecret below)
|
|
|
|
|
|
|
|
|
|
replicas: 1
|
|
|
|
|
|
|
|
|
|
# RWO PVC (Longhorn) — old pod must fully terminate before the new one can
|
|
|
|
|
# mount the volume. Recreate avoids the "two pods fighting over one PVC" failure.
|
|
|
|
|
deploymentStrategy:
|
|
|
|
|
type: Recreate
|
|
|
|
|
|
|
|
|
|
podAnnotations:
|
2026-08-18 15:08:02 -07:00
|
|
|
secret.reloader.stakater.com/reload: "grafana-oidc,grafana-admin"
|
2026-07-11 19:17:28 -07:00
|
|
|
|
|
|
|
|
adminUser: admin
|
2026-08-18 15:08:02 -07:00
|
|
|
admin:
|
|
|
|
|
existingSecret: grafana-admin
|
|
|
|
|
existingSecretKey: admin-password
|
2026-07-11 19:17:28 -07:00
|
|
|
|
|
|
|
|
resources:
|
|
|
|
|
requests:
|
|
|
|
|
cpu: 100m
|
|
|
|
|
memory: 128Mi
|
|
|
|
|
limits:
|
|
|
|
|
cpu: 500m
|
|
|
|
|
memory: 256Mi
|
|
|
|
|
|
|
|
|
|
# ── Persistence ───────────────────────────────────────────────────────────────
|
|
|
|
|
# Stores dashboards saved in the UI, datasource edits, and user sessions.
|
|
|
|
|
# Longhorn provides the RWO block volume; 5Gi is ample for dashboard JSON.
|
|
|
|
|
persistence:
|
|
|
|
|
enabled: true
|
|
|
|
|
storageClassName: longhorn
|
|
|
|
|
accessModes:
|
|
|
|
|
- ReadWriteOnce
|
|
|
|
|
size: 5Gi
|
|
|
|
|
|
|
|
|
|
# ── Grafana config ────────────────────────────────────────────────────────────
|
|
|
|
|
grafana.ini:
|
|
|
|
|
server:
|
2026-07-19 09:29:17 -07:00
|
|
|
root_url: https://grafana.riotpiao.com
|
2026-07-11 19:17:28 -07:00
|
|
|
|
|
|
|
|
# No anonymous read access — every user must log in via Authentik SSO.
|
|
|
|
|
auth.anonymous:
|
|
|
|
|
enabled: false
|
|
|
|
|
|
|
|
|
|
# Explore tab: required for ad-hoc LogQL/PromQL queries against Loki/Prometheus.
|
|
|
|
|
explore:
|
|
|
|
|
enabled: true
|
|
|
|
|
|
|
|
|
|
# WAL for the embedded SQLite DB — prevents corruption on ungraceful shutdown.
|
|
|
|
|
database:
|
|
|
|
|
wal: true
|
|
|
|
|
|
|
|
|
|
# ── Authentik OIDC (generic OAuth2) ───────────────────────────────────────
|
|
|
|
|
# Grafana v10+ supports OIDC auto-discovery; we wire it manually here because
|
|
|
|
|
# Authentik's discovery endpoint is internal-only (no external DNS for iam.svc).
|
|
|
|
|
# All URLs use the external hostname so CoreDNS rewrites them to
|
|
|
|
|
# authentik-server.iam.svc — this keeps the Host header correct so Authentik
|
|
|
|
|
# doesn't return localhost redirects in its token responses.
|
|
|
|
|
#
|
|
|
|
|
# role_attribute_path: JMESPath expression evaluated against the userinfo
|
|
|
|
|
# response. Members of the 'grafana-admins' Authentik group get Admin role;
|
|
|
|
|
# everyone else gets Viewer. The group name must match exactly what Authentik
|
|
|
|
|
# sends in the 'groups' claim.
|
|
|
|
|
auth.generic_oauth:
|
|
|
|
|
enabled: true
|
|
|
|
|
name: Authentik
|
|
|
|
|
allow_sign_up: true
|
|
|
|
|
client_id: grafana
|
|
|
|
|
scopes: openid email profile
|
2026-07-19 09:29:17 -07:00
|
|
|
auth_url: https://authentik.riotpiao.com/application/o/authorize/
|
|
|
|
|
token_url: https://authentik.riotpiao.com/application/o/token/
|
|
|
|
|
api_url: https://authentik.riotpiao.com/application/o/userinfo/
|
2026-08-12 16:46:57 -07:00
|
|
|
# Read identity straight from the userinfo/id_token claims. Without these,
|
|
|
|
|
# Grafana falls back to the GitHub-style "<api_url>/emails" call, which
|
|
|
|
|
# Authentik doesn't serve — request 404s with "Error getting email address"
|
|
|
|
|
# and the whole OAuth login fails.
|
|
|
|
|
email_attribute_path: email
|
|
|
|
|
login_attribute_path: preferred_username
|
|
|
|
|
name_attribute_path: name
|
2026-07-11 19:17:28 -07:00
|
|
|
role_attribute_path: "contains(groups[*], 'grafana-admins') && 'Admin' || 'Viewer'"
|
|
|
|
|
use_pkce: false
|
|
|
|
|
use_refresh_token: false
|
|
|
|
|
skip_org_role_sync: false
|
|
|
|
|
tls_skip_verify_insecure: true # Authentik uses self-signed cert; verify in prod
|
|
|
|
|
|
|
|
|
|
# GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET is injected from the grafana-oidc K8s
|
|
|
|
|
# Secret (created by k8s/talos-iam/setup_talos_iam.sh). envFromSecret mounts
|
|
|
|
|
# every key in that secret as an environment variable — keeps secrets out of
|
|
|
|
|
# values files and out of git.
|
|
|
|
|
envFromSecret: grafana-oidc
|
|
|
|
|
|
|
|
|
|
# ── Datasources ───────────────────────────────────────────────────────────────
|
|
|
|
|
# Provisioned at install — no manual "Add datasource" step in the UI.
|
|
|
|
|
# Loki is the default (log exploration); Prometheus is secondary (metrics).
|
|
|
|
|
# Both use in-cluster service DNS — Grafana never leaves the cluster for data.
|
|
|
|
|
datasources:
|
|
|
|
|
datasources.yaml:
|
|
|
|
|
apiVersion: 1
|
|
|
|
|
datasources:
|
|
|
|
|
- name: Loki
|
|
|
|
|
type: loki
|
|
|
|
|
uid: loki
|
|
|
|
|
access: proxy
|
|
|
|
|
url: http://loki.logging.svc.cluster.local:3100
|
|
|
|
|
isDefault: true
|
|
|
|
|
version: 1
|
|
|
|
|
editable: true
|
|
|
|
|
jsonData:
|
|
|
|
|
maxLines: 1000
|
|
|
|
|
timeout: 60
|
|
|
|
|
- name: Prometheus
|
|
|
|
|
type: prometheus
|
|
|
|
|
uid: prometheus
|
|
|
|
|
access: proxy
|
|
|
|
|
url: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090
|
|
|
|
|
isDefault: false
|
|
|
|
|
version: 1
|
|
|
|
|
editable: true
|
|
|
|
|
jsonData:
|
|
|
|
|
timeInterval: 30s
|
|
|
|
|
timeout: 60
|
|
|
|
|
|
|
|
|
|
# ── Dashboard providers ───────────────────────────────────────────────────────
|
|
|
|
|
# Tells Grafana to watch a directory for dashboard JSON files.
|
|
|
|
|
# The `dashboards` block below populates that directory via an init container
|
|
|
|
|
# that downloads from grafana.com at install time.
|
|
|
|
|
dashboardProviders:
|
|
|
|
|
dashboardproviders.yaml:
|
|
|
|
|
apiVersion: 1
|
|
|
|
|
providers:
|
|
|
|
|
- name: default
|
|
|
|
|
orgId: 1
|
|
|
|
|
folder: ""
|
|
|
|
|
type: file
|
|
|
|
|
disableDeletion: false
|
|
|
|
|
editable: true
|
|
|
|
|
options:
|
|
|
|
|
path: /var/lib/grafana/dashboards/default
|
|
|
|
|
|
|
|
|
|
# ── Pre-loaded dashboards ──────────────────────────────────────────────────────
|
|
|
|
|
# Fetched from grafana.com by an init container at helm-install time and baked
|
|
|
|
|
# into ConfigMaps. gnetId + revision pin the exact dashboard version so an
|
|
|
|
|
# upstream change on grafana.com doesn't silently alter what's deployed.
|
|
|
|
|
dashboards:
|
|
|
|
|
default:
|
|
|
|
|
node-exporter-full:
|
|
|
|
|
gnetId: 1860
|
|
|
|
|
revision: 37
|
|
|
|
|
datasource: Prometheus
|
|
|
|
|
kubernetes-cluster:
|
|
|
|
|
gnetId: 7249
|
|
|
|
|
revision: 1
|
|
|
|
|
datasource: Prometheus
|
|
|
|
|
|
|
|
|
|
# Allow scheduling on the control-plane node (talos-cp-1 carries NoSchedule taint).
|
|
|
|
|
tolerations:
|
|
|
|
|
- key: node-role.kubernetes.io/control-plane
|
|
|
|
|
operator: Exists
|
|
|
|
|
effect: NoSchedule
|
|
|
|
|
|
2026-08-18 15:08:02 -07:00
|
|
|
# Pin to az-a (talos-cp-1) — the only node running Longhorn. Without this the
|
|
|
|
|
# scheduler may place grafana on cp-2/cp-3, where its Longhorn PVC cannot attach
|
|
|
|
|
# ("CSINode does not contain driver driver.longhorn.io").
|
|
|
|
|
affinity:
|
|
|
|
|
nodeAffinity:
|
|
|
|
|
requiredDuringSchedulingIgnoredDuringExecution:
|
|
|
|
|
nodeSelectorTerms:
|
|
|
|
|
- matchExpressions:
|
|
|
|
|
- key: topology.kubernetes.io/zone
|
|
|
|
|
operator: In
|
|
|
|
|
values: [az-a]
|
|
|
|
|
|
2026-07-19 09:29:17 -07:00
|
|
|
# ClusterIP only — access via ingress (grafana.riotpiao.com) or port-forward.
|
2026-07-11 19:17:28 -07:00
|
|
|
service:
|
|
|
|
|
type: ClusterIP
|
|
|
|
|
port: 80
|
|
|
|
|
|
|
|
|
|
# Ingress managed by k8s/ingress/ingress.yaml — not the chart's built-in ingress.
|
|
|
|
|
ingress:
|
|
|
|
|
enabled: false
|
|
|
|
|
|
|
|
|
|
serviceMonitor:
|
|
|
|
|
enabled: false
|
|
|
|
|
|
|
|
|
|
# ── Dashboard-as-code (sidecar discovery) ──────────────────────────────────────
|
|
|
|
|
# Additive to the gnetId-download mechanism above. The sidecar watches for
|
|
|
|
|
# ConfigMaps labeled grafana_dashboard=1 in ANY namespace and loads them live —
|
|
|
|
|
# no Grafana restart needed when a new dashboard ConfigMap is applied.
|
|
|
|
|
sidecar:
|
|
|
|
|
dashboards:
|
|
|
|
|
enabled: true
|
|
|
|
|
label: grafana_dashboard
|
|
|
|
|
labelValue: "1"
|
|
|
|
|
folder: /var/lib/grafana/dashboards/custom
|
|
|
|
|
folderAnnotation: grafana_folder
|
|
|
|
|
provider:
|
|
|
|
|
name: custom
|
|
|
|
|
folder: "Homelab"
|
|
|
|
|
disableDelete: false
|
|
|
|
|
foldersFromFilesStructure: true
|
|
|
|
|
searchNamespace: ALL
|