168 lines
7.3 KiB
Markdown
168 lines
7.3 KiB
Markdown
# 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`
|
||
- **hasura** → `Deployment` + `Service`
|
||
- **trade-api** → `Deployment` + `Service`
|
||
- **trade-frontend** → `Deployment` + `Service` + `Ingress`
|
||
- **trade-ingestor** → `Deployment` (1 replika) albo `CronJob` (jeśli chcesz uruchamiać okresowo)
|
||
- **bootstrap / migracje** → `Job` (odpalane ręcznie albo jako część release’u)
|
||
|
||
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.json` → `Secret` 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?
|
||
|