# 🐳 DevContainer für ESS Community GitOps

Dieses DevContainer-Setup ermöglicht dir, auf **macOS, Windows und Linux** einheitlich zu entwickeln.

## 🚀 Schnelstart

### VSCode mit Remote Containers Extension

1. **VSCode Extension installieren:**
   - Öffne VSCode → Extensions → Suche nach `Dev Containers` (Microsoft)
   - Installiere sie

2. **GitOps Verzeichnis öffnen:**
   ```bash
   cd "april mit Ansible/prod/gitops"
   code .
   ```

3. **DevContainer starten:**
   - Klick auf `><` Symbol unten links in VSCode
   - Wähle `Reopen in Container`
   - Warte, bis das Image gebaut wurde (~3-5 Min beim ersten Mal)

### Alternative: Docker + CLI

```bash
docker build -t ess-gitops .devcontainer
docker run -it --rm \
  -v ~/.kube:/home/vscode/.kube \
  -v ~/.ssh:/home/vscode/.ssh \
  -v ~/.age:/home/vscode/.age \
  -v /var/run/docker.sock:/var/run/docker.sock \
  ess-gitops
```

## 📦 Enthaltene Tools

- **kubectl** - Kubernetes CLI
- **flux** - FluxCD GitOps Controller CLI
- **helm** - Kubernetes Package Manager
- **sops** - Secret Operations (Verschlüsselung)
- **age** - Modern File Encryption
- **docker** - Container CLI (über Host-Socket)
- **git** - Versionskontrolle
- **jq/yq** - JSON/YAML Processing
- **zsh + oh-my-zsh** - Shell mit Plugins

## 🔐 Wichtige Verzeichnis-Binds

Der Container mountet automatisch:

| Host | Container | Zweck |
|------|-----------|-------|
| `~/.kube` | `/home/vscode/.kube` | Kubernetes Config |
| `~/.ssh` | `/home/vscode/.ssh` | SSH Keys |
| `~/.age` | `/home/vscode/.age` | Age Encryption Keys |
| `/var/run/docker.sock` | `/var/run/docker.sock` | Docker Daemon (für `docker` Befehle) |

## ⚙️ Kubeconfig Einrichten

1. **Host-Machine (z.B. macOS):**
   ```bash
   # Stelle sicher, dass ~/.kube/config existiert und den richtigen Cluster enthält
   kubectl get nodes
   ```

2. **Im Container:**
   ```bash
   kubectl get nodes  # Sollte jetzt auch dein Cluster zeigen
   kubectl config current-context
   ```

## 🔐 SOPS + Age Setup

Damit du Secrets bearbeiten kannst, brauchst du den privaten `age`-Key. Dieser ist in `.sops.yaml` konfiguriert.

### Schritt 1: Age-Key bereitstellen

```bash
# Host-Machine: Key-Datei erstellen
mkdir -p ~/.age
# Füge deinen privaten Key ein (Format: "age-secret-key-...")
echo "age-secret-key-xxx..." > ~/.age/keys.txt
chmod 600 ~/.age/keys.txt
```

### Schritt 2: Im Container konfigurieren

Der Container mounted `~/.age` automatisch. Setze die Umgebungsvariable:

```bash
# Im Container-Terminal (SOPS_AGE_KEY_FILE ist bereits automatisch gesetzt!)
# Jetzt kannst du Secrets bearbeiten (wird transparent ver-/entschlüsselt):
sops apps/production/custom-configs/mas-secret.yaml
```

### Schritt 3: VSCode Integration (optional)

Um die Umgebungsvariable beim Start zu setzen, nutze die `.devcontainer/devcontainer.json`:

```json
"remoteEnv": {
  "KUBECONFIG": "/home/vscode/.kube/config",
  "SOPS_AGE_KEY_FILE": "/home/vscode/.age/keys.txt"
}
```

### Wie es funktioniert

- `.sops.yaml` definiert, dass Secrets mit `age` verschlüsselt werden
- Beim Öffnen mit `sops <datei>` wird die Datei entschlüsselt → du editierst den plaintext in deinem Editor
- Beim Speichern wird alles wieder automatisch verschlüsselt
- **Wichtig:** Niemals den plaintext-Buffer commiten!

## 📝 Nach Container-Start: Git Hooks Installieren

Wichtig für die ConfigMap Auto-Sync (verhindert Merge-Konflikte):

```bash
./scripts/install-hooks.sh
```

Mehr Details: `docs/ops-configmap-sync.md`

## 📝 Nützliche Befehle

```bash
# Status des Deployments
kubectl get pods -n matrix
flux get helmreleases -A

# Secrets bearbeiten (mit verschlüsselung)
sops apps/production/custom-configs/mas-secret.yaml

# FluxCD Sync erzwingen
flux reconcile kustomization production-apps --with-source

# Zertifikate debuggen
kubectl get certificate -n matrix
kubectl describe certificate matrix-ingress -n matrix

# HelmRelease Status prüfen
flux describe helmrelease matrix-stack -n matrix
```

## 🛠️ Anpassungen für Windows/WSL2

Falls du Windows nutzt:

1. **Docker Desktop installieren** (mit WSL2 Backend)
2. **VSCode mit WSL Extension öffnen**
3. **Im WSL Terminal:**
   ```bash
   cd /mnt/c/path/to/projekt
   code .
   ```
4. Dann `Dev Containers: Reopen in Container`

Das funktioniert seamless, weil Docker Desktop unter WSL2 läuft.

## 🔧 Troubleshooting

