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
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:
@@ -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 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
|
||||||
|
|
||||||
|
```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
|
||||||
|
|||||||
Reference in New Issue
Block a user