blumeops/argocd/manifests/grafana/deployment.yaml

298 lines
11 KiB
YAML
Raw Normal View History

apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: monitoring
labels:
app.kubernetes.io/name: grafana
app.kubernetes.io/instance: grafana
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: grafana
app.kubernetes.io/instance: grafana
strategy:
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: grafana
app.kubernetes.io/instance: grafana
annotations:
kubectl.kubernetes.io/default-container: grafana
spec:
automountServiceAccountToken: true
serviceAccountName: grafana
securityContext:
fsGroup: 472
runAsGroup: 472
runAsNonRoot: true
runAsUser: 472
initContainers:
- name: init-chown-data
image: docker.io/library/busybox:kustomized
imagePullPolicy: IfNotPresent
command: ["chown", "-R", "472:472", "/var/lib/grafana"]
securityContext:
runAsNonRoot: false
runAsUser: 0
capabilities:
add: ["CHOWN"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: storage
mountPath: /var/lib/grafana
# Fetch TeslaMate dashboards from forge mirror at a pinned tag.
# To upgrade: update TESLAMATE_VERSION below.
- name: init-teslamate-dashboards
image: docker.io/library/alpine:kustomized
imagePullPolicy: IfNotPresent
command: ["sh", "-c"]
args:
- |
set -e
TESLAMATE_VERSION="v3.0.0"
BASE_URL="https://forge.ops.eblu.me/mirrors/teslamate/raw/tag/${TESLAMATE_VERSION}/grafana/dashboards"
DEST="/tmp/dashboards/TeslaMate"
mkdir -p "$DEST"
for f in \
battery-health.json \
charge-level.json \
charges.json \
charging-stats.json \
drive-stats.json \
drives.json \
efficiency.json \
locations.json \
mileage.json \
overview.json \
projected-range.json \
states.json \
statistics.json \
timeline.json \
trip.json \
updates.json \
vampire-drain.json \
visited.json \
; do
wget -q -O "$DEST/$f" "$BASE_URL/$f"
done
# Stamp stable top-level UIDs so stars/bookmarks survive pod restarts
# Uses 0,/pattern/ to replace only the first "uid" (the dashboard UID),
# leaving datasource UIDs inside panels untouched.
for f in "$DEST"/*.json; do
uid="teslamate-$(basename "$f" .json)"
sed -i "0,/\"uid\": *\"[^\"]*\"/{s/\"uid\": *\"[^\"]*\"/\"uid\": \"${uid}\"/}" "$f"
done
echo "Fetched $(ls "$DEST" | wc -l) TeslaMate dashboards"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: sc-dashboard-volume
mountPath: /tmp/dashboards
# Fetch UnPoller (UniFi) dashboards from forge mirror.
# Source: github.com/unpoller/dashboards (v2.0.0 Prometheus set)
- name: init-unpoller-dashboards
image: docker.io/library/alpine:kustomized
imagePullPolicy: IfNotPresent
command: ["sh", "-c"]
args:
- |
set -e
BASE_URL="https://forge.ops.eblu.me/mirrors/unpoller-dashboards/raw/branch/master/v2.0.0"
DEST="/tmp/dashboards/UniFi"
mkdir -p "$DEST"
# DPI dashboard omitted — requires DPI enabled on both UX7 and UnPoller
for f in \
"UniFi-Poller_ Client Insights - Prometheus.json" \
"UniFi-Poller_ Network Sites - Prometheus.json" \
"UniFi-Poller_ UAP Insights - Prometheus.json" \
"UniFi-Poller_ USG Insights - Prometheus.json" \
"UniFi-Poller_ USW Insights - Prometheus.json" \
; do
wget -q -O "$DEST/$f" "$BASE_URL/$(echo "$f" | sed 's/ /%20/g')"
done
# Fix datasource UIDs to match our Prometheus instance
sed -i 's/"uid": *"bdkj55oguty4gd"/"uid": "prometheus"/g' "$DEST"/*.json
sed -i 's/"uid": *"\${DS_PROMETHEUS}"/"uid": "prometheus"/g' "$DEST"/*.json
# Stamp stable top-level UIDs so stars/bookmarks survive pod restarts
for f in "$DEST"/*.json; do
slug=$(basename "$f" .json | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
uid="unpoller-${slug}"
sed -i "0,/\"uid\": *\"[^\"]*\"/{s/\"uid\": *\"[^\"]*\"/\"uid\": \"${uid}\"/}" "$f"
done
echo "Fetched $(ls "$DEST" | wc -l) UnPoller dashboards"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: sc-dashboard-volume
mountPath: /tmp/dashboards
# Pre-populate ConfigMap dashboards so they exist before Grafana starts.
# Without this, the sidecar and Grafana race: if the provisioner scans
# before the sidecar writes files, it deletes existing DB records and
# re-creates them with new IDs, breaking starred dashboards.
- name: init-configmap-dashboards
image: registry.ops.eblu.me/blumeops/grafana-sidecar:kustomized
imagePullPolicy: IfNotPresent
env:
- name: METHOD
value: LIST
- name: LABEL
value: grafana_dashboard
- name: LABEL_VALUE
value: "1"
- name: FOLDER
value: /tmp/dashboards
- name: RESOURCE
value: both
- name: FOLDER_ANNOTATION
value: grafana_folder
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: sc-dashboard-volume
mountPath: /tmp/dashboards
containers:
# Dashboard sidecar - watches ConfigMaps with grafana_dashboard=1
- name: grafana-sc-dashboard
image: registry.ops.eblu.me/blumeops/grafana-sidecar:kustomized
imagePullPolicy: IfNotPresent
env:
- name: METHOD
value: WATCH
- name: LABEL
value: grafana_dashboard
- name: LABEL_VALUE
value: "1"
- name: FOLDER
value: /tmp/dashboards
- name: RESOURCE
value: both
- name: FOLDER_ANNOTATION
value: grafana_folder
- name: REQ_USERNAME
valueFrom:
secretKeyRef:
name: grafana-admin
key: admin-user
- name: REQ_PASSWORD
valueFrom:
secretKeyRef:
name: grafana-admin
key: admin-password
- name: REQ_URL
value: http://localhost:3000/api/admin/provisioning/dashboards/reload
- name: REQ_METHOD
value: POST
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: sc-dashboard-volume
mountPath: /tmp/dashboards
# Grafana
- name: grafana
image: registry.ops.eblu.me/blumeops/grafana:kustomized
imagePullPolicy: IfNotPresent
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: GF_SECURITY_ADMIN_USER
valueFrom:
secretKeyRef:
name: grafana-admin
key: admin-user
- name: GF_SECURITY_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: grafana-admin
key: admin-password
- name: GF_PATHS_DATA
value: /var/lib/grafana/
- name: GF_PATHS_LOGS
value: /var/log/grafana
- name: GF_PATHS_PLUGINS
value: /var/lib/grafana/plugins
- name: GF_PATHS_PROVISIONING
value: /etc/grafana/provisioning
envFrom:
- secretRef:
name: grafana-teslamate-datasource
optional: true
- secretRef:
name: grafana-authentik-oauth
optional: true
ports:
- name: http
containerPort: 3000
protocol: TCP
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 60
timeoutSeconds: 30
failureThreshold: 10
readinessProbe:
httpGet:
path: /api/health
port: 3000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: config
mountPath: /etc/grafana/grafana.ini
subPath: grafana.ini
- name: config
mountPath: /etc/grafana/provisioning/datasources/datasources.yaml
subPath: datasources.yaml
- name: storage
mountPath: /var/lib/grafana
- name: sc-dashboard-volume
mountPath: /tmp/dashboards
- name: sc-dashboard-provider
mountPath: /etc/grafana/provisioning/dashboards/sc-dashboardproviders.yaml
subPath: provider.yaml
volumes:
- name: config
configMap:
name: grafana
- name: storage
persistentVolumeClaim:
claimName: grafana
- name: sc-dashboard-volume
emptyDir: {}
- name: sc-dashboard-provider
configMap:
name: grafana-config-dashboards