### Problem: `SOPS_AGE_KEY_FILE not found`
**Lösung:** Key muss in `~/.age/keys.txt` auf der Host-Machine sein:
```bash
# Host
mkdir -p ~/.age
echo "your-age-private-key" > ~/.age/keys.txt
```
Der Container mountet `~/.age` automatisch → sollte dann funktionieren.

### Problem: `kubectl: connection refused`
**Lösung:** `~/.kube/config` muss auf Host vorhanden sein:
```bash
# Host
kubectl get nodes  # Test, ob Zugriff existiert
# Dann Container neustarten
```

### Problem: `HelmChart is not ready: stat ... no such file or directory`
Siehe `README.md` → **Issue 1**. Kontrolliere:
- `HelmRepository` nutzt `type: oci`
- URL ist `oci://ghcr.io/element-hq/ess-helm`

### Problem: `values don't meet the specifications of the schema`
Siehe `README.md` → **Issue 2**. Häufige Fehler:
- `tls:` darf nicht im `ingress:` Block sein
- `serverName` muss auf Root-Ebene der `values` stehen
- Komponenten-Namen: `camelCase` (z.B. `elementWeb`, `matrixAuthenticationService`)

### Problem: Let's Encrypt `403 Order's status is processing`
Siehe `README.md` → **Issue 3**. Kurz: 
- `wellKnownDelegation: enabled: false` setzen
- Oder `.well-known/matrix/server` manuell auf `elementWeb` weiterleiten

## ⚠️ Wartungshinweis: Warum dieser Container regelmäßig getestet werden muss

Der Dockerfile installiert mehrere Tools über externe apt-Repos und Install-Skripte
(`pkgs.k8s.io`, `download.docker.com`, GitHub-Releases, `fluxcd.io`/`ohmyzsh.sh`
Installer). **Diese Quellen sind nicht unter unserer Kontrolle und können jederzeit
brechen** — genau das ist am 2026-07-28 passiert: der Container konnte seit
Fertigstellung nie erfolgreich gebaut werden, ohne dass es jemand bemerkt hat, weil
niemand ihn zwischenzeitlich tatsächlich gebaut hat. Gefundene und behobene Probleme:

| # | Problem | Ursache | Fix |
|---|---------|---------|-----|
| 1 | `apt.kubernetes.io` → `404 Not Found` | Google hat das alte Kubernetes-apt-Repo 2023 abgeschaltet | Umgestellt auf das offizielle Nachfolge-Repo `pkgs.k8s.io` (versioniert pro k8s-Minor-Version, aktuell `v1.34`) |
| 2 | `docker-ce-cli` "has no installation candidate" auf Apple Silicon | Repo-Zeile hatte `arch=amd64` hartkodiert, Build lief aber auf arm64 | `arch=$(dpkg --print-architecture)` zur Build-Zeit ermitteln |
| 3 | `useradd: group 'docker' does not exist` | Nur die Docker-**CLI** wird installiert (kein Daemon), daher legt kein Paket die `docker`-Gruppe automatisch an | `groupadd docker` explizit vor `useradd` |
| 4 | oh-my-zsh-Install schlägt mit Quoting-Fehler fehl | Verschachtelte `sh -c '...'`-Anführungszeichen in einer Zeile | Install-Skript erst in eine Datei laden, dann sauber mit `su - vscode -c "sh /tmp/install-omz.sh --unattended"` ausführen |
| 5 | `sops`-Binary war hart auf `linux.amd64` gepinnt | Lief auf Apple Silicon nur zufällig per QEMU-Emulation von Docker Desktop mit, nicht nativ | Arch dynamisch über `dpkg --print-architecture` auflösen (`linux.arm64` / `linux.amd64`) |
| 6 | `docker.sock`-Zugriff im Container: `permission denied` | Der gemountete Host-Socket gehört (je nach Docker-Setup) einer Gruppe/GID, die im Container nicht existiert oder nicht der `docker`-Gruppe entspricht (auf Docker Desktop für Mac/Windows z.B. GID 0/root statt einer eigenen `docker`-Gruppe) | `docker-init.sh`: Root-Entrypoint gleicht beim Container-Start die GID der `docker`-Gruppe an den tatsächlich gemounteten Socket an (bzw. tritt der GID-Inhaber-Gruppe bei, falls die GID schon vergeben ist), wechselt danach per `gosu` zu `vscode` |

**Konsequenz für die Zukunft:** Vor jeder größeren Änderung an `.devcontainer/` (oder
mindestens vierteljährlich) einmal real bauen und laufen lassen:

```bash
docker build -f .devcontainer/Dockerfile -t ess-gitops-devcontainer-test .devcontainer
docker run --rm \
  -v ~/.kube:/home/vscode/.kube \
  -v ~/.age:/home/vscode/.age \
  -v /var/run/docker.sock:/var/run/docker.sock \
  ess-gitops-devcontainer-test bash -c '
    kubectl version --client && helm version --short && flux --version && \
    sops --version && age --version && docker version --format "{{.Server.Version}}" && \
    id vscode
  '
```

Wenn `docker version` hier den echten Server, nicht nur die Client-Version zeigt, und
`id vscode` die passende Docker-Gruppe/GID auflistet, funktioniert der Socket-Zugriff
tatsächlich — nicht nur der Build.

## 📚 Weitere Ressourcen

- [Dev Containers Docs](https://containers.dev)
- [FluxCD Dokumentation](https://fluxcd.io)
- [SOPS Anleitung](https://github.com/getsops/sops)
- **Projekt-README:** `README.md` (Architektur, Issues, Best Practices)
- **Setup-Docs:** `docs/setup/`
- **Install-Guide:** `docs/install.md`
