7.9 KiB
| type | status | owner | date | last_update |
|---|---|---|---|---|
| Journal | ACTIVE | Lead Architect | 2026-03-06 | 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.
- 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 | ❌ RAM-OOM + unklar |
| v6 | RAM-OOM + Daemon-Neustart komplex | config.json direkt + max-parallel:1 | ✅ BESTÄTIGT 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.
- 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).
- 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.
Fix v6: config.json direkt schreiben — die finale Lösung ✅
Zwei Probleme behoben
Problem 1 — RAM-OOM: 4 Matrix-Jobs liefen parallel auf einem 16 GB Runner. Jeder Job: Gradle-Build + Docker-Buildx = leicht 3–4 GB. Zusammen → 15+ GB → OOM → Builds crashed.
Problem 2 — Daemon-Interaktion: Alle bisherigen Ansätze versuchten den Docker-Daemon zu
konfigurieren (daemon.json, systemctl, iptables). Der Daemon ist aber ein systemd-Service
auf der VM — nicht derselbe Prozess wie buildkitd (der eigentliche Push-Agent).
Lösung
# Schritt 1: Credentials OHNE Daemon-Kontakt schreiben
- name: Registry-Credentials konfigurieren (kein Daemon-Kontakt)
run: |
mkdir -p ~/.docker
AUTH=$(echo -n "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_TOKEN }}" | base64 -w 0)
printf '{"auths":{"%s":{"auth":"%s"}}}\n' "10.0.0.22:3000" "${AUTH}" > ~/.docker/config.json
# Schritt 2: BuildKit mit HTTP/insecure für interne Registry
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."10.0.0.22:3000"]
http = true
insecure = true
# RAM-Schutz: sequenziell statt parallel
strategy:
max-parallel: 1
Warum das funktioniert:
printf ... > ~/.docker/config.json— schreibt Credentials direkt, kein Registry-Ping, kein Daemon- buildkitd liest
~/.docker/config.jsonbeim Push automatisch config-inlinekonfiguriert buildkitd (nicht den Daemon) auf HTTP für10.0.0.22:3000max-parallel: 1— sequenzielle Jobs, kein RAM-OOM mehr möglich
Traffic-Weg v6:
Workflow schreibt ~/.docker/config.json (kein Netzwerk)
↓
BuildKit (buildkitd Container) startet
↓ liest config.json für Auth
↓ config-inline: http=true für 10.0.0.22:3000
BuildKit push → http://10.0.0.22:3000 → Gitea (intern, kein Pangolin)
Kein sudo. Kein systemctl. Kein socat. Kein iptables. Kein Neustart.
Gelernt
- Minimale Runner-Images haben oft kein
socat— APT-Repos auf Air-Gapped Systemen sind limitiert iptablesDNAT schlägt fehl wenn sudo-Policy es nicht erlaubt — abersudo teefunktioniert- buildkitd-Mirror gilt nur für Pulls, nicht für Pushes — falscher Ansatz für Registry-Push-Bypass
docker/login-actionund 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