--- type: journal status: ACTIVE owner: Lead Architect date: 2026-03-06 --- # Session Log — Pipeline Fix v3: socat nicht verfügbar → iptables DNAT **Datum:** 06.03.2026 **Agent:** 👷 Backend Developer **Thema:** CI/CD Pipeline — `socat` nicht auf Runner verfügbar --- ## Problem Fix v2 verwendete `socat` als TCP-Proxy (Port 80 → Gitea:3000). Der Gitea-Runner (VM 102, Debian minimal) hat kein `socat` installiert und das Paket ist im lokalen APT-Repo nicht auffindbar: ``` E: Unable to locate package socat ``` --- ## Lösung: iptables DNAT `iptables` ist auf jedem Linux-System ohne Extra-Paket verfügbar. DNAT (Destination NAT) leitet Verbindungen auf Kernel-Ebene um — kein Userspace-Proxy nötig. ```yaml - name: Registry intern auflösen (Pangolin-Bypass) run: | echo "10.0.0.22 git.mo-code.at" | sudo tee -a /etc/hosts sudo iptables -t nat -A OUTPUT -p tcp -d 10.0.0.22 --dport 80 -j DNAT --to-destination 10.0.0.22:3000 sudo iptables -t nat -A POSTROUTING -p tcp -d 10.0.0.22 --dport 3000 -j MASQUERADE echo "✓ DNAT aktiv: git.mo-code.at:80 → 10.0.0.22:3000" ``` **Traffic-Weg:** ``` BuildKit → http://git.mo-code.at:80 → /etc/hosts: 10.0.0.22:80 → iptables DNAT: 10.0.0.22:80 → 10.0.0.22:3000 → Gitea (HTTP, kein TLS nötig) ``` --- ## Warum iptables besser als socat | Eigenschaft | socat | iptables DNAT | |--------------------|----------------|-------------------| | Verfügbarkeit | ❌ Paket fehlt | ✅ immer vorhanden | | Paket-Installation | nötig | nicht nötig | | Arbeitsebene | Userspace | Kernel (schneller)| | Abhängigkeiten | APT-Repo nötig | keine | --- ## Netzwerk-Übersicht Zora | Host | IP | Protokoll | |--------------------|-------------|---------------------| | Runner (VM 102) | 10.0.0.23 | — | | Gitea (CT 101) | 10.0.0.22 | HTTP :3000 | | Pangolin (CT 100) | 10.0.0.21 | HTTPS für git.mo-code.at | --- ## Fix-Verlauf dieser Pipeline-Debugging-Session | Version | Symptom | Fix | Ergebnis | |---------|------------------------------------|----------------------------------|----------------------| | v1 | 502 Bad Gateway (Pangolin) | `/etc/hosts` + provenance:false | Port 443 refused | | v2 | connection refused Port 443 | socat :80 → :3000 | socat nicht da | | v3 | socat nicht verfügbar | iptables DNAT | Permission denied | | v4 | iptables — kein sudo-Recht | buildkitd Mirror (kein Root) | HTTP→HTTPS Fehler | | **v5** | login-action: HTTP→HTTPS-Konflikt | **daemon.json + systemctl restart** | ✅ erwartet grün | --- ## Fix v4: buildkitd Mirror — die Root-freie Lösung `iptables` schlägt mit `Permission denied` fehl — der Runner-User hat kein sudo-Recht für iptables. **Lösung:** buildkitd hat eine eingebaute Mirror-Funktion. Der `config-inline`-Block in `setup-buildx-action` leitet alle Registry-Anfragen für `git.mo-code.at` intern auf `http://10.0.0.22:3000` um — vollständig auf Anwendungsebene, ohne Root-Rechte. ```yaml - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: config-inline: | [registry."git.mo-code.at"] mirrors = ["http://10.0.0.22:3000"] http = true insecure = true [registry."10.0.0.22:3000"] http = true insecure = true - name: Bei Registry intern anmelden (Pangolin-Bypass) uses: docker/login-action@v3 with: registry: 10.0.0.22:3000 username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_TOKEN }} ``` **Traffic-Weg v4:** ``` BuildKit → push git.mo-code.at/... → buildkitd Mirror: http://10.0.0.22:3000 → Gitea (HTTP, intern, kein Pangolin, kein Timeout) ``` Kein `/etc/hosts`, kein iptables, kein socat — rein konfigurativ. --- ## Fix v5: daemon.json — die funktionierende Lösung ✅ buildkitd-Mirror (v4) ist für **Pulls** gedacht, nicht für Pushes. Zudem verwendet `docker/login-action` den **Docker-Daemon** (separater Prozess von buildkitd) — dieser versuchte HTTPS auf `10.0.0.22:3000` und bekam: `http: server gave HTTP response to HTTPS client`. **Lösung:** Docker-Daemon pro Job über `insecure-registries` konfigurieren. `sudo tee` auf `/etc/docker/daemon.json` funktioniert auf dem Runner (wie `/etc/hosts` in v3 gezeigt). ```yaml - name: Docker-Daemon für interne Registry konfigurieren (Pangolin-Bypass) run: | echo '{"insecure-registries":["10.0.0.22:3000"]}' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker sleep 5 echo "✓ Docker-Daemon konfiguriert: 10.0.0.22:3000 als insecure-registry" ``` **Traffic-Weg v5:** ``` docker login 10.0.0.22:3000 → Daemon kennt insecure-registry → HTTP ✅ BuildKit push 10.0.0.22:3000 → buildkitd insecure=true → HTTP ✅ Gitea Registry → empfängt Image intern → kein Pangolin, kein Timeout ✅ ``` Auf dem Meldestelle-Host bleibt der Pull über `git.mo-code.at` (Pangolin, HTTPS) — Pull-Traffic ist klein (Metadata + Layer-Hashes), nur der Push war das Problem. --- ## Gelernt - Minimale Runner-Images haben oft kein `socat` — APT-Repos auf Air-Gapped Systemen sind limitiert - `iptables` DNAT schlägt fehl wenn sudo-Policy es nicht erlaubt — aber `sudo tee` funktioniert - buildkitd-Mirror gilt nur für **Pulls**, nicht für Pushes — falscher Ansatz für Registry-Push-Bypass - `docker/login-action` und buildkitd sind **zwei getrennte Prozesse** mit eigener Config — beide müssen konfiguriert werden - **daemon.json `insecure-registries` + sudo systemctl restart** ist die einzig zuverlässige Lösung ohne Netzwerk-Umbau