diff --git a/.env b/.env index 07ecb510..6668a121 100644 --- a/.env +++ b/.env @@ -7,6 +7,14 @@ PROJECT_NAME=meldestelle RESTART_POLICY=no +# Docker build versions (optional overrides) +DOCKER_VERSION=1.0.0-SNAPSHOT +DOCKER_BUILD_DATE=2025-12-04T15:00:00Z +DOCKER_GRADLE_VERSION=9.1.0 +DOCKER_JAVA_VERSION=21 +DOCKER_NODE_VERSION=22.21.0 +DOCKER_NGINX_VERSION=1.28.0-alpine + # Postgres POSTGRES_IMAGE=postgres:16-alpine POSTGRES_USER=pg-user @@ -16,7 +24,6 @@ POSTGRES_PORT=5432:5432 POSTGRES_DB_URL=jdbc:postgresql://postgres:5432/pg-meldestelle-db # --- REDIS --- -# Optional password for Redis; leave empty to disable authentication in dev REDIS_IMAGE=redis:7.4-alpine REDIS_PASSWORD=redis-password REDIS_PORT=6379:6379 @@ -28,12 +35,8 @@ REDIS_SERVER_CONNECT_TIMEOUT=5s KEYCLOAK_IMAGE_TAG=26.4 KC_ADMIN_USERNAME=kc-admin KC_ADMIN_PASSWORD=kc-password -# Type der Datenbank (postgres, h2, mariadb, mysql, oracle, mssql) KC_DB=postgres -# DB Schema 01-init-keycloak-schema.sql KC_DB_SCHEMA=keycloak -# DB Verbindungsparameter -# KC_DB_URL=jdbc:postgresql://postgres:5432/pg-meldestelle-db KC_HOSTNAME=localhost KC_PORT=8180:8080 KC_DEBUG_PORT=9000:9000 @@ -58,10 +61,8 @@ GF_PORT=3000:3000 CONSUL_IMAGE=hashicorp/consul:1.22.1 CONSUL_PORT=8500:8500 CONSUL_UDP_PORT=8600:8600/udp -# Zentrale App-Config für Consul (interner Host/Port im Compose-Netz) CONSUL_HOST=consul CONSUL_HTTP_PORT=8500 -# SPRING-CLOUD-CONSUL SCLOUD_CONSUL_HOSTNAME=consul SCLOUD_CONSUL_PORT=8500 @@ -71,13 +72,9 @@ GATEWAY_DEBUG_PORT=5005:5005 GATEWAY_SERVER_PORT=8081 GATEWAY_SPRING_PROFILES_ACTIVE=docker GATEWAY_DEBUG=true -# Service-Registrierungsname in Consul (Anzeige in der UI) GATEWAY_SERVICE_NAME=api-gateway -# TODO Check Keycloak-URI -# SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT SSEC_ISSUER_URI=http://keycloak:8080/realms/meldestelle SSEC_JWK_SET_URI=http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs -# SPRING-CLOUD-CONSUL GATEWAY_CONSUL_HOSTNAME=api-gateway GATEWAY_CONSUL_PREFER_IP=true @@ -93,16 +90,8 @@ PING_CONSUL_PREFER_IP=true # --- WEB-APP --- WEB_APP_PORT=4000:4000 -DOCKER_NODE_VERSION=22.21.0 -DOCKER_NGINX_VERSION=1.28.0-alpine WEB_BUILD_PROFILE=dev # --- DESKTOP-APP --- -DESKTOP_APP_VNC_PORT=5900:5900 +DESKTOP_APP_VNC_PORT=5901:5901 DESKTOP_APP_NOVNC_PORT=6080:6080 - -# Docker build versions (optional overrides) -DOCKER_VERSION=1.0.0-SNAPSHOT -DOCKER_BUILD_DATE=2025-12-04T15:00:00Z -DOCKER_GRADLE_VERSION=9.1.0 -DOCKER_JAVA_VERSION=21 diff --git a/config/frontends/desktop-app/Dockerfile b/config/frontends/desktop-app/Dockerfile index 38b69ff7..6e180672 100644 --- a/config/frontends/desktop-app/Dockerfile +++ b/config/frontends/desktop-app/Dockerfile @@ -2,44 +2,44 @@ # Multi-Stage Dockerfile für Meldestelle Desktop-App (VNC) # =================================================================== -# =================================================================== -# Stage 1: Build Stage - Kotlin Desktop-App kompilieren -# =================================================================== -FROM gradle:8-jdk21-alpine AS builder +# 1. Build Stage (Debian-basiert für Stabilität bei Desktop-Builds) +FROM gradle:8-jdk21 AS builder WORKDIR /app -# Kopiere Gradle-Konfiguration und Wrapper +# Copy Configs COPY build.gradle.kts settings.gradle.kts gradle.properties ./ -COPY gradle ./gradle +COPY gradle/ gradle/ COPY gradlew ./ -# Kopiere alle notwendigen Module für Multi-Modul-Projekt -COPY frontend ./frontend -COPY backend ./backend -COPY core ./core -COPY domains ./domains -COPY platform ./platform -COPY docs ./docs +# Fix Permissions +RUN chmod +x gradlew -# Setze Gradle-Wrapper Berechtigung -RUN chmod +x ./gradlew +# Copy Sources (Struktur wie im Web-App Fix) +COPY platform/ platform/ +COPY core/ core/ +COPY backend/ backend/ +COPY frontend/ frontend/ +COPY docs/ docs/ +# Falls du 'domains' oder andere Ordner hast, die in settings.gradle.kts stehen: +# COPY domains/ domains/ -# Dependencies downloaden (für besseres Caching) -RUN ./gradlew :frontend:shells:meldestelle-portal:dependencies --no-configure-on-demand +# Dependencies laden +RUN ./gradlew :frontend:shells:meldestelle-portal:dependencies --no-daemon -# Desktop-App kompilieren (createDistributable für native Distribution) -RUN ./gradlew :frontend:shells:meldestelle-portal:createDistributable --no-configure-on-demand +# Desktop-App Distribution erstellen +# Wir nutzen 'packageDistributionForCurrentOS' oder 'createDistributable' +RUN ./gradlew :frontend:shells:meldestelle-portal:createDistributable --no-daemon # =================================================================== -# Stage 2: Runtime Stage - Ubuntu mit VNC + noVNC +# 2. Runtime Stage - Ubuntu (Notwendig für GUI/X11 Libraries) # =================================================================== FROM ubuntu:22.04 -# Verhindere interaktive Installationen ENV DEBIAN_FRONTEND=noninteractive -# Installiere System-Dependencies +# Installiere X11, VNC, Window Manager und Libraries für Compose Multiplatform +# Compose braucht oft libgl1-mesa-glx, libgtk-3-0, libasound2 etc. RUN apt-get update && apt-get install -y \ openjdk-21-jdk \ xvfb \ @@ -52,43 +52,43 @@ RUN apt-get update && apt-get install -y \ wget \ unzip \ supervisor \ + net-tools \ + libgl1-mesa-glx \ + libgtk-3-0 \ + libasound2 \ && rm -rf /var/lib/apt/lists/* -# Arbeitsverzeichnis WORKDIR /app -# Kopiere kompilierte Desktop-App von Build-Stage -COPY --from=builder /app/frontend/shells/meldestelle-portal/build/compose/binaries/main/desktop/ ./desktop-app/ +# Kopiere Build-Ergebnis +# HINWEIS: Der Pfad muss exakt stimmen. Compose Gradle Plugin Output ist oft verschachtelt. +# Wir kopieren den Inhalt nach /app/desktop-app +COPY --from=builder /app/frontend/shells/meldestelle-portal/build/compose/binaries/main/app/ /app/desktop-app/ -# Kopiere Scripts -COPY dockerfiles/clients/desktop-app/entrypoint.sh /entrypoint.sh -COPY dockerfiles/clients/desktop-app/health-check.sh /opt/health-check.sh -COPY dockerfiles/clients/desktop-app/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +# Scripts (Achte darauf, dass die Pfade im Host stimmen!) +COPY config/frontends/desktop-app/entrypoint.sh /entrypoint.sh +COPY config/frontends/desktop-app/health-check.sh /opt/health-check.sh +# Wir nutzen vorerst dein Entrypoint-Script, Supervisor Config ist optional wenn Script alles macht +# COPY config/frontends/desktop-app/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -# Setze Permissions RUN chmod +x /entrypoint.sh /opt/health-check.sh -# Erstelle VNC-User +# User Setup RUN useradd -m -s /bin/bash vncuser && \ mkdir -p /home/vncuser/.vnc && \ chown -R vncuser:vncuser /home/vncuser && \ chown -R vncuser:vncuser /app -# VNC und noVNC Ports EXPOSE 5901 6080 -# Environment Variables -ENV DISPLAY=:99 -ENV VNC_PORT=5901 -ENV NOVNC_PORT=6080 -ENV API_BASE_URL=http://api-gateway:8081 +ENV DISPLAY=:99 \ + VNC_PORT=5901 \ + NOVNC_PORT=6080 \ + API_BASE_URL="http://api-gateway:8081" -# Health-Check HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD /opt/health-check.sh -# User wechseln USER vncuser -# Entrypoint ENTRYPOINT ["/entrypoint.sh"] diff --git a/config/frontends/desktop-app/entrypoint.sh b/config/frontends/desktop-app/entrypoint.sh index 877b887f..8a1d1c37 100644 --- a/config/frontends/desktop-app/entrypoint.sh +++ b/config/frontends/desktop-app/entrypoint.sh @@ -17,6 +17,8 @@ export DISPLAY=${DISPLAY:-:99} export VNC_PORT=${VNC_PORT:-5901} export NOVNC_PORT=${NOVNC_PORT:-6080} export API_BASE_URL=${API_BASE_URL:-http://api-gateway:8081} +# Standard-Passwort setzen, falls keines über ENV kommt +export VNC_PW=${VNC_PW:-meldestelle} log "Environment:" log " DISPLAY: $DISPLAY" @@ -24,11 +26,17 @@ log " VNC_PORT: $VNC_PORT" log " NOVNC_PORT: $NOVNC_PORT" log " API_BASE_URL: $API_BASE_URL" +# 0. VNC Passwort generieren +log "Generating VNC password..." +mkdir -p /home/vncuser/.vnc +x11vnc -storepasswd "$VNC_PW" /home/vncuser/.vnc/passwd + # Erstelle .Xauthority wenn nicht vorhanden touch /home/vncuser/.Xauthority # 1. Starte X11 Virtual Display (Xvfb) log "Starting Xvfb on display $DISPLAY..." +# rm -f /tmp/.X99-lock # Aufräumen falls Container neu gestartet wurde (optional) Xvfb $DISPLAY -screen 0 1280x1024x24 -ac +extension GLX +render -noreset & XVFB_PID=$! @@ -45,16 +53,37 @@ sleep 5 # 3. Starte VNC Server log "Starting VNC server on port $VNC_PORT..." -x11vnc -display $DISPLAY -forever -usepw -create -rfbport $VNC_PORT -nopw -shared -bg +# WICHTIG: -rfbauth statt -usepw nutzen, um interaktive Abfrage zu vermeiden +x11vnc -display $DISPLAY -forever -rfbauth /home/vncuser/.vnc/passwd -create -rfbport $VNC_PORT -shared -bg VNC_PID=$! -# 4. Starte noVNC Web Interface -log "Starting noVNC web interface on port $NOVNC_PORT..." -websockify --web=/usr/share/novnc/ $NOVNC_PORT localhost:$VNC_PORT & -NOVNC_PID=$! +# 4. Start noVNC (Websockify) +log "Starting noVNC on port $NOVNC_PORT..." + +# Pfad-Korrektur für Ubuntu novnc +WEB_DIR="/usr/share/novnc" +if [ ! -d "$WEB_DIR" ]; then + log "WARNING: $WEB_DIR not found! Searching..." + WEB_DIR=$(find /usr/share -type d -name "novnc" | head -n 1) +fi + +# Fix: Index File erstellen, falls es fehlt (Ubuntu hat oft nur vnc.html) +if [ -d "$WEB_DIR" ] && [ ! -f "$WEB_DIR/index.html" ]; then + log "Fixing missing index.html in noVNC..." + if [ -f "$WEB_DIR/vnc.html" ]; then + ln -s "$WEB_DIR/vnc.html" "$WEB_DIR/index.html" + elif [ -f "$WEB_DIR/vnc_lite.html" ]; then + ln -s "$WEB_DIR/vnc_lite.html" "$WEB_DIR/index.html" + fi +fi + +log "Serving noVNC from: $WEB_DIR" + +# Starte Websockify im Vordergrund, wenn es crasht, sehen wir es +websockify --web="$WEB_DIR" $NOVNC_PORT localhost:$VNC_PORT & # 5. Warte bis Services bereit sind -sleep 10 +sleep 5 # 6. Starte Desktop-App log "Starting Meldestelle Desktop-App..." @@ -71,27 +100,30 @@ elif [ -f "client" ]; then else log "ERROR: Desktop-App executable not found!" log "Contents of /app/desktop-app:" - ls -la /app/desktop-app/ - exit 1 + ls -R /app/desktop-app/ + # Wir beenden hier NICHT, damit man debuggen kann (VNC bleibt offen) + log "Keeping VNC open for debugging..." fi -log "Found desktop app: $DESKTOP_APP" -chmod +x "$DESKTOP_APP" - -# Starte Desktop-App -./"$DESKTOP_APP" & -APP_PID=$! +if [ -n "$DESKTOP_APP" ]; then + log "Found desktop app: $DESKTOP_APP" + chmod +x "$DESKTOP_APP" + # Starte Desktop-App + ./"$DESKTOP_APP" & + APP_PID=$! +fi log "All services started successfully!" -log "VNC: vnc://localhost:$VNC_PORT" +log "VNC: vnc://localhost:$VNC_PORT (Password: $VNC_PW)" log "noVNC: http://localhost:$NOVNC_PORT/vnc.html" # Cleanup-Funktion cleanup() { log "Shutting down services..." - kill $APP_PID 2>/dev/null || true + if [ -n "$APP_PID" ]; then kill $APP_PID 2>/dev/null || true; fi kill $NOVNC_PID 2>/dev/null || true - kill $VNC_PID 2>/dev/null || true + # x11vnc läuft im Background (-bg), PID ist schwerer zu greifen, killall hilft: + pkill x11vnc || true kill $XFCE_PID 2>/dev/null || true kill $XVFB_PID 2>/dev/null || true exit 0 @@ -100,5 +132,6 @@ cleanup() { # Signal-Handler trap cleanup SIGTERM SIGINT -# Warten auf Prozesse -wait $APP_PID +# Warten auf Prozesse (unendlich, damit Container nicht stirbt wenn App crasht) +# wait $APP_PID +tail -f /dev/null diff --git a/docker-compose.yaml b/docker-compose.yaml index 6143fd07..231bb9d8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -347,9 +347,9 @@ services: # außer man nutzt envsubst im Entrypoint (für dynamische API URLs). # Hier nutzen wir den Docker-DNS Namen 'api-gateway', der ist fest in nginx.conf. dummy_var: "prevent_empty_block" -# volumes: -# # Hot-Reloading der Nginx Config (Optional) -# - ./config/frontends/web-app/nginx.conf:/etc/nginx/nginx.conf:ro + # volumes: + # # Hot-Reloading der Nginx Config (Optional) + # - ./config/frontends/web-app/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: api-gateway: condition: "service_started" @@ -358,6 +358,7 @@ services: aliases: - "web-app" + # --- DESKTOP-APP --- desktop-app: build: context: . @@ -371,7 +372,7 @@ services: environment: API_BASE_URL: "http://api-gateway:8081" ports: - - "${DESKTOP_APP_VNC_PORT:-5900:5900}" + - "${DESKTOP_APP_VNC_PORT:-5901:5901}" - "${DESKTOP_APP_NOVNC_PORT:-6080:6080}" depends_on: api-gateway: