Files
homelab/k8s/infra/logging/grafana-values.yaml
T

212 lines
8.0 KiB
YAML
Raw Normal View History

# logging/grafana-values.yaml
# Grafana — dashboarding and log/metrics exploration UI.
# Deployed in the logging namespace alongside Loki and Promtail.
#
# Secrets provided by ArgoCD SOPS CMP plugin:
# adminPassword — mounted from the grafana-admin K8s Secret (admin.existingSecret)
# 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:
secret.reloader.stakater.com/reload: "grafana-oidc,grafana-admin"
adminUser: admin
admin:
existingSecret: grafana-admin
existingSecretKey: admin-password
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:
root_url: https://grafana.riotpiao.com
# Allow embedding dashboards in iframes (NextJS integration)
security:
allow_embedding: true
# 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
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/
# 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
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
# 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]
# ClusterIP only — access via ingress (grafana.riotpiao.com) or port-forward.
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