diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 2f4b168..2e6d801 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -190,54 +190,76 @@ jobs: COMPOSE_FILES="-f docker-compose.yml -f docker-compose.hetzner.yml" COMMIT_SHA="${GITHUB_SHA:-unknown}" SHORT_SHA="${COMMIT_SHA:0:8}" + REPO_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" echo "=== BreakPilot Compliance Deploy ===" echo "Commit: ${SHORT_SHA}" echo "Deploy Dir: ${DEPLOY_DIR}" echo "" - # 1. Repo auf dem Host aktualisieren - if [ ! -d "${DEPLOY_DIR}/.git" ]; then - echo "FEHLER: ${DEPLOY_DIR} ist kein Git-Repository" - echo "Bitte einmalig einrichten:" - echo " git clone ${DEPLOY_DIR}" - echo " cp .env.example ${DEPLOY_DIR}/.env # und anpassen" - exit 1 - fi + # Der Runner laeuft in einem Container mit Docker-Socket-Zugriff, + # hat aber KEINEN direkten Zugriff auf das Host-Dateisystem. + # Loesung: Alpine-Helper-Container mit Host-Bind-Mount fuer Git-Ops. - # Git pull im Deploy-Verzeichnis - apk add --no-cache git > /dev/null 2>&1 - cd "${DEPLOY_DIR}" - git fetch origin main - git reset --hard origin/main + # 1. Repo auf dem Host erstellen/aktualisieren via Helper-Container + echo "=== Updating code on host ===" + docker run --rm \ + -v "${DEPLOY_DIR}:${DEPLOY_DIR}" \ + alpine/git:latest \ + sh -c " + if [ ! -d '${DEPLOY_DIR}/.git' ]; then + echo 'Erstmaliges Klonen nach ${DEPLOY_DIR}...' + git clone '${REPO_URL}' '${DEPLOY_DIR}' + else + cd '${DEPLOY_DIR}' + git fetch origin main + git reset --hard origin/main + fi + " echo "Code aktualisiert auf ${SHORT_SHA}" - # 2. Core-Services (admin, backend, ai-sdk, dev-portal) bauen + # 2. .env sicherstellen (muss einmalig manuell angelegt werden) + docker run --rm -v "${DEPLOY_DIR}:${DEPLOY_DIR}" alpine \ + sh -c " + if [ ! -f '${DEPLOY_DIR}/.env' ]; then + echo 'WARNUNG: ${DEPLOY_DIR}/.env fehlt!' + echo 'Bitte einmalig auf dem Host anlegen.' + echo 'Deploy wird fortgesetzt (Services starten ggf. mit Defaults).' + else + echo '.env vorhanden' + fi + " + + # 3. Docker Images bauen (docker compose liest vom Host-Dateisystem) echo "" echo "=== Building Docker Images ===" - docker compose ${COMPOSE_FILES} build \ - --parallel \ + docker compose -f "${DEPLOY_DIR}/docker-compose.yml" \ + -f "${DEPLOY_DIR}/docker-compose.hetzner.yml" \ + --project-directory "${DEPLOY_DIR}" \ + build --parallel \ admin-compliance \ backend-compliance \ ai-compliance-sdk \ developer-portal - # 3. Container neu starten (nur geaenderte) + # 4. Container neu starten echo "" echo "=== Deploying ===" - docker compose ${COMPOSE_FILES} up -d \ - --remove-orphans \ + docker compose -f "${DEPLOY_DIR}/docker-compose.yml" \ + -f "${DEPLOY_DIR}/docker-compose.hetzner.yml" \ + --project-directory "${DEPLOY_DIR}" \ + up -d --remove-orphans \ admin-compliance \ backend-compliance \ ai-compliance-sdk \ developer-portal - # 4. Health Checks + # 5. Health Checks echo "" echo "=== Health Checks ===" sleep 10 - for svc in bp-compliance-admin bp-compliance-backend bp-compliance-ai-sdk; do + for svc in bp-compliance-admin bp-compliance-backend bp-compliance-ai-sdk bp-compliance-developer-portal; do STATUS=$(docker inspect --format='{{.State.Status}}' "${svc}" 2>/dev/null || echo "not found") echo "${svc}: ${STATUS}" done diff --git a/.gitea/workflows/rag-ingest.yaml b/.gitea/workflows/rag-ingest.yaml index dc94501..7c1c534 100644 --- a/.gitea/workflows/rag-ingest.yaml +++ b/.gitea/workflows/rag-ingest.yaml @@ -6,6 +6,7 @@ # Phasen: gesetze, eu, templates, datenschutz, verbraucherschutz, verify, version, all # # Voraussetzung: RAG-Service und Qdrant muessen auf Hetzner laufen. +# Die BreakPilot-Services muessen deployed sein (ci.yaml deploy-hetzner). name: RAG Ingestion @@ -24,37 +25,68 @@ jobs: steps: - name: Setup run: | - apk add --no-cache git curl bash python3 > /dev/null 2>&1 + apk add --no-cache git curl bash > /dev/null 2>&1 - name: Checkout run: | git clone --depth 1 --branch main ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git . - - name: Discover RAG Service + - name: Run Ingestion run: | set -euo pipefail - echo "=== Docker Environment Discovery ===" + PHASE="${{ github.event.inputs.phase }}" + DEPLOY_DIR="/opt/breakpilot-compliance" + + echo "=== RAG Ingestion: Phase ${PHASE} ===" echo "" - echo "--- Alle Container ---" - docker ps --format "table {{.Names}}\t{{.Ports}}\t{{.Networks}}" 2>/dev/null || true + # Pruefen ob Services laufen + echo "--- BreakPilot Container ---" + docker ps --filter name=bp- --format "{{.Names}}: {{.Status}}" 2>/dev/null || true echo "" - echo "--- Container mit Port 8097 ---" - docker ps --format "{{.Names}} {{.Ports}}" 2>/dev/null | grep -i "8097" || echo "Kein Container auf Port 8097" + # Netzwerk finden in dem die bp-Services laufen + BP_NETWORK=$(docker inspect bp-core-rag-service --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}' 2>/dev/null || echo "") + if [ -z "$BP_NETWORK" ]; then + # Fallback: Netzwerk vom Compliance-Backend nehmen + BP_NETWORK=$(docker inspect bp-compliance-backend --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}' 2>/dev/null || echo "") + fi + + if [ -z "$BP_NETWORK" ]; then + echo "FEHLER: Keine BreakPilot-Container gefunden." + echo "Bitte zuerst deployen (CI/CD Pipeline oder manuell)." + echo "" + echo "Verfuegbare Container:" + docker ps --format " {{.Names}}" 2>/dev/null || true + echo "" + echo "Verfuegbare Netzwerke:" + docker network ls --format " {{.Name}}" 2>/dev/null || true + exit 1 + fi + + echo "BreakPilot Netzwerk: $BP_NETWORK" echo "" - echo "--- Container mit 'rag' oder 'compliance' im Namen ---" - docker ps --format "{{.Names}} {{.Networks}} {{.Ports}}" 2>/dev/null | grep -iE "rag|compliance" || echo "Keine gefunden" - echo "" + # Ingestion in einem Container auf dem BP-Netzwerk ausfuehren, + # mit Zugriff auf die Scripts aus dem Deploy-Dir + docker run --rm \ + --network "$BP_NETWORK" \ + -v "${DEPLOY_DIR}/scripts:/workspace/scripts:ro" \ + -e "WORK_DIR=/tmp/rag-ingestion" \ + -e "RAG_URL=http://bp-core-rag-service:8097/api/v1/documents/upload" \ + -e "QDRANT_URL=https://qdrant-dev.breakpilot.ai" \ + -e "SDK_URL=http://bp-compliance-ai-sdk:8090" \ + alpine:3.19 \ + sh -c " + apk add --no-cache curl bash coreutils > /dev/null 2>&1 + mkdir -p /tmp/rag-ingestion/{pdfs,repos,texts} + cd /workspace + if [ '${PHASE}' = 'all' ]; then + bash scripts/ingest-legal-corpus.sh + else + bash scripts/ingest-legal-corpus.sh --only '${PHASE}' + fi + " - echo "--- Netzwerke ---" - docker network ls 2>/dev/null || true echo "" - - # Finde RAG-Service Port auf dem Host - echo "--- Host-Port-Mapping fuer 8097 ---" - docker ps --format "{{.Names}} {{.Ports}}" 2>/dev/null | grep "8097" || echo "Kein 8097 Mapping" - echo "" - - echo "=== Discovery abgeschlossen ===" + echo "=== Ingestion abgeschlossen ===" diff --git a/docker-compose.hetzner.yml b/docker-compose.hetzner.yml index 521a692..137a409 100644 --- a/docker-compose.hetzner.yml +++ b/docker-compose.hetzner.yml @@ -3,23 +3,48 @@ # ========================================================= # Verwendung: docker compose -f docker-compose.yml -f docker-compose.hetzner.yml up -d # -# Entfernt ARM64-Platform-Constraint (Hetzner = x86_64/amd64) -# und passt Hetzner-spezifische Einstellungen an. +# Aenderungen gegenueber docker-compose.yml: +# - Platform: arm64 → amd64 (Hetzner = x86_64) +# - Network: external → auto-create (kein breakpilot-core auf Hetzner) +# - depends_on: core-health-check entfernt (kein Core auf Hetzner) +# - API URLs: auf Hetzner-interne Adressen angepasst # ========================================================= +# Auf Hetzner laeuft kein breakpilot-core, daher Network selbst erstellen +networks: + breakpilot-network: + external: false + name: breakpilot-network + services: + # Core-Health-Check deaktivieren (Core laeuft nicht auf Hetzner) + core-health-check: + entrypoint: ["sh", "-c", "echo 'Core health check skipped on Hetzner' && exit 0"] + restart: "no" + admin-compliance: platform: linux/amd64 + depends_on: + core-health-check: + condition: service_completed_successfully + backend-compliance: + condition: service_started developer-portal: platform: linux/amd64 backend-compliance: platform: linux/amd64 + depends_on: + core-health-check: + condition: service_completed_successfully ai-compliance-sdk: platform: linux/amd64 + depends_on: + core-health-check: + condition: service_completed_successfully compliance-tts-service: platform: linux/amd64