Files
trade-doc/k8s-migracja.md
2026-01-06 12:33:47 +01:00

7.3 KiB
Raw Blame History

Plan migracji na Kubernetes (mikroserwisy + CI/CD)

1) Co jest dziś w repo (stan wejściowy)

Ten projekt już ma podział “mikroserwisowy” w Docker Compose:

  • DB stack (devops/db/docker-compose.yml)
    • postgres (TimescaleDB, port 5432)
    • hasura (GraphQL Engine, port 8080)
    • pgadmin (narzędzie dev, port 5050)
  • App stack (devops/app/docker-compose.yml)
    • api = trade-api (Node, port 8787, devops/api/Dockerfile)
    • frontend = trade-frontend (Node + statyczny build visualizera, port 8081, devops/app/frontend/Dockerfile)
    • ingestor = worker (Node, devops/ingestor/Dockerfile) opcjonalnie, profil ingest
  • One-shot bootstrap (devops/tools/bootstrap/docker-compose.yml)
    • db-init (aplikuje SQL devops/db/initdb/001_init.sql)
    • db-version / db-backfill (migracje “wersji” ticków)
    • hasura-bootstrap (Node script devops/db/hasura-bootstrap.mjs: track tabel + permissions + funkcje)

Konfiguracja i sekrety dziś są w tokens/*.json (gitignored) i są montowane jako pliki do kontenerów.

2) Docelowa architektura na K8s

Minimalny sensowny podział na K8s (1 namespace lub 2):

  • timescaledb (stanowe) → StatefulSet + PVC + Service
  • hasuraDeployment + Service
  • trade-apiDeployment + Service
  • trade-frontendDeployment + Service + Ingress
  • trade-ingestorDeployment (1 replika) albo CronJob (jeśli chcesz uruchamiać okresowo)
  • bootstrap / migracjeJob (odpalane ręcznie albo jako część releaseu)

Opcjonalnie:

  • pgadmin tylko na dev/staging (nieprodukcyjnie).

3) Proponowane zasoby Kubernetes (mapowanie 1:1 z Compose)

3.1 timescaledb (Postgres)

  • StatefulSet z volumeClaimTemplates (dane w PVC)
  • Service typu ClusterIP (np. timescaledb:5432)
  • Init schematu:
    • na pierwszy start można nadal użyć mechanizmu /docker-entrypoint-initdb.d (ConfigMap z SQL),
    • dla istniejących wolumenów potrzebny jest osobny Job (odpowiednik db-init z compose).

3.2 Hasura

  • Deployment + Service (hasura:8080)
  • Secret na:
    • HASURA_GRAPHQL_ADMIN_SECRET
    • klucz JWT (HASURA_GRAPHQL_JWT_SECRET / HASURA_JWT_KEY)
    • connection string do Postgresa (albo osobno hasło)
  • Bootstrap metadanych:
    • Job uruchamiający devops/db/hasura-bootstrap.mjs (odpowiednik hasura-bootstrap).

3.3 trade-api

  • Deployment + Service (trade-api:8787)
  • readinessProbe/livenessProbe: GET /healthz (już istnieje)
  • Konfiguracja:
    • env: HASURA_GRAPHQL_URL, TICKS_TABLE, CANDLES_FUNCTION, APP_VERSION, BUILD_TIMESTAMP
    • sekret plikowy (jak dziś): tokens/hasura.json + tokens/api.jsonSecret montowany do /app/tokens/*

3.4 trade-frontend

  • Deployment + Service (trade-frontend:8081)
  • Ingress wystawiający UI na zewnątrz (TLS opcjonalnie)
  • readinessProbe/livenessProbe: GET /healthz (już istnieje)
  • Sekrety plikowe:
    • tokens/frontend.json (basic auth do UI)
    • tokens/read.json (read token do proxy /api/*)
    • oba jako Secret montowany do /tokens/*
  • API_UPSTREAM: http://trade-api:8787 (Service DNS)

3.5 trade-ingestor

  • Deployment (zwykle replicas: 1)
  • Sekrety:
    • RPC do Drift (np. tokens/heliusN.json / rpcUrl / heliusApiKey)
    • write token do API (tokens/alg.json)
  • Konfiguracja:
    • MARKET_NAME, INTERVAL_MS, SOURCE, INGEST_API_URL=http://trade-api:8787
  • Uwaga: worker wymaga egress do internetu (Helius RPC + Drift).

3.6 Jobs: db-init / db-version / db-backfill / hasura-bootstrap

Bezpieczny pattern:

  • uruchamiane manualnie (kubectl) albo jako “hook” w Helm (pre/post-install)
  • odpalane w tym samym namespace co DB/Hasura (żeby DNS działał prosto)

4) Sekrety i konfiguracja (z tokens/ → K8s)

Rekomendacja: rozdziel na 2 typy:

  • Secret (nie commitować w git):
    • tokens/hasura.json (adminSecret, jwtKey)
    • tokens/api.json (api adminSecret)
    • tokens/frontend.json (basic auth)
    • tokens/read.json (read token)
    • tokens/alg.json (write token)
    • tokens/heliusN.json (RPC token / url)
  • ConfigMap:
    • wersja i parametry nie-wrażliwe: APP_VERSION, BUILD_TIMESTAMP, TICKS_TABLE, CANDLES_FUNCTION, MARKET_NAME, INTERVAL_MS

Jeśli chcesz GitOps bez trzymania sekretów “na piechotę”, wybierz jedno:

  • Sealed Secrets (zaszyfrowane sekrety w repo),
  • External Secrets Operator (Vault / AWS / GCP / Azure),
  • “na start” manualne kubectl create secret ... per środowisko.

5) Wersjonowanie (v1, v2…) i cutover bez wyłączania DB

W scripts/ops/ jest workflow wersjonowania Compose:

  • nowa wersja api+frontend(+ingestor) działa równolegle
  • pisze do nowej tabeli (drift_ticks_vN) i używa nowej funkcji (get_drift_candles_vN)

Na K8s najprościej odwzorować to tak:

  • Helm release name albo suffix w nazwach zasobów: trade-v1, trade-v2, …
  • wspólne DB/Hasura pozostają bez zmian
  • Job “version-init”:
    • odpala SQL migracji (odpowiednik db-version)
    • odpala hasura-bootstrap z TICKS_TABLE i CANDLES_FUNCTION ustawionymi na vN
  • “cutover”:
    • startujesz trade-ingestor vN
    • stopujesz trade-ingestor v1
    • po czasie robisz db-backfill (opcjonalnie) i sprzątasz stare zasoby

6) CI/CD “na gita” (build → deploy po pushu)

Opcja A (polecana): GitOps (Argo CD / Flux)

  1. CI (GitHub Actions / GitLab CI) buduje obrazy:
    • trade-api
    • trade-frontend
    • trade-ingestor
  2. CI publikuje je do registry (np. GHCR)
  3. CD (ArgoCD/Flux) automatycznie synchronizuje manifesty/Helm z repo i robi rollout

Tagowanie obrazów:

  • :sha-<shortsha> dla każdego commita
  • opcjonalnie :vN dla releaseów

Aktualizacja tagów:

  • ArgoCD Image Updater / Flux Image Automation albo
  • CI robi commit do k8s/ (np. podmienia tag w values.yaml)

Opcja B (prostsza na start): “kubectl apply” z CI

  1. CI buduje i pushuje obrazy
  2. CI wykonuje helm upgrade --install albo kubectl apply -k ...
  3. Dostęp do klastra przez sekret w repo (kubeconfig / token)

7) Proponowana sekwencja migracji (checklista)

  1. Decyzje: gdzie stoi klaster (EKS/GKE/AKS/k3s), jakie registry, jaki Ingress, jak trzymamy sekrety.
  2. K8s “base”: namespace, storage class, ingress controller, certy (jeśli TLS).
  3. DB: wdroż Timescale (StatefulSet + PVC), odpal db-init job.
  4. Hasura: wdroż Hasurę, odpal hasura-bootstrap job.
  5. API: wdroż trade-api, sprawdź /healthz.
  6. Tokeny: wygeneruj read/write tokeny (obecnym mechanizmem API) i wgraj je jako Secrets.
  7. Frontend: wdroż trade-frontend + Ingress, sprawdź /healthz i UI.
  8. Ingestor: wdroż trade-ingestor (1 replika), potwierdź że ticki wpadają.
  9. CI/CD: dodaj workflow build+push i deploy (GitOps albo kubectl).
  10. Staging → Prod: rollout na staging, potem prod.

8) Pytania, które domykają plan

  1. Jaki “git”: GitHub czy GitLab?
  2. Gdzie ma stać K8s: cloud (EKS/GKE/AKS) czy on-prem/k3s?
  3. DB w klastrze (StatefulSet) czy zewnętrzny managed Postgres/Timescale?
  4. Czy “po pushu” ma:
    • tylko robić rollout na main,
    • czy tworzyć preview env per branch/PR,
    • czy startować nową wersję vN równolegle (jak scripts/ops/)?
  5. Jaki dostęp z zewnątrz: domena + TLS, czy wystarczy port-forward / internal?