Files
zeavis-edu/docs/superpowers/specs/2026-05-22-docker-deployment-design.md
T

111 lines
3.9 KiB
Markdown

# Docker Deployment Design
## Goal
Deploy all ZeaVis Edu production services from GitHub Actions to GHCR and then to a VPS behind Traefik.
The deployment will use:
- Deploy directory: `/opt/ZeaVis-Edu`
- Shared Traefik Docker network: `app-shared-net`
- Frontend domain: `zeavisedu.asepharyana.tech`
- API domain: `api.zeavisedu.asepharyana.tech`
- ML service domain: `ml.zeavisedu.asepharyana.tech`
## Architecture
The repo will deploy as three independent production containers:
1. `zeavis-web`
- Builds the Vite React app from `apps/web`.
- Serves static assets through Nginx.
- Routes through Traefik at `https://zeavisedu.asepharyana.tech`.
- Uses internal port `80`.
2. `zeavis-api`
- Runs the Elysia API with Bun from `apps/api`.
- Routes through Traefik at `https://api.zeavisedu.asepharyana.tech`.
- Uses internal port `3000`.
- Calls the ML service through `ML_SERVICE_URL=https://ml.zeavisedu.asepharyana.tech`.
3. `zeavis-ml`
- Runs the FastAPI ML service from `apps/ml-service` with Uvicorn.
- Routes through Traefik at `https://ml.zeavisedu.asepharyana.tech`.
- Uses internal port `8000`.
- Loads the TensorFlow model from the path expected by the existing service code unless implementation inspection shows a supported environment override.
All containers join the external Docker network `app-shared-net`. Host ports are not published because Traefik is the public entrypoint.
## Images
GitHub Actions will build and push three GHCR images on pushes to `main` and manual workflow dispatch:
- `ghcr.io/${{ github.repository }}/web:main`
- `ghcr.io/${{ github.repository }}/api:main`
- `ghcr.io/${{ github.repository }}/ml:main`
Each image will also receive a SHA tag for traceability.
## Compose deployment
> Catatan (2026-08-02): port produksi sekarang API 4006, nginx 4011, ML 4012; deploy Nix+systemd+Caddy.
The VPS will run `docker compose` from `/opt/ZeaVis-Edu`.
The compose file will define:
- External network `app-shared-net`.
- One service per image.
- Stable container names: `zeavis-web`, `zeavis-api`, `zeavis-ml`.
- `restart: always` for all services.
- Traefik labels for each domain, using `websecure`, TLS enabled, and the `letsencrypt` cert resolver.
- `env_file: .env` for runtime configuration.
## GitHub Actions deployment flow
The workflow will:
1. Check out the repository.
2. Set up Docker Buildx.
3. Log in to GHCR with `GITHUB_TOKEN`.
4. Build and push the web, API, and ML images.
5. SSH to the VPS after successful image pushes.
6. Change directory to `/opt/ZeaVis-Edu`.
7. Pull the latest `main` branch.
8. Rewrite `.env` from GitHub repository secrets.
9. Ensure `app-shared-net` exists.
10. Run `docker compose pull`.
11. Run `docker compose up -d`.
12. Show `docker compose ps` and fail if any service is not up.
## Required secrets
The workflow requires these repository secrets:
- `VPS_HOST`
- `VPS_USER`
- `VPS_PORT`
- `VPS_SSH_KEY`
- `DATABASE_URL`
If frontend or API code requires public URL configuration at build time or runtime, implementation will add the exact required secrets after inspecting the existing environment variable names.
## Verification
After deployment, verify:
- `docker compose ps` shows all three services up.
- `docker logs --tail 100 zeavis-web` has no startup errors.
- `docker logs --tail 100 zeavis-api` has no startup errors.
- `docker logs --tail 100 zeavis-ml` has no startup errors.
- `curl -I https://zeavisedu.asepharyana.tech/` returns a non-Traefik 404 response.
- `curl -I https://api.zeavisedu.asepharyana.tech/health` returns the API health response or an expected application response.
- `curl -I https://ml.zeavisedu.asepharyana.tech/health` returns the ML health response.
## Out of scope
- Provisioning Traefik itself.
- Creating DNS records.
- Migrating or seeding production database data.
- Changing application behavior beyond what is required to run correctly in containers.