docs: document pipeline fix v6 using direct config.json and sequential builds
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 7m56s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 7m27s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 2m14s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 1m47s

Added a session log detailing the resolution of RAM-OOM issues and daemon interaction complexities by writing credentials directly to `config.json` and limiting jobs to sequential execution. Updated `.gitea/workflows/docker-publish.yaml` to reflect the simplified and rootless BuildKit configuration for internal HTTP registry access.
This commit is contained in:
2026-03-06 15:16:51 +01:00
parent be474a2c93
commit cdb01a7b4c
2 changed files with 83 additions and 40 deletions
+24 -39
View File
@@ -14,26 +14,28 @@ on:
- '.gitea/workflows/docker-publish.yaml' - '.gitea/workflows/docker-publish.yaml'
env: env:
REGISTRY: git.mo-code.at # Interner Registry-Endpunkt: direkter HTTP-Zugriff, umgeht Pangolin-Tunnel komplett
# Interner Registry-Endpunkt (direkter HTTP, kein Pangolin-Timeout)
REGISTRY_INTERNAL: 10.0.0.22:3000 REGISTRY_INTERNAL: 10.0.0.22:3000
# WICHTIG: Kleingeschrieben für Docker-Konformität
IMAGE_PREFIX: mocode-software/meldestelle IMAGE_PREFIX: mocode-software/meldestelle
# Build Arguments für Zora (ARM64 Power)
JAVA_VERSION: "25" JAVA_VERSION: "25"
GRADLE_VERSION: "9.3.1" GRADLE_VERSION: "9.3.1"
# OPTIMIERUNG: Gradle Parameter für mehr Speed # Workers auf 4 limitiert: verhindert OOM auf dem 16GB Runner (VM 102)
GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.workers.max=8" GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4"
# Deine neuen JVM Power-Flags für ARM64 (Cortex-A720) JVM_OPTS_ARM64: "-XX:ActiveProcessorCount=8 -XX:+UseZGC -XX:+UseTransparentHugePages"
JVM_OPTS_ARM64: "-XX:ActiveProcessorCount=12 -XX:+UseG1GC -XX:+UseTransparentHugePages -XX:+UseSVE=1"
jobs: jobs:
build-and-push: build-and-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
# max-parallel: 1 → sequenzielle Ausführung verhindert RAM-OOM auf Zora (16GB VM)
max-parallel: 1
matrix: matrix:
include: include:
- service: keycloak
context: .
dockerfile: config/docker/keycloak/Dockerfile
image: keycloak
- service: api-gateway - service: api-gateway
context: . context: .
dockerfile: backend/infrastructure/gateway/Dockerfile dockerfile: backend/infrastructure/gateway/Dockerfile
@@ -46,23 +48,18 @@ jobs:
context: . context: .
dockerfile: config/docker/caddy/web-app/Dockerfile dockerfile: config/docker/caddy/web-app/Dockerfile
image: web-app image: web-app
- service: keycloak
context: .
dockerfile: config/docker/keycloak/Dockerfile
image: keycloak
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
# Java Setup (Wichtig für Gradle-Builds im Runner) - name: Set up JDK ${{ env.JAVA_VERSION }}
- name: Set up JDK 25
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: ${{ env.JAVA_VERSION }} java-version: ${{ env.JAVA_VERSION }}
distribution: "temurin" distribution: "temurin"
cache: gradle cache: gradle
# Cache für Gradle (Beschleunigt Folgebauvorgänge massiv)
- name: Setup Gradle Cache - name: Setup Gradle Cache
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
@@ -73,17 +70,13 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-gradle- ${{ runner.os }}-gradle-
# Cache-Cleanup: Entfernt inkonsistente Node/Yarn-Caches die zu mysteriösen Build-Fehlern führen können. # Verhindert mysteriöse Build-Fehler durch korrupte Node/Kotlin-Caches (nur web-app relevant)
# Hintergrund: git-clone warnings ("some refs were not updated") deuten auf korrupte Runner-Caches hin.
# Dieser Step ist idempotent — schlägt nie fehl, auch wenn die Verzeichnisse nicht existieren.
- name: Cleanup stale build caches - name: Cleanup stale build caches
if: matrix.service == 'web-app' if: matrix.service == 'web-app'
run: | run: |
echo "Cleaning stale Kotlin/JS and Node caches..."
rm -rf frontend/shells/meldestelle-portal/build/js/node_modules/.cache || true rm -rf frontend/shells/meldestelle-portal/build/js/node_modules/.cache || true
rm -rf frontend/shells/meldestelle-portal/build/js/.yarn/cache || true rm -rf frontend/shells/meldestelle-portal/build/js/.yarn/cache || true
rm -rf ~/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable || true rm -rf ~/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable || true
echo "Cache cleanup done."
- name: Build Frontend (Kotlin JS) - name: Build Frontend (Kotlin JS)
if: matrix.service == 'web-app' if: matrix.service == 'web-app'
@@ -91,19 +84,21 @@ jobs:
chmod +x gradlew chmod +x gradlew
./gradlew :frontend:shells:meldestelle-portal:jsBrowserDistribution \ ./gradlew :frontend:shells:meldestelle-portal:jsBrowserDistribution \
-Pproduction=true \ -Pproduction=true \
--max-workers=8 \ --max-workers=4 \
-Dkotlin.daemon.jvm.options="-Xmx4g" -Dkotlin.daemon.jvm.options="-Xmx4g"
# Pangolin-Bypass: Docker-Daemon + buildkitd für interne HTTP-Registry konfigurieren. # Pangolin-Bypass: Credentials direkt in config.json schreiben.
# Problem: git.mo-code.at läuft über Pangolin (HTTPS), große Layer-Uploads timeouton (502). # Kein "docker login" → kein Daemon-Ping → kein HTTPS-Fehler.
# Lösung: Push direkt auf 10.0.0.22:3000 (intern, HTTP). sudo tee funktioniert auf dem Runner. # BuildKit liest ~/.docker/config.json und verwendet diese Credentials beim Push.
- name: Docker-Daemon für interne Registry konfigurieren (Pangolin-Bypass) - name: Registry-Credentials konfigurieren (kein Daemon-Kontakt)
run: | run: |
echo '{"insecure-registries":["10.0.0.22:3000"]}' | sudo tee /etc/docker/daemon.json mkdir -p ~/.docker
sudo systemctl restart docker AUTH=$(echo -n "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_TOKEN }}" | base64 -w 0)
sleep 5 printf '{"auths":{"%s":{"auth":"%s"}}}\n' "${{ env.REGISTRY_INTERNAL }}" "${AUTH}" > ~/.docker/config.json
echo "✓ Docker-Daemon konfiguriert: 10.0.0.22:3000 als insecure-registry" echo "✓ Credentials für ${{ env.REGISTRY_INTERNAL }} gespeichert"
# BuildKit-Instanz mit HTTP-Unterstützung für die interne Registry konfigurieren.
# KEIN sudo, KEIN systemctl, KEIN Neustart — rein konfigurativ.
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
with: with:
@@ -112,13 +107,6 @@ jobs:
http = true http = true
insecure = true insecure = true
- name: Bei Registry intern anmelden (Pangolin-Bypass)
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY_INTERNAL }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Extract metadata - name: Extract metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
@@ -134,12 +122,9 @@ jobs:
context: ${{ matrix.context }} context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }} file: ${{ matrix.dockerfile }}
push: true push: true
# Fokus auf ARM64 für Zora, AMD64 bleibt für Kompatibilität (optional)
platforms: linux/arm64 platforms: linux/arm64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
# Attestation-Manifeste deaktivieren: verhindert extra OAuth-Token-Requests
# die bei proxied Registries (Pangolin) ebenfalls mit 502 fehlschlagen können
provenance: false provenance: false
sbom: false sbom: false
build-args: | build-args: |
@@ -77,7 +77,8 @@ BuildKit → http://git.mo-code.at:80
| v2 | connection refused Port 443 | socat :80 → :3000 | socat nicht da | | v2 | connection refused Port 443 | socat :80 → :3000 | socat nicht da |
| v3 | socat nicht verfügbar | iptables DNAT | Permission denied | | v3 | socat nicht verfügbar | iptables DNAT | Permission denied |
| v4 | iptables — kein sudo-Recht | buildkitd Mirror (kein Root) | HTTP→HTTPS Fehler | | 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 | | 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** | ✅ erwartet grün |
--- ---
@@ -151,6 +152,63 @@ 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 34 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
```yaml
# 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
```
```yaml
# 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.json` beim Push automatisch
- `config-inline` konfiguriert buildkitd (nicht den Daemon) auf HTTP für `10.0.0.22:3000`
- `max-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 ## Gelernt
- Minimale Runner-Images haben oft kein `socat` — APT-Repos auf Air-Gapped Systemen sind limitiert - Minimale Runner-Images haben oft kein `socat` — APT-Repos auf Air-Gapped Systemen sind limitiert