feat: Automate ConfigMap checksum updates via Git pre-commit hook
- Add pre-commit hook (scripts/hooks/pre-commit) that automatically calculates MD5 checksums of ConfigMaps (element-values.yaml, synapse-values.yaml) - Update annotations in kustomization.yaml to trigger Flux CD HelmRelease syncs - Add install script (scripts/install-hooks.sh) for easy hook setup - Add comprehensive documentation (docs/ops-configmap-sync.md) explaining: * Why Flux doesn't auto-detect ConfigMap changes * How the checksum-based workaround works * How to install and use the hook * Troubleshooting and manual sync procedures - Update README.md with post-clone hook installation step This solves the issue where Flux CD doesn't automatically re-deploy when external ConfigMaps are modified. Users no longer need manual checksum updates. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
174e9721ed
commit
5f50a60071
@ -53,6 +53,12 @@ winget install Kubernetes.kubectl FluxCD.Flux Mozilla.sops age-encryption.age He
|
||||
|
||||
1. **Kubeconfig:** Stelle sicher, dass die Datei `~/.kube/config` mit den Zugangsdaten zu deinem K3s-Cluster gefüllt ist. Test: `kubectl get nodes`.
|
||||
2. **SOPS Key:** Du benötigst den privaten `age`-Key (oder GPG-Key), der in der `.sops.yaml` des Repositories hinterlegt ist, um Secrets bearbeiten zu können.
|
||||
3. **Git Hooks installieren:** Nach dem Klonen dieses Repositories müssen Git Hooks installiert werden, um ConfigMap-Änderungen automatisch zu tracken:
|
||||
```bash
|
||||
cd prod/gitops
|
||||
./scripts/install-hooks.sh
|
||||
```
|
||||
Siehe [📖 GitOps ConfigMap Auto-Sync](docs/ops-configmap-sync.md) für Details.
|
||||
|
||||
-----
|
||||
|
||||
|
||||
296
docs/ops-configmap-sync.md
Normal file
296
docs/ops-configmap-sync.md
Normal file
@ -0,0 +1,296 @@
|
||||
# 🔄 GitOps ConfigMap Auto-Sync via Checksums
|
||||
|
||||
Dieses Dokument erklärt ein Kernproblem mit **Flux CD** und **externe Konfigurationen** – und wie wir es gelöst haben.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Das Problem: Flux erkennt ConfigMap-Änderungen nicht
|
||||
|
||||
### Die Situation
|
||||
|
||||
Unsere HelmRelease (`element-server-suite.yaml`) nutzt `valuesFrom`, um Konfigurationen aus externen **ConfigMaps** zu laden:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
valuesFrom:
|
||||
- kind: ConfigMap
|
||||
name: ess-element-custom # ← Diese ConfigMap
|
||||
valuesKey: values.yaml
|
||||
- kind: ConfigMap
|
||||
name: ess-synapse-custom # ← Diese ConfigMap
|
||||
valuesKey: values.yaml
|
||||
```
|
||||
|
||||
Diese ConfigMaps entstehen aus Dateien im Git-Repo (`apps/production/custom-configs/*.yaml`) und werden von Kustomize in den Cluster deployed.
|
||||
|
||||
### Das Kernproblem
|
||||
|
||||
**Flux CD reagiert NICHT automatisch, wenn sich eine ConfigMap ändert.**
|
||||
|
||||
Warum? Flux überwacht nur das Git-Repository auf Änderungen. Wenn du `element-values.yaml` änderst:
|
||||
|
||||
1. ✅ Flux sieht die Änderung im Git-Repo
|
||||
2. ✅ Kustomize erzeugt eine neue ConfigMap mit den neuen Werten
|
||||
3. ❌ Aber Helm (der Helm-Controller in Flux) erkennt **nicht**, dass sich die externe ConfigMap geändert hat
|
||||
4. ❌ Helm deployt das Chart nicht neu → Die alten Themes/Configs bleiben aktiv
|
||||
|
||||
Das ist kein Bug, sondern by-design: Helm achtet nur auf:
|
||||
- Chart-Version (z.B. `26.4.0`)
|
||||
- Änderungen in den direkten `values:` Blöcken
|
||||
- Nicht auf externe Quellen wie ConfigMaps
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Die Lösung: Checksums als Trigger
|
||||
|
||||
Wir nutzen **Annotations mit Checksums** als Workaround:
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
annotations:
|
||||
element-config-checksum: "401f8a87d0ef5d91d2e5032d4aede42c" # ← Hash der element-values.yaml
|
||||
synapse-config-checksum: "e98fe81141f52e7ea833596ca39853b9" # ← Hash der synapse-values.yaml
|
||||
```
|
||||
|
||||
Wenn sich der Annotation-Wert ändert, sieht Flux, dass die **HelmRelease selbst** sich geändert hat – und deployt neu.
|
||||
|
||||
### Automatisierung via Git Pre-Commit Hook
|
||||
|
||||
Das Problem: Wer aktualisiert die Checksums, wenn man `element-values.yaml` editiert?
|
||||
|
||||
**Lösung:** Ein Git **pre-commit Hook** tut das automatisch:
|
||||
|
||||
```bash
|
||||
$ vi apps/production/custom-configs/element-values.yaml
|
||||
# (Farbe ändern, Theme hinzufügen, …)
|
||||
|
||||
$ git add apps/production/custom-configs/element-values.yaml
|
||||
$ git commit -m "feat: new theme"
|
||||
# ← Der Hook läuft jetzt:
|
||||
# 1. Berechnet MD5-Hash der neuen element-values.yaml
|
||||
# 2. Aktualisiert die Annotation in kustomization.yaml
|
||||
# 3. Added kustomization.yaml zum Commit automatisch
|
||||
```
|
||||
|
||||
Der User muss **nichts Zusätzliches tun** – alles läuft automatisch.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
Nach dem Repository **klonen**, führe dieses Skript aus:
|
||||
|
||||
```bash
|
||||
cd prod/gitops
|
||||
./scripts/install-hooks.sh
|
||||
```
|
||||
|
||||
Das Skript:
|
||||
- ✅ Erstellt einen Symlink `.git/hooks/pre-commit` → `scripts/hooks/pre-commit`
|
||||
- ✅ Macht die Hook-Datei ausführbar
|
||||
- ✅ Gibt dir eine Bestätigungsmeldung
|
||||
|
||||
**Einmalig pro lokales Repository.** Neue Klone müssen den Hook auch installieren.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Workflow: ConfigMaps ändern
|
||||
|
||||
So sieht die Praxis aus:
|
||||
|
||||
### 1️⃣ Änderung machen
|
||||
|
||||
```bash
|
||||
vi apps/production/custom-configs/element-values.yaml
|
||||
# Edit: Themes, Farben, Logging-Level, etc.
|
||||
```
|
||||
|
||||
### 2️⃣ Committen (Hook läuft automatisch)
|
||||
|
||||
```bash
|
||||
git add apps/production/custom-configs/element-values.yaml
|
||||
git commit -m "feat: add Dark Purple theme variant"
|
||||
|
||||
# Pre-Commit Hook läuft automatisch:
|
||||
# → Berechnet neuen Hash
|
||||
# → Updated kustomization.yaml
|
||||
# → Added kustomization.yaml zum Commit
|
||||
```
|
||||
|
||||
### 3️⃣ Überprüfung (optional)
|
||||
|
||||
```bash
|
||||
# Schaue, was committet wird:
|
||||
git show --stat
|
||||
|
||||
# Output sollte zeigen:
|
||||
# element-values.yaml (modified)
|
||||
# kustomization.yaml (modified) ← vom Hook hinzugefügt
|
||||
```
|
||||
|
||||
### 4️⃣ Pushen & Deployen
|
||||
|
||||
```bash
|
||||
git push
|
||||
# ← Flux sieht die Änderung an kustomization.yaml
|
||||
# ← HelmRelease wird neu-synced mit den neuen Checksums
|
||||
# ← Die neue Config ist in ~5 Minuten aktiv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technische Details
|
||||
|
||||
### Welche Dateien sind "überwacht"?
|
||||
|
||||
Der Hook beobachtet:
|
||||
|
||||
| Datei | Annotation | Ziel |
|
||||
|-------|-----------|------|
|
||||
| `apps/production/custom-configs/element-values.yaml` | `element-config-checksum` | Element Web Themes, Branding |
|
||||
| `apps/production/custom-configs/synapse-values.yaml` | `synapse-config-checksum` | Synapse Logging, Federation |
|
||||
|
||||
### Hook-Implementation
|
||||
|
||||
Der Hook (`scripts/hooks/pre-commit`) macht folgendes:
|
||||
|
||||
1. Prüft, ob eine der überwachten Dateien geändert wurde (`git diff --cached`)
|
||||
2. Berechnet den MD5-Hash der Datei (kompatibel mit macOS/Linux)
|
||||
3. Ersetzt den Hash-Wert in `apps/production/kustomization.yaml` via `sed`
|
||||
4. Added `kustomization.yaml` automatisch zum Commit mit `git add`
|
||||
|
||||
```bash
|
||||
# Beispiel: element-values.yaml ändert sich von
|
||||
value: "401f8a87d0ef5d91d2e5032d4aede42c" # element-config
|
||||
# zu
|
||||
value: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" # element-config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Häufige Fragen
|
||||
|
||||
### F: Was passiert, wenn der Hook fehlschlägt?
|
||||
|
||||
A: Der Commit wird **abgebrochen**. Du siehst eine Fehlermeldung. Typische Gründe:
|
||||
- `md5` oder `md5sum` nicht installiert (sehr unwahrscheinlich)
|
||||
- `sed` Syntax-Fehler (sehr selten)
|
||||
|
||||
Lass dich nicht entmutigen – rufe denen auf, die das Setup machen 🚀
|
||||
|
||||
### F: Kann ich den Hook deaktivieren?
|
||||
|
||||
A: Ja, aber bitte nicht! Wenn du temporär ohne Hook arbeiten möchtest:
|
||||
|
||||
```bash
|
||||
git commit --no-verify
|
||||
```
|
||||
|
||||
Das umgeht den Hook einmalig. Danach musst du die Checksums manuell aktualisieren.
|
||||
|
||||
### F: Der Hook touched `kustomization.yaml`, obwohl ich sie nicht editiert habe?
|
||||
|
||||
A: Das ist **Absicht**. Der Hook updated **nur** die Checksums, nicht den Rest der Datei. Das ist sauber und Git-freundlich.
|
||||
|
||||
### F: Was wenn ich mehrere ConfigMaps gleichzeitig ändere?
|
||||
|
||||
A: Der Hook aktualisiert **alle** deren Checksums in einem Pass. Keine Probleme.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Verifikation: Hook funktioniert?
|
||||
|
||||
Teste es selbst:
|
||||
|
||||
```bash
|
||||
# 1. Hook installieren
|
||||
./scripts/install-hooks.sh
|
||||
|
||||
# 2. Eine Teständerung machen
|
||||
echo "# Test" >> apps/production/custom-configs/element-values.yaml
|
||||
|
||||
# 3. Committen
|
||||
git add apps/production/custom-configs/element-values.yaml
|
||||
git commit -m "test: verify hook"
|
||||
|
||||
# 4. Überprüfung: Wurde kustomization.yaml auto-updated?
|
||||
git diff HEAD~1 apps/production/kustomization.yaml | grep -i checksum
|
||||
|
||||
# Output sollte zeigen, dass ein Checksum sich geändert hat
|
||||
```
|
||||
|
||||
Wenn ja → Hook funktioniert! ✅
|
||||
Wenn nein → Rufe uns an 📞
|
||||
|
||||
---
|
||||
|
||||
## 📚 Zusammenhang mit Flux CD
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Git Repository (axion1337.chat-gitops) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ apps/production/custom-configs/ │
|
||||
│ ├── element-values.yaml (du änderst das) │
|
||||
│ ├── synapse-values.yaml │
|
||||
│ └── mas-secret.yaml │
|
||||
│ │
|
||||
│ apps/production/ │
|
||||
│ └── kustomization.yaml (Hook updated die Checksums hier) │
|
||||
│ │
|
||||
│ apps/production/ │
|
||||
│ └── element-server-suite.yaml (HelmRelease mit Annotations)│
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓ git push
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ FluxCD im Kubernetes-Cluster │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. GitRepository Source │
|
||||
│ └─ Fetcht dein Repo alle 10 Minuten │
|
||||
│ │
|
||||
│ 2. Kustomization production-apps │
|
||||
│ └─ Applyt die Kustomize-Overlays │
|
||||
│ └─ Erzeugt ConfigMaps mit neuen Werten │
|
||||
│ │
|
||||
│ 3. HelmRelease matrix-stack │
|
||||
│ └─ Sieht neue Annotations (Checksums) │
|
||||
│ └─ Deployt Helm-Chart mit neuen Werten │
|
||||
│ │
|
||||
│ 4. Element Web Pods │
|
||||
│ └─ Restarten automatisch │
|
||||
│ └─ Laden neue Config aus der ConfigMap │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Notfall: Manuelle Checksum-Aktualisierung
|
||||
|
||||
Falls der Hook ausfällt (z.B. weil Git Hooks in CI deaktiviert sind), kannst du Checksums manuell aktualisieren:
|
||||
|
||||
```bash
|
||||
# 1. Neuen Hash berechnen
|
||||
md5sum apps/production/custom-configs/element-values.yaml
|
||||
# Output: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 apps/production/custom-configs/element-values.yaml
|
||||
|
||||
# 2. Annotation in kustomization.yaml updaten
|
||||
vi apps/production/kustomization.yaml
|
||||
# Ändere: value: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" # element-config
|
||||
|
||||
# 3. Committen
|
||||
git add apps/production/kustomization.yaml
|
||||
git commit -m "fix: manual checksum update"
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Version:** 1.0
|
||||
**Letztes Update:** 2026-05-14
|
||||
**Kompatibilität:** FluxCD 2.x, Kustomize 5.x+
|
||||
41
scripts/hooks/pre-commit
Executable file
41
scripts/hooks/pre-commit
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# GitOps ConfigMap Checksum Hook
|
||||
# Automatically updates checksum annotations in kustomization.yaml when ConfigMaps change.
|
||||
# This ensures Flux CD re-deploys the HelmRelease when external ConfigMap sources are modified.
|
||||
#
|
||||
# See: docs/ops-configmap-sync.md
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
ELEMENT_VALUES="$REPO_ROOT/apps/production/custom-configs/element-values.yaml"
|
||||
SYNAPSE_VALUES="$REPO_ROOT/apps/production/custom-configs/synapse-values.yaml"
|
||||
KUSTOMIZATION="$REPO_ROOT/apps/production/kustomization.yaml"
|
||||
|
||||
# Function to calculate MD5 hash (handles both GNU md5sum and BSD md5)
|
||||
get_md5() {
|
||||
local file="$1"
|
||||
if command -v md5sum &> /dev/null; then
|
||||
md5sum "$file" | awk '{print $1}'
|
||||
elif command -v md5 &> /dev/null; then
|
||||
md5 -q "$file"
|
||||
else
|
||||
echo "ERROR: Neither md5sum nor md5 found" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Update checksums for ConfigMaps that exist and are staged
|
||||
if git diff --cached --name-only | grep -q "element-values.yaml"; then
|
||||
ELEMENT_HASH=$(get_md5 "$ELEMENT_VALUES")
|
||||
sed -i.bak "s/value: \"[0-9a-f]\{32\}\" *# element-config/value: \"$ELEMENT_HASH\" # element-config/" "$KUSTOMIZATION"
|
||||
rm -f "$KUSTOMIZATION.bak"
|
||||
git add "$KUSTOMIZATION"
|
||||
fi
|
||||
|
||||
if git diff --cached --name-only | grep -q "synapse-values.yaml"; then
|
||||
SYNAPSE_HASH=$(get_md5 "$SYNAPSE_VALUES")
|
||||
sed -i.bak "s/value: \"[0-9a-f]\{32\}\" *# synapse-config/value: \"$SYNAPSE_HASH\" # synapse-config/" "$KUSTOMIZATION"
|
||||
rm -f "$KUSTOMIZATION.bak"
|
||||
git add "$KUSTOMIZATION"
|
||||
fi
|
||||
27
scripts/install-hooks.sh
Executable file
27
scripts/install-hooks.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install Git Hooks for GitOps automation
|
||||
# Must be run after cloning the repository
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
||||
echo "❌ Not in a git repository"
|
||||
exit 1
|
||||
}
|
||||
|
||||
HOOKS_DIR="$REPO_ROOT/.git/hooks"
|
||||
HOOK_SOURCE="$REPO_ROOT/scripts/hooks/pre-commit"
|
||||
HOOK_DEST="$HOOKS_DIR/pre-commit"
|
||||
|
||||
# Verify source exists
|
||||
if [ ! -f "$HOOK_SOURCE" ]; then
|
||||
echo "❌ Hook source not found: $HOOK_SOURCE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create symlink (force if exists)
|
||||
mkdir -p "$HOOKS_DIR"
|
||||
ln -sf "../../scripts/hooks/pre-commit" "$HOOK_DEST"
|
||||
chmod +x "$HOOK_SOURCE"
|
||||
|
||||
echo "✅ Git hooks installed:"
|
||||
echo " • pre-commit: ConfigMap checksum auto-update"
|
||||
echo " See: docs/ops-configmap-sync.md"
|
||||
Loading…
x
Reference in New Issue
Block a user