first commit

This commit is contained in:
2026-10-09 02:48:31 +07:00
commit 8db22bfaa6
17 changed files with 1722 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
# Deploy (build/lokal): SiCABE Control Panel
> Untuk deploy PRODUKSI dari image registry (menyatu dengan gateway: docker-proxy +
> config-agent + nginx, dengan profile), pakai **`deploy/stack/`**. Compose di sini
> untuk **build lokal** dan menjalankan panel sendirian.
Panel (Next.js) dijalankan sebagai container. Image produksi memakai
**Next.js standalone** + user non-root (`nextjs`, uid 1001).
> Gateway **per host** (`deploy/host-gateway/`) adalah stack terpisah — sudah punya
> compose sendiri. Panel hanya perlu menunjuk ke gateway itu lewat `SICABE_HOSTS`.
## 1. Build image
```bash
./scripts/build-image.sh # tag default: sicabe/control-panel:<git-sha> + :latest
./scripts/build-image.sh --tag sicabe/control-panel:1.0.0
./scripts/build-image.sh --push --registry registry.example.com/sicabe
./scripts/build-image.sh --no-cache --platform linux/amd64
```
Script memverifikasi Dockerfile/`public/`, menandai `:latest` + `<sha>`, dan
mencetak ukuran image.
## 2. Siapkan env
```bash
cd deploy/panel
cp env.example .env # lalu isi NEXTAUTH_SECRET, api key gateway, dll.
# NEXTAUTH_SECRET: openssl rand -base64 32
```
**Penting:** panel di container **tidak bisa membaca filesystem platform** → tiap
host di `SICABE_HOSTS` **wajib** punya `configUrl` (config-agent). Karena itu
**tidak perlu** mount folder platform: katalog Trino, project dbt, dokumen OPA,
`.env` platform, dan CA Trino semuanya dibaca lewat agent (HTTP). Env
`TRINO_CATALOG_DIR` / `DBT_PROJECT_DIR` / `OPA_DATA_FILE` / `SICABE_ENV_FILE` /
`TRINO_CA_FILE` hanya dipakai `LocalConfigStore` (dev/single-host tanpa agent) —
jangan diandalkan di container.
## 3. Jalankan
```bash
cd deploy/panel
docker compose up -d # pakai image hasil build
# docker compose up -d --build # sekaligus build dari source
docker compose logs -f panel
```
Buka `http://localhost:3000` (atau `PANEL_PORT`).
## Yang persisten
| Data | Lokasi |
| --- | --- |
| Config panel (hosts/modules/services/service types) | volume `panel-data` → `/app/data/config.json` |
| Monitored state | volume `panel-data` → `/app/data/state.json` |
Backup/pindah config lewat **Settings → Backup** (Export/Import) — tanpa
menyentuh volume. Untuk migrasi dari deployment host lama: Export di yang lama →
Import di yang baru.
## Catatan jaringan & TLS
- **Default compose = `network_mode: host`.** Gateway host
(`deploy/host-gateway`) hanya membuka `127.0.0.1:22375` (aman), sehingga panel
di **bridge network tidak bisa** menjangkaunya lewat `host.docker.internal`.
Terverifikasi: dari bridge, Keycloak (`0.0.0.0:12080`) **bisa**, gateway
(`127.0.0.1:22375`) **gagal**; dari host network keduanya **bisa**. Host network
juga membuat `127.0.0.1` & SAN sertifikat Trino (`localhost`) cocok.
Port ditentukan `PORT` (default 3000), bukan `ports:`.
- **Varian bridge** (bila gateway dibuka ke alamat non-loopback): lihat komentar
di `docker-compose.yml` — hapus `network_mode: host`, tambah `ports:` +
`extra_hosts: host.docker.internal`.
- **TLS Trino**: sertifikat self-signed Trino hanya mencakup SAN
`localhost / trino / sicabe-trino / trino-coordinator / 127.0.0.1`.
`host.docker.internal` **tidak** termasuk → verifikasi TLS gagal di bridge.
- CA Trino **tidak perlu** file lokal bila host punya `configUrl` (agent `/ca`).
## Login di produksi = SSO (Keycloak)
Container berjalan `NODE_ENV=production`, dan **login kredensial dev dinonaktifkan
di produksi** (hanya provider `keycloak` yang aktif — cek
`GET /api/auth/providers`). Artinya:
- Login lewat tombol **Sign in with Keycloak** di browser (bukan form dev).
- **`NEXTAUTH_URL` harus sama dengan URL publik panel**, dan panel Keycloak
(`scripts/create-keycloak-client.sh`, `APP_URL`) harus punya redirect URI
`${NEXTAUTH_URL}/api/auth/callback/keycloak`. Kalau panel disajikan di port
selain 3000, jalankan ulang script dengan `APP_URL=http://<host>:<port>`.
- Image **gagal-cepat** bila `NEXTAUTH_SECRET` atau `KEYCLOAK_CLIENT_SECRET`
kosong (memang disengaja) — panel menolak start dengan pesan jelas.
## Update
```bash
./scripts/build-image.sh --tag sicabe/control-panel:1.1.0
PANEL_TAG=1.1.0 docker compose up -d # dari deploy/panel
```
## Healthcheck
Image menyertakan `HEALTHCHECK` (`GET /api/auth/session` → 200 walau belum login),
jadi `docker compose ps` menampilkan status `healthy`.
+61
View File
@@ -0,0 +1,61 @@
# =============================================================================
# sicabe-control-panel — deploy panel (Next.js) via Docker Compose.
#
# Build image dulu: ../../scripts/build-image.sh
# Lalu jalankan : docker compose up -d
#
# Persisten: volume bernama `panel-data` → `data/config.json` (hosts/modules/
# services/service types) + `data/state.json`. Backup/restore dari UI
# (Settings → Backup) tanpa menyentuh volume.
#
# PENTING: panel di container TIDAK bisa membaca filesystem platform → setiap
# host di SICABE_HOSTS WAJIB punya `configUrl` (config-agent).
#
# NETWORK: default `network_mode: host` karena gateway host
# (deploy/host-gateway) membuka `127.0.0.1:22375` — container di bridge TIDAK
# bisa menjangkaunya via host.docker.internal. Dengan host network, `127.0.0.1`
# berfungsi seperti di host (dan SAN sertifikat Trino `localhost` cocok).
# Lihat README.md untuk varian bridge.
# =============================================================================
name: sicabe-control-panel
services:
panel:
image: sicabe/control-panel:${PANEL_TAG:-latest}
# Biarkan `build` aktif bila ingin `docker compose up --build`.
build:
context: ../..
dockerfile: Dockerfile
container_name: sicabe-control-panel
network_mode: host
# `.env` dibuat dari env.example (cp env.example .env). `required: false`
# agar `docker compose config` tetap valid sebelum file dibuat.
env_file:
- path: .env
required: false
environment:
NODE_ENV: production
HOSTNAME: "0.0.0.0"
# Host network: port binding ditentukan PORT (bukan `ports:`).
PORT: "${PANEL_PORT:-3000}"
volumes:
- panel-data:/app/data
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# ── Varian BRIDGE (bila gateway dibuka ke alamat non-loopback) ────────────
# Hapus `network_mode: host` di atas, lalu tambahkan:
# ports:
# - "${PANEL_PORT:-3000}:3000"
# extra_hosts:
# - "host.docker.internal:host-gateway"
# dan set SICABE_HOSTS/URL memakai host.docker.internal (perhatikan SAN TLS
# Trino — host.docker.internal TIDAK ada di SAN).
volumes:
panel-data:
+70
View File
@@ -0,0 +1,70 @@
# =============================================================================
# Env untuk panel yang berjalan sebagai CONTAINER.
# Salin ke .env LALU ISI NILAINYA (jangan commit .env):
# cp deploy/panel/env.example deploy/panel/.env
#
# Beda penting dari .env dev (panel di host):
# - Panel di container TIDAK bisa membaca filesystem platform → WAJIB pakai
# config-agent (`configUrl`) di SICABE_HOSTS.
# - Alamat ke service di HOST memakai `host.docker.internal` (atau
# `network_mode: host`, lihat docker-compose.yml).
# =============================================================================
# ── Wajib ────────────────────────────────────────────────────────────────────
# URL publik panel — HARUS sama dengan yang diakses browser.
NEXTAUTH_URL=http://localhost:3000
# Rahasia NextAuth (WAJIB di produksi). Buat: openssl rand -base64 32
NEXTAUTH_SECRET=
# ── Login lokal (hybrid dengan SSO) — OPSIONAL ───────────────────────────────
#PANEL_LOCAL_USER=admin
#PANEL_LOCAL_PASSWORD_HASH=$2b$10$...
#PANEL_LOCAL_PASSWORD_HASH_B64=
#PANEL_LOCAL_ROLE=data-admin
#TRINO_SERVICE_ACCOUNT=svc_dbt
# ── Keycloak (SSO & login dev ROPC) ──────────────────────────────────────────
# Dari container, Keycloak di host diakses via host.docker.internal.
KEYCLOAK_URL=http://host.docker.internal:12080
KEYCLOAK_CLIENT_ID=sicabe-control-panel
KEYCLOAK_CLIENT_SECRET=dev-keycloak-secret
# URL yang dilihat browser (tautan Keycloak).
KEYCLOAK_WEB_URL=http://localhost:12080
#KEYCLOAK_REALM=sicabe
# ── Host/agent yang dikelola (WAJIB configUrl) ───────────────────────────────
# Gateway per host (nginx: docker-proxy + config-agent) jalan di HOST:22375.
# Dari container → host.docker.internal:22375. `publicHost` = alamat yang
# dilihat BROWSER (untuk tautan UI), mis. IP LAN host.
SICABE_HOSTS='[{"name":"local-gw","proxyUrl":"http://host.docker.internal:22375","apiKey":"<gateway-key>","configUrl":"http://host.docker.internal:22375","configApiKey":"<gateway-key>","publicHost":"localhost","enabled":true}]'
# ── Service (fallback; registry hasil scan diutamakan) ───────────────────────
# CATATAN TLS Trino: sertifikat Trino (self-signed) punya SAN
# `localhost / trino / sicabe-trino / trino-coordinator / 127.0.0.1`. Dari
# container, `host.docker.internal` TIDAK ada di SAN → verifikasi TLS gagal.
# Pilihan:
# (a) pakai `network_mode: host` (lihat docker-compose.yml) → 127.0.0.1 cocok;
# (b) tambah alias di extra_hosts yang ADA di SAN (mis. `sicabe-trino`), lalu
# set TRINO_URL=https://sicabe-trino:12443
TRINO_URL=https://host.docker.internal:12443
TRINO_WEB_URL=http://localhost:12443
# CA diambil otomatis via config-agent (`/ca`) → tak perlu file lokal.
NESSIE_URL=http://host.docker.internal:12120
AIRFLOW_URL=http://host.docker.internal:12082
STARROCKS_HOST=host.docker.internal
STARROCKS_PORT=12930
STARROCKS_WEB_URL=http://localhost:12030
OPENMETADATA_URL=http://host.docker.internal:12085
GRAFANA_URL=http://host.docker.internal:12300
MINIO_CONSOLE_URL=http://localhost:12901
# Dremio (bila ada)
#DREMIO_URL=http://host.docker.internal:12947
# ── Runtime state (di dalam volume panel-data) ───────────────────────────────
SICABE_CONFIG_FILE=data/config.json
SICABE_STATE_FILE=data/state.json
SICABE_COMPOSE_PROJECTS=sicabe