From 0f12ce25c7ac4a8a1b16a9c729b3a87ade7579f4 Mon Sep 17 00:00:00 2001 From: Alex Lebens Date: Wed, 14 May 2025 22:15:41 -0500 Subject: [PATCH] add grafana operator --- .../monitoring/grafana-operator/Chart.yaml | 27 +++++ .../templates/external-secret.yaml | 62 ++++++++++ .../templates/grafana-dashboard.yaml | 18 +++ .../templates/grafana-datasource.yaml | 60 ++++++++++ .../templates/grafana-folder.yaml | 109 ++++++++++++++++++ .../grafana-operator/templates/grafana.yaml | 107 +++++++++++++++++ .../templates/http-route.yaml | 30 +++++ .../monitoring/grafana-operator/values.yaml | 38 ++++++ .../cl01tl/monitoring/grafana/values.yaml | 4 +- 9 files changed, 453 insertions(+), 2 deletions(-) create mode 100644 clusters/cl01tl/monitoring/grafana-operator/Chart.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/external-secret.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/grafana-dashboard.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/grafana-datasource.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/grafana-folder.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/grafana.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/templates/http-route.yaml create mode 100644 clusters/cl01tl/monitoring/grafana-operator/values.yaml diff --git a/clusters/cl01tl/monitoring/grafana-operator/Chart.yaml b/clusters/cl01tl/monitoring/grafana-operator/Chart.yaml new file mode 100644 index 000000000..719e980d7 --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: grafana-operator +version: 1.0.0 +description: Grafana Operator +keywords: + - grafana-operator + - dashboard + - metrics + - logs +home: https://wiki.alexlebens.dev/s/3e5723e1-2ab7-45ab-b496-b8854907fa39 +sources: + - https://github.com/grafana/grafana-operator + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/grafana/grafana-operator/tree/master/deploy/helm/grafana-operator + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: grafana-operator + version: v5.18.0 + repository: oci://ghcr.io/grafana/helm-charts/grafana-operator + - name: postgres-cluster + alias: postgres-17-cluster + version: 5.0.7 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/grafana.png +appVersion: v5.18.0 diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/external-secret.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/external-secret.yaml new file mode 100644 index 000000000..81da4d4bc --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/external-secret.yaml @@ -0,0 +1,62 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: grafana-auth-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: admin-user + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/grafana/auth + metadataPolicy: None + property: admin-user + - secretKey: admin-password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/grafana/auth + metadataPolicy: None + property: admin-password + +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: grafana-oauth-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-oauth-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: AUTH_CLIENT_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/grafana + metadataPolicy: None + property: client + - secretKey: AUTH_CLIENT_SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/grafana + metadataPolicy: None + property: secret diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-dashboard.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-dashboard.yaml new file mode 100644 index 000000000..b6492f3e2 --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-dashboard.yaml @@ -0,0 +1,18 @@ +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: grafana-operator-dashboard + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-operator-dashboard + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + grafanaCom: + id: 22785 + revision: 2 diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-datasource.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-datasource.yaml new file mode 100644 index 000000000..8ef57e4ed --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-datasource.yaml @@ -0,0 +1,60 @@ +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDatasource +metadata: + name: grafana-operator-prometheus-datasource + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-operator-prometheus-datasource + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: metrics + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + datasource: + name: Prometheus + type: prometheus + url: http://kube-prometheus-stack-prometheus.kube-prometheus-stack:9090/ + access: proxy + isDefault: true + jsonData: + timeInterval: 30s + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + plugins: + - name: grafana-clock-panel + version: 1.3.0 + - name: marcusolsson-treemap-panel + version: 2.0.1 + - name: camptocamp-prometheus-alertmanager-datasource + version: 2.1.0 + uid: kube-prometheus-stack + +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDatasource +metadata: + name: grafana-operator-loki-datasource + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-operator-loki-datasource + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: logs + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + datasource: + name: Loki + type: loki + url: http://loki.loki:3100 + jsonData: + httpHeaderName1: "X-Scope-OrgID" + secureJsonData: + httpHeaderValue1: "1" + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + plugins: + - name: grafana-lokiexplore-app + version: 1.0.15 + uid: loki diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-folder.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-folder.yaml new file mode 100644 index 000000000..7cd25f2e7 --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana-folder.yaml @@ -0,0 +1,109 @@ +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaFolder +metadata: + name: grafana-folder-application + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-folder-application + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + title: Application + uid: grafana-folder-application + resyncPeriod: 10m0s + permissions: | + { + "items": [ + { + "role": "Admin", + "permission": 4 + }, + { + "role": "Editor", + "permission": 2 + }, + { + "role": "Viewer", + "permission": 1 + } + ] + } + +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaFolder +metadata: + name: grafana-folder-service + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-folder-service + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + title: Service + uid: grafana-folder-service + resyncPeriod: 10m0s + permissions: | + { + "items": [ + { + "role": "Admin", + "permission": 4 + }, + { + "role": "Editor", + "permission": 2 + }, + { + "role": "Viewer", + "permission": 1 + } + ] + } + +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaFolder +metadata: + name: grafana-folder-system + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-folder-system + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + instanceSelector: + matchLabels: + app.kubernetes.io/name: grafana-main + title: System + uid: grafana-folder-system + resyncPeriod: 10m0s + permissions: | + { + "items": [ + { + "role": "Admin", + "permission": 4 + }, + { + "role": "Editor", + "permission": 2 + }, + { + "role": "Viewer", + "permission": 1 + } + ] + } diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/grafana.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana.yaml new file mode 100644 index 000000000..8592a761e --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/grafana.yaml @@ -0,0 +1,107 @@ +apiVersion: grafana.integreatly.org/v1beta1 +kind: Grafana +metadata: + name: grafana-main + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-main + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + config: + analytics: + check_for_updates: false + server: + domain: alexlebens.net + root_url: https://grafana.alexlebens.net + log: + mode: "console" + security: + admin_user: ${ADMIN_USER} + admin_password: ${ADMIN_PASSWORD} + users: + auto_assign_org: true + auto_assign_org_id: 1 + auth: + disable_login_form: true + oauth_auto_login: true + signout_redirect_url: https://authentik.alexlebens.net/application/o/grafana/end-session/ + auth.generic_oauth: + enabled: true + name: Authentik + allow_sign_up: true + client_id: ${AUTH_CLIENT_ID} + client_secret: ${AUTH_CLIENT_SECRET} + scopes: openid profile email + auth_url: https://authentik.alexlebens.net/application/o/authorize/ + token_url: https://authentik.alexlebens.net/application/o/token/ + api_url: https://authentik.alexlebens.net/application/o/userinfo/ + role_attribute_path: contains(groups, 'Grafana Admins') && 'Admin' || contains(groups, 'Grafana Editors') && 'Editor' || 'Viewer' + database: + type: postgres + host: "${DB_HOST}:${DB_PORT}" + name: ${DB_DATABASE} + user: ${DB_USER} + password: ${DB_PASSWORD} + unified_alerting: + enabled: true + ha_listen_address: "${POD_IP}:9094" + ha_peers: "grafana-alerting:9094" + ha_advertise_address: "${POD_IP}:9094" + ha_peer_timeout: 15s + ha_reconnect_timeout: 2m + deployment: + spec: + template: + spec: + containers: + - name: grafana + image: grafana/grafana:12.0.0 + env: + - name: AUTH_CLIENT_ID + valueFrom: + secretKeyRef: + name: grafana-oauth-secret + key: AUTH_CLIENT_ID + - name: AUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: grafana-oauth-secret + key: AUTH_CLIENT_SECRET + - name: ADMIN_USER + valueFrom: + secretKeyRef: + name: grafana-auth-secret + key: admin-user + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: grafana-auth-secret + key: admin-password + - name: DB_HOST + valueFrom: + secretKeyRef: + name: grafana-operator-postgresql-17-cluster-app + key: host + - name: DB_DATABASE + valueFrom: + secretKeyRef: + name: grafana-operator-postgresql-17-cluster-app + key: dbname + - name: DB_PORT + valueFrom: + secretKeyRef: + name: grafana-operator-postgresql-17-cluster-app + key: port + - name: DB_USER + valueFrom: + secretKeyRef: + name: grafana-operator-postgresql-17-cluster-app + key: user + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: grafana-operator-postgresql-17-cluster-app + key: password diff --git a/clusters/cl01tl/monitoring/grafana-operator/templates/http-route.yaml b/clusters/cl01tl/monitoring/grafana-operator/templates/http-route.yaml new file mode 100644 index 000000000..3d1459d81 --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/templates/http-route.yaml @@ -0,0 +1,30 @@ +# apiVersion: gateway.networking.k8s.io/v1 +# kind: HTTPRoute +# metadata: +# name: http-route-grafana +# namespace: {{ .Release.Namespace }} +# labels: +# app.kubernetes.io/name: http-route-grafana +# app.kubernetes.io/instance: {{ .Release.Name }} +# app.kubernetes.io/version: {{ .Chart.AppVersion }} +# app.kubernetes.io/component: web +# app.kubernetes.io/part-of: {{ .Release.Name }} +# spec: +# parentRefs: +# - group: gateway.networking.k8s.io +# kind: Gateway +# name: traefik-gateway +# namespace: traefik +# hostnames: +# - grafana.alexlebens.net +# rules: +# - matches: +# - path: +# type: PathPrefix +# value: / +# backendRefs: +# - group: '' +# kind: Service +# name: grafana +# port: 80 +# weight: 100 diff --git a/clusters/cl01tl/monitoring/grafana-operator/values.yaml b/clusters/cl01tl/monitoring/grafana-operator/values.yaml new file mode 100644 index 000000000..d1dbb6028 --- /dev/null +++ b/clusters/cl01tl/monitoring/grafana-operator/values.yaml @@ -0,0 +1,38 @@ +grafana-operator: + replicas: 2 + serviceAccount: + create: true + rbac: + create: true + resources: + requests: + cpu: 10m + memory: 64Mi + serviceMonitor: + enabled: true + dashboard: + enabled: false +postgres-17-cluster: + mode: standalone + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + endpointURL: https://nyc3.digitaloceanspaces.com + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/grafana-operator/grafana-operator-postgresql-17-cluster + endpointCredentials: grafana-operator-postgresql-17-cluster-backup-secret + recoveryIndex: 1 + backup: + enabled: true + endpointURL: https://nyc3.digitaloceanspaces.com + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/grafana-operator/grafana-operator-postgresql-17-cluster + endpointCredentials: grafana-operator-postgresql-17-cluster-backup-secret + backupIndex: 1 diff --git a/clusters/cl01tl/monitoring/grafana/values.yaml b/clusters/cl01tl/monitoring/grafana/values.yaml index c032a52d8..ec1e8997f 100644 --- a/clusters/cl01tl/monitoring/grafana/values.yaml +++ b/clusters/cl01tl/monitoring/grafana/values.yaml @@ -85,8 +85,8 @@ grafana: url: http://gitea-http.gitea:3000/alexlebens/grafana-dashboards/raw/branch/main/dashboards/service/blocky.json cert-manager: url: http://gitea-http.gitea:3000/alexlebens/grafana-dashboards/raw/branch/main/dashboards/service/cert-manager.json - # cloudnativepg: - # url: http://gitea-http.gitea:3000/alexlebens/grafana-dashboards/raw/branch/main/dashboards/service/cloudnativepg.json + cloudnativepg: + url: http://gitea-http.gitea:3000/alexlebens/grafana-dashboards/raw/branch/main/dashboards/service/cloudnativepg.json coredns: url: http://gitea-http.gitea:3000/alexlebens/grafana-dashboards/raw/branch/main/dashboards/service/coredns.json descheduler: