Operacje

Wdrożenie i udostępnianie

DataFlow AI ma dwie odrębne rzeczywistości wdrożeniowe: udokumentowaną ścieżkę CI/CD, która buduje obrazy w GitHub Actions i udostępnia je na GKE Autopilot z etapami canary i automatycznym wycofywaniem, oraz rzeczywisty działający system produkcyjny — pojedynczy VPS z systemem Debian uruchamiający Docker Compose. Ta strona dokumentuje oba podejścia, uczciwie, aby operatorzy wiedzieli, które z nich obsługuje użytkowników.


Dwa modele wdrożenia

Repozytorium zawiera dwa odrębne, niespójne sposoby wdrożenia platformy. Zanim dotkniesz produkcji, musisz wiedzieć, który z nich jest rzeczywisty.

ModelCelUdostępniaUdostępnianieMigracjeCzy obsługuje produkcję dzisiaj?
(a) Udokumentowany CI/CDKlastry GKE Autopilot (dev / staging / prod)GitHub Actions → GCP Artifact Registry → Kustomize → kubectlCanary 10% → 50% → 100% z automatycznym wycofywaniemBinarium Go /app/migrate przez kubectl execNie — aspiracyjny
(b) Rzeczywista produkcjaPojedynczy VPS Debian etl.exai.cloud (57.129.120.73)Ręcznie napisane skrypty Python (deploy/deploy_to_vps.py) przez SSHBrak — pełna przebudowa + uporządkowany restartSpring Boot Flyway przy starcie usługiTak

Wiedz, która ścieżka jest aktywna

Przepływy pracy GKE odwołują się do dataflow.polkomtel.internal, regionów GCP oraz narzędzia migracji Go. Żaden z tych elementów nie obsługuje produkcji. Produkcją jest VPS pod adresem etl.exai.cloud, wdrożony za pomocą Docker Compose. Traktuj ścieżkę GKE jako architekturę docelową, a nie stan bieżący.

Obie ścieżki różnią się w fundamentalny sposób:

  • GKE używa nakładek Kustomize na środowisko; VPS używa pojedynczego pliku docker-compose.yml.
  • GKE uruchamia dedykowane narzędzie Go /app/migrate; VPS uruchamia Flyway przy starcie z agresywnymi flagami naprawy.
  • GKE ma etapy canary, testy dymne, testy integracyjne i automatyczne wycofywanie; ścieżka VPS nie ma żadnego z tych elementów.
  • GKE zakłada wieloregionowy Cloud SQL; VPS ma pojedynczy kontener PostgreSQL.

Wybór topologii docelowej

Ta strona opisuje sposób, w jaki platforma jest budowana i dostarczana. Nie omawia tego, na jaką topologię infrastruktury wdrażać — lokalnie / on-premises, pełną chmurę GCP czy zalecaną hybrydową — ani wymiarowania i kosztu każdej z nich.

Wybór topologii, wymagania infrastrukturalne, wymiarowanie pojemności, pełny rozkład kosztów usług GCP oraz przewodnik decyzyjny znajdziesz na stronie Scenariusze wdrożenia i wymiarowanie. W skrócie: dokumenty źródłowe zalecają topologię hybrydową dla Polkomtela (bazy danych źródłowe pozostają on-premises, platforma działa na GCP), z 3-letnim TCO na poziomie około 606 000–741 000 USD.

Topologia zamierzona a stan bieżący

Strona scenariuszy wdrożenia opisuje zamierzoną architekturę GCP opartą na GKE. Mechanika budowy i udostępniania udokumentowana na tej stronie odzwierciedla to, co obsługuje produkcję dzisiaj — pojedynczy VPS z Docker Compose. Przeczytaj obie strony razem, aby zrozumieć różnicę między stanem docelowym a bieżącym.


Inwentarz usług

Pełne wdrożenie tworzy osiem wdrażalnych usług plus warstwa infrastruktury.

Usługi aplikacyjne

UsługaStosBuildPort konteneraPort hosta VPS
api-gatewayKotlin / Spring Cloud Gatewayplatform/Dockerfile BUILD_MODULE=api-gateway80808085
metadata-serviceKotlin / Spring BootBUILD_MODULE=metadata-service80808181
pipeline-engineKotlin / Spring BootBUILD_MODULE=pipeline-engine80808082
lineage-serviceKotlin / Spring BootBUILD_MODULE=lineage-service80808083
monitor-serviceKotlin / Spring BootBUILD_MODULE=monitor-service80808084
copilotPython 3.12 / FastAPIai-services/copilot/Dockerfile80008090
migration-enginePython 3.12 / FastAPIai-services/migration-engine/Dockerfile80008091
frontendReact / Vite + nginxfrontend/Dockerfile803006

Interfejs Go CLI (backend/cli) jest dostarczany jako binaria wydania, a nie jako wdrożona usługa. Moduły Gradle pushdown-sql i connector-sdk są przywoływane przez build oraz konfigurację Prometheus, ale nie są samodzielnymi usługami Compose.

Usługi infrastrukturalne

Działają obok kontenerów aplikacyjnych za pośrednictwem Docker Compose:

  • PostgreSQL 15pgvector/pgvector:pg15
  • Keycloak 24 — dostawca tożsamości OIDC
  • Zookeeper + Kafkaconfluentinc/cp-* 7.7.1 (pojedynczy broker, RF=1 — nie HA)
  • Prometheusv2.54.1
  • Grafana11.2.2
  • MinIO — magazyn obiektów zgodny z S3
  • Redis 7-alpineniewdrożony na VPS; brama przechodzi na ograniczanie liczby żądań w pamięci

Architektura budowy

Usługi Kotlin

Wszystkie pięć usług Kotlin buduje się z jednego wieloetapowego pliku backend/platform/Dockerfile, wybieranego przez argument budowy BUILD_MODULE.

  • Etap 1gradle:8.5-jdk21. Pliki budowy są kopiowane jako pierwsze dla buforowania warstw, zależności są wstępnie pobierane, następnie gradle :${BUILD_MODULE}:bootJar -x test --no-daemon uruchamia wewnątrzprocesowy kompilator Kotlin z GRADLE_OPTS=-Xmx2g.
  • Etap 2eclipse-temurin:21-jre-alpine. Użytkownik dataflow bez uprawnień roota, JVM świadoma kontenera (MaxRAMPercentage=75) oraz kontrola stanu Spring Boot Actuator na /actuator/health.

Dockerfile.local to wariant wyłącznie środowiska uruchomieniowego — oczekuje plików JAR wstępnie zbudowanych na hoście (./gradlew bootJar -x test --parallel) i omija problemy DNS Dockera podczas budowy.

Usługi Python

copilot i migration-engine mają każda własny plik Dockerfile, budowany z własnego kontekstu. Copilot ładuje sekrety LLM z ignorowanego przez git pliku .env.local (required: false), więc jego brak nie psuje budowy.

Frontend

frontend/Dockerfile jest wieloetapowy: node:22-alpine uruchamia vite build, a środowiskiem uruchomieniowym jest nginx:alpine obsługujący /app/dist z niestandardowym nginx.conf do routingu SPA.


Potok CI

W .github/workflows/ znajduje się osiem przepływów pracy GitHub Actions. Najważniejsze dla wdrożenia opisano poniżej.

ci.yml — Continuous Integration

Wyzwalany przy push do main/develop oraz PR do main. Używa dorny/paths-filter do wykrycia, które części monorepo uległy zmianie (kotlin / python / go / frontend / terraform / docker / openapi), i warunkowo uruchamia zadania zmatrycowane wg języka:

ZadanieCo uruchamia
kotlin-buildJDK 21 + Gradle: kompilacja → lint Detekt → testy jednostkowe → integrationTest → build; przesyła raporty + pliki JAR
python-testMacierz [copilot, migration-engine], Python 3.12 + Poetry 1.8.4: lint/format Ruff, mypy (nieblokujący), pytest z pokryciem. Bramka pokrycia PR thresholdAll 0.70 / thresholdNew 0.80
go-buildGo 1.22: build / vet / test z -race, golangci-lint
frontend-buildNode 20: ESLint, tsc -b --noEmit, build, pokrycie vitest
terraform-validateterraform fmt/validate na środowisko + moduł, TFLint
docker-compose-validatedocker compose config, hadolint
openapi-validateLint Redocly dla 5 specyfikacji OpenAPI + kontrola zmian przełomowych oasdiff
ci-statusZagregowana bramka dla ochrony gałęzi

zero-tolerance.yml — Bramka zgodności

Przy PR/push do main/develop uruchamia scripts/detect-fake-code.js na zmienionych plikach .ts/.tsx/.js/.jsx, egzekwując regułę „brak fałszywego kodu”, plus typecheck/lint/test/build frontendu.

security-scan.yml — Bezpieczeństwo

Cotygodniowy cron (pon. 06:00 UTC) plus push/PR do main. Zadania:

  • gitleaks — wykrywanie sekretów
  • Trivy — skan kontenerów na usługę, CRITICAL,HIGH, exit-code 1
  • Snyk — skan zależności
  • OWASP dependency-check — zależności JVM
  • Python safety — podatności zależności Python
  • Checkov — skan błędnych konfiguracji Terraform
  • license-check — przerywa build przy licencjach GPL/AGPL

codeql-analysis.yml również uruchamia analizę statyczną.

Przepływy pracy wdrożenia i wydania

  • deploy-dev.yml — przy push do develop: buduje i przesyła wszystkie 8 obrazów (dev-<sha>, dev-latest), uruchamia kustomize edit set image na nakładce dev, kubectl apply --prune, czeka na udostępnianie, uruchamia testy dymne, powiadamia przez Slack.
  • deploy-staging.yml — przy push do main / tagu v*.*.*-rc* / ręcznie: buduje + przesyła 8 obrazów, tworzy kopię zapasową Cloud SQL przed wdrożeniem, stosuje nakładkę staging, uruchamia migracje bazy danych przez kubectl exec deployment/api-gateway -- /app/migrate --direction=up --environment=staging, a następnie testy dymne i integracyjne.
  • deploy-production.yml — wyłącznie workflow_dispatch; udostępnianie canary (zobacz poniżej).
  • release.yml — przy tagach v*.*.*: buduje obrazy wydania otagowane wg semver, buduje binaria Go CLI dla 5 kombinacji OS/architektura, generuje dziennik zmian w formacie conventional-commit oraz tworzy GitHub Release z SHA256SUMS.txt.

Uwierzytelnianie do GCP używa Workload Identity Federation (google-github-actions/auth@v2, id-token: write) — w repozytorium nie ma statycznych kluczy GCP.


Udostępnianie canary (ścieżka produkcyjna GKE)

Udokumentowane wdrożenie produkcyjne (deploy-production.yml) to ręczny workflow_dispatch z wejściami: image_tag (musi być przetestowanym tagiem staging), canary_weight_step1 (domyślnie 10%), canary_weight_step2 (domyślnie 50%) oraz skip_canary.

  ┌──────────────────────────────────────────────────────────────────┐
  │ 1. pre-deploy-validation                                          │
  │    verify images in Artifact Registry · verify Trivy scan ·        │
  │    check current prod pod health                                  │
  └────────────────────────────┬─────────────────────────────────────┘

  ┌──────────────────────────────────────────────────────────────────┐
  │ 2. database-backup   gcloud sql backups create dataflow-prod-db   │
  └────────────────────────────┬─────────────────────────────────────┘

  ┌──────────────────────────────────────────────────────────────────┐
  │ 3. canary-stage-1 (10%)                                           │
  │    clone each deployment as ${svc}-canary · scale by weight ·      │
  │    5-minute health observation                                    │
  │    ABORT if  >10 failures  OR  >2 pod restarts  ──────────┐        │
  └────────────────────────────┬──────────────────────────────┼───────┘
                               ▼                              │
  ┌──────────────────────────────────────────────────────────┐│
  │ 4. canary-stage-2 (50%)                                   ││
  │    scale canary to 50% · 10-minute observation            ││
  └────────────────────────────┬──────────────────────────────┼───────┘
                               ▼                              │
  ┌──────────────────────────────────────────────────────────┐│
  │ 5. full-deploy (100%)                                     ││
  │    kustomize edit set image · DB migrations (dry-run then ││
  │    real) · kubectl apply --prune · wait rollout · delete  ││
  │    canary deployments                                     ││
  └────────────────────────────┬──────────────────────────────┼───────┘
                               ▼                              │
  ┌──────────────────────────────────────────────────────────┐│
  │ 6. post-deploy-verify                                     ││
  │    all pods healthy · smoke tests vs ingress IP ·         ││
  │    replica counts match                                   ││
  └────────────────────────────┬──────────────────────────────┘│
                               ▼            on failure()       ▼
  ┌──────────────────────────────────────────────────────────────────┐
  │ 7. rollback   kubectl rollout undo all deployments · remove        │
  │    canaries · verify                                              │
  └────────────────────────────┬─────────────────────────────────────┘

  ┌──────────────────────────────────────────────────────────────────┐
  │ 8. notify   Slack on every outcome · PagerDuty critical if         │
  │    deploy failed AND rollback also failed                         │
  └──────────────────────────────────────────────────────────────────┘

Etap canary 1 klonuje każde wdrożenie jako ${svc}-canary, skaluje je do skonfigurowanej wagi i obserwuje stan przez 5 minut — przerywając, jeśli wystąpi więcej niż 10 niepowodzeń lub więcej niż 2 ponowne uruchomienia poda. Etap 2 podnosi canary do 50% i obserwuje przez 10 minut. Dopiero wtedy full-deploy przełącza na 100% i usuwa wdrożenia canary.

Canary dotyczy wyłącznie GKE

Canary 10% → 50% → 100%, bramki testów dymnych/integracyjnych oraz automatyczne kubectl rollout undo istnieją wyłącznie w przepływach pracy GKE. Ścieżka produkcyjna VPS nie ma canary ani automatycznego wycofywania.


Wdrożenie produkcyjne na VPS — krok po kroku

To jest ścieżka, która faktycznie dostarcza produkcję. Jest sterowana przez deploy/deploy_to_vps.py, 7-krokowy skrypt Python/paramiko.

Topologia

        Internet  (HTTPS :443)


  ┌───────────────────────────────────────────────────────┐
  │  Debian VPS  etl.exai.cloud  (57.129.120.73)           │
  │                                                        │
  │   System nginx  ── TLS termination (Plesk cert) ──┐    │
  │      /auth/  → 127.0.0.1:4180  (Keycloak)         │    │
  │      /api/   → 127.0.0.1:8085  (api-gateway)      │    │
  │      /       → 127.0.0.1:3006  (frontend)         │    │
  │                       │                            │   │
  │   ┌───────────────────▼────────────────────────┐   │   │
  │   │  docker compose — network dataflow-network  │   │   │
  │   │  8 app services + postgres · keycloak ·     │   │   │
  │   │  kafka · zookeeper · prometheus · grafana · │   │   │
  │   │  minio                                      │   │   │
  │   └─────────────────────────────────────────────┘   │   │
  │   (shared host: itsm.exai.cloud, openmeet.exai.cloud)│   │
  └───────────────────────────────────────────────────────┘

7 kroków deploy_to_vps.py

  1. Archiwizacjagit archive HEAD tworzy deploy/dataflow-source.tar.gz (~17,4 MB).
  2. Połączenie — SSH/SFTP do VPS.
  3. Przesłanie — przesłanie archiwum tar, rm -rf /home/debian/dataflow, rozpakowanie go; przesłanie .env.production zarówno do backend/.env, jak i frontend/.env.production; przesłanie etl-dataflow.conf.
  4. Konfiguracja nginx — instalacja konfiguracji do /etc/nginx/conf.d/etl-dataflow.conf i uruchomienie nginx -t.
  5. Budowa obrazów — budowa jednego obrazu naraz (najpierw frontend, następnie 5 usług Kotlin z limitem czasu 900 s każda, aby zarządzać pamięcią VPS, następnie 2 usługi Python).
  6. Uruchomienie falamipostgres (sleep 15) → zookeeper kafka (sleep 20) → keycloak prometheus grafana minio (sleep 15) → docker compose up -d (wszystkie); następnie przeładowanie systemowego nginx.
  7. Weryfikacjadocker compose ps i curl frontendu na 127.0.0.1:3006.

Aby uruchomić pełne wdrożenie produkcyjne:

python deploy/deploy_to_vps.py

Zaszyte na sztywno poświadczenia

deploy_to_vps.py zawiera host, użytkownika i hasło VPS jako literały zaszyte na sztywno w kodzie źródłowym. Jest to znany problem bezpieczeństwa. Nie traktuj tego skryptu jako wzorca — poświadczenia należą do menedżera sekretów. To samo dotyczy deploy/.env.production (hasła do bazy danych / Keycloak / Grafana / MinIO w postaci jawnej) oraz seed_keycloak_vps.py.

Budowa obrazów po jednym naraz

Krok 5 celowo buduje obrazy sekwencyjnie. VPS ma ograniczoną pamięć i współdzieli host z niepowiązanymi vhostami Plesk, więc równoległa budowa wszystkich pięciu usług Kotlin wyczerpałaby pamięć RAM. Każda budowa Kotlin działa z limitem czasu 900 sekund.

Ostatnie zarejestrowane uruchomienie (.deploy.log, 19 maja) zakończyło się niepowodzeniem lokalnie podczas kroku 5 — błąd Windows UnicodeEncodeError (cp1252) spowodował awarię skryptu Python podczas strumieniowania wyjścia budowy frontendu. Jest to kosmetyczna awaria lokalna, a nie błąd po stronie serwera; kompletność wdrożenia dla tego uruchomienia jest niepewna i należy ją zweryfikować ręcznie.

Plik środowiska produkcyjnego

deploy/.env.production przesuwa każdy port, aby współistnieć ze stosem itsm na tym samym VPS:

KomponentPort produkcyjny
Postgres5433
Keycloak4180
Prometheus9095
Grafana4001
MinIO9002 / 9003

REDIS nie jest wdrożony (brama używa przejścia na ograniczanie liczby żądań w pamięci), ANTHROPIC_API_KEY jest pusty (funkcje AI copilota wyłączone), a CORS_ALLOWED_ORIGINS to https://etl.exai.cloud.


nginx — terminacja TLS i routing

Systemowy nginx na VPS (nie kontener) terminuje TLS przy użyciu certyfikatu Plesk w /opt/psa/var/certificates/scfht5otmidur05fohWXaj i odwrotnie proxuje do kontenerów.

ŚcieżkaProxowane doUwagi
/auth/127.0.0.1:4180Kontener Keycloak
/api/127.0.0.1:8085/api/api-gateway; limity czasu 300 s, uaktualnienie WebSocket, SSE (proxy_buffering off)
/127.0.0.1:3006Kontener frontendu
port 80Przekierowanie 301 na HTTPS

Nie ma oauth2-proxy. Uwierzytelnianie odbywa się bezpośrednio przez Keycloak OIDC — frontendowa aplikacja SPA wykonuje przepływ OIDC, a nginx po prostu proxuje /auth/ do kontenera Keycloak.

Poprawka nagłówka uaktualnienia w nginx

apply-nginx-fix.py rozwiązuje rzeczywisty incydent produkcyjny. Oryginalna konfiguracja zaszywała na sztywno Connection "upgrade" na /api/, co pozostawiało nginx w trybie tunelu połączenia i nigdy nie emitowało ramki HTTP/2 END_STREAM dla uwierzytelnionych tokenem JWT żądań fetch z przeglądarki. Objaw: strony marketplace, szablonów, my-pipelines i data-browser kręciły się w nieskończoność.

Poprawka wprowadza warunkową mapę:

map $http_upgrade $etl_connection_upgrade {
    default upgrade;
    ''      close;
}

Skrypt tworzy kopię zapasową starej konfiguracji ze znacznikiem czasu, weryfikuje za pomocą nginx -t i przeładowuje tylko wtedy, gdy weryfikacja przebiegnie pomyślnie. Aby go zastosować:

python deploy/apply-nginx-fix.py

Ostrzeżenia nginx na współdzielonym hoście

Ponieważ etl.exai.cloud współdzieli VPS z itsm.exai.cloud i openmeet.exai.cloud, nazwa serwera koliduje z innymi vhostami Plesk i nginx emituje ostrzeżenia. Są one oczekiwane na tym hoście i nie wskazują na uszkodzone wdrożenie.


Migracje bazy danych — Flyway przy starcie

Na ścieżce VPS nie ma osobnego zadania migracji. Każda usługa Spring Boot uruchamia Flyway przy starcie wobec współdzielonej instancji PostgreSQL.

UsługaLokalizacja migracjiWersjeTabela historii
metadata-servicedb/migration/metadata/V1–V51+flyway_schema_history
monitor-servicedb/migration/monitor/V9–V25flyway_schema_history_monitor
pipeline-enginedb/migration/engine/V1, V3–V9flyway_schema_history_engine

Ponieważ VPS pierwotnie miał tabele sprzed wprowadzenia Flyway, środowisko Compose wzmacnia Flyway, aby zbiegł się niezależnie od początkowego stanu bazy danych:

SPRING_FLYWAY_VALIDATE_ON_MIGRATE=false
SPRING_FLYWAY_BASELINE_ON_MIGRATE=true
SPRING_FLYWAY_BASELINE_VERSION=20.1
SPRING_FLYWAY_OUT_OF_ORDER=true
SPRING_FLYWAY_REPAIR_ON_MIGRATE=true
SPRING_FLYWAY_PLACEHOLDER_REPLACEMENT=false

Dodatkowo scripts/make-migrations-idempotent.py przepisuje DDL migracji w miejscu — CREATE TABLECREATE TABLE IF NOT EXISTS (to samo dla INDEX/SEQUENCE), ADD COLUMN IF NOT EXISTS oraz CREATE TRIGGER poprzedzone DROP TRIGGER IF EXISTS.

Ścieżka GKE zamiast tego uruchamia binarium Go /app/migrate --direction=up --environment=… przez kubectl exec — osobne, rozbieżne narzędzie migracji.


Inicjowanie danych po wdrożeniu

Po wdrożeniu na VPS kilka idempotentnych skryptów inicjuje środowisko uruchomieniowe:

  • deploy/seed_keycloak_vps.py — odwołuje się do administracyjnego REST API Keycloak na :4180. Włącza unmanagedAttributePolicy=ENABLED, ustawia atrybut workspace_id dla 4 użytkowników demonstracyjnych, dodaje oidc-usermodel-attribute-mapper, aby workspace_id był przesyłany w każdym JWT, aktualizuje identyfikatory URI przekierowania / webOrigins / PKCE (S256) klienta dataflow-app, resetuje hasła użytkowników demonstracyjnych i weryfikuje przyznanie JWT.
  • deploy/seed_monitor_data.sql — inicjuje monitor_alerts i monitor_pipeline_runs realistycznymi danymi telekomunikacyjnymi na potrzeby przeglądu e2e Playwright.
  • deploy/create_user.py, setup_keycloak.py, ssh_cmd.py — pomocnicze skrypty jednorazowe.

Podsumowanie cyklu życia oprogramowania

Udokumentowany cykl życia CI/CD: kod (conventional commits, CODEOWNERS, Dependabot) → budowa i testy (ci.yml + zero-tolerance.yml + security-scan.yml) → budowa obrazu i publikacja do Artifact Registry → wdrożenie (develop→dev automatycznie, main→staging automatycznie, prod przez ręczny canary) → migracja → weryfikacja testami dymnymi/integracyjnymi → monitorowanie i automatyczne wycofywanie → wydanie przy tagach semver.

Rzeczywisty cykl życia VPS: git archive HEAD → przesłanie przez SSH → docker compose build na serwerze → uporządkowane docker compose up -d → Flyway uruchamia się przy starcie → ręczne inicjowanie Keycloak/monitora → przeładowanie nginx. Poprawki są stosowane za pomocą ukierunkowanych skryptów. Na VPS nie ma canary, automatycznego wycofywania ani automatycznych testów.

Poprzednia
API monitorowania i AI