Skip to main content

Docker Deployment and Container Orchestration Guide

This document explains how to deploy the complete OAuth2 service stack with Docker Compose, locally or in production.


1. Service Stack Architecture

docker-compose.yml orchestrates the following 6 services:

Internet

│ :8080 / :8081

┌────────────────────────┐ ┌────────────────────────┐
│ fulla-frontend │ │ fulla-admin │
│ Vue 用户前端 (Nginx) │ │ 管理后台前端 (Nginx) │
│ Port: 8080 │ │ Port: 8081 │
└───────────┬────────────┘ └───────────┬────────────┘
│ 内网 │
└────────────┬───────────────┘

┌────────────────────────┐
│ fulla-backend │
│ Drogon 后端 :5555 │
│ → postgres → redis │
└───────────┬────────────┘
┌────┴─────┐
▼ ▼
postgres redis
(5433:5432) (6380:6379)

prometheus (9090:9090)
ServiceImage/buildExposed portNotes
fulla-frontenddeploy/docker/Dockerfile (frontend-runtime)8080:80Vue SPA (user-facing) + Nginx
fulla-adminfrontends/admin/Dockerfile8081:80Admin console frontend
fulla-backenddeploy/docker/Dockerfile (backend-runtime)5555:5555Drogon C++ backend
fulla-postgrespostgres:17-alpine5433:5432PostgreSQL (host port 5433, avoiding local conflicts)
fulla-redisredis:7-alpine6380:6379Redis (host port 6380, avoiding local conflicts)
fulla-prometheusprom/prometheus:latest9090:9090Metrics collection

2. Quick Start

See the Docker image and container specification guide.

# 第一次或代码变更后:重新构建并启动(在项目根目录执行)
docker-compose -f deploy/docker/docker-compose.yml up -d --build

# 后续启动(无代码变更)
docker-compose -f deploy/docker/docker-compose.yml up -d

# 查看服务状态
docker-compose -f deploy/docker/docker-compose.yml ps

# 实时查看后端日志
docker-compose -f deploy/docker/docker-compose.yml logs -f fulla-backend

# 停止所有服务
docker-compose -f deploy/docker/docker-compose.yml down

# 停止并删除数据卷(数据库会被清空)
docker-compose -f deploy/docker/docker-compose.yml down -v

3. Environment Variables and Secret Injection

fulla-backend receives sensitive configuration through environment variables in the environment section of docker-compose.yml, fully overriding the defaults in config.json. The development defaults (for local evaluation only) are:

environment:
- FULLA_DB_HOST=fulla-postgres # 指向 Docker 内网的 postgres 服务名
- FULLA_DB_NAME=fulla_db
- FULLA_DB_PASSWORD=123456
- FULLA_REDIS_HOST=fulla-redis
- FULLA_REDIS_PASSWORD=redis_secret_pass
- FULLA_VUE_CLIENT_SECRET=123456
- FULLA_AUTO_MIGRATE=true # 启动时自动执行 apps/server/migrations
- FULLA_FRONTEND_URL=http://localhost:8080
# SMTP 配置经 ${FULLA_SMTP_*:-} 占位从 .env.docker 注入;留空则回退到控制台模式
- FULLA_SMTP_HOST=${FULLA_SMTP_HOST:-}
...

WARNING Production security notes:

  • Never write real passwords directly into docker-compose.yml and commit them to Git.
  • Docker Secrets or an external secret manager (Vault, AWS Secrets Manager) is recommended.
  • Minimum requirement: use an .env file and add it to .gitignore.

The repository ships the example files deploy/env/docker.env.example (and deploy/env/server.env.example). Copy one to .env.docker (already excluded via .gitignore) and fill in production values:

FULLA_DB_PASSWORD=your_strong_password
FULLA_REDIS_PASSWORD=your_redis_password
FULLA_VUE_CLIENT_SECRET=your_client_secret
# SMTP(留空则后端回退到控制台模式)
FULLA_SMTP_HOST=
FULLA_SMTP_PORT=465
...

Then reference the values from docker-compose.yml via ${VAR_NAME:-default}.


4. Data Persistence

Data persistence is achieved through named volumes, so container restarts do not lose data:

volumes:
pgdata: # PostgreSQL 数据文件
redisdata: # Redis RDB / AOF 文件

Database initialization is performed automatically by the backend at startup (FULLA_AUTO_MIGRATE=true executes apps/server/migrations/V*.sql in filename order, followed by apps/server/seed/*.sql). docker-compose.yml also mounts the migration and seed scripts into subdirectories of the postgres container:

volumes:
- ../../apps/server/migrations:/docker-entrypoint-initdb.d/migrations:ro
- ../../apps/server/seed:/docker-entrypoint-initdb.d/seed:ro

WARNING Note: the postgres entrypoint does not recurse into subdirectories of /docker-entrypoint-initdb.d, so these two mounts are no-ops for first-time initialization; actual schema initialization is performed by the backend's FULLA_AUTO_MIGRATE.


5. Prometheus Monitoring Configuration

prometheus.yml configures Prometheus to scrape the /metrics endpoint of fulla-backend:

scrape_configs:
- job_name: "fulla-backend"
static_configs:
- targets: ["fulla-backend:5555"]

Prometheus sits on the same Docker network as fulla-backend, oauth2-net, and reaches it directly by service name (no host port needs to be exposed).

Visit http://localhost:9090 for the Prometheus UI.


6. Production Deployment Recommendations

6.1 Add SSL termination in front of the frontend service

The Nginx inside fulla-frontend serves static files; put an SSL-terminating Nginx/Traefik layer in front of it:

server {
listen 443 ssl;
server_name your-domain.com;

ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;

location / {
proxy_pass http://fulla-frontend:80;
proxy_set_header X-Forwarded-Proto https;
}

location /api/ {
proxy_pass http://fulla-backend:5555;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}

Important: forward the X-Forwarded-For header so the backend's Hodor plugin can obtain the real client IP.

6.2 Block the /metrics endpoint

The Prometheus /metrics endpoint must not be exposed to the public internet. Add to Nginx:

location /metrics {
deny all;
}

Alternatively, do not expose fulla-backend:5555 through Docker at all, allowing access only to Prometheus on the internal network.

6.3 Database connection pool tuning

For production, consider raising number_of_connections in config.prod.json from 4 to 10-50, determined by testing against actual concurrency.


7. Health Checks and Troubleshooting

# 检查所有容器状态
docker-compose ps

# 检查后端服务是否可达
curl http://localhost:5555/metrics

# 查看数据库是否已初始化
docker exec -it fulla-postgres psql -U fulla_user -d fulla_db -c "\dt"

# 查看 Redis 连接
docker exec -it fulla-redis redis-cli -a redis_secret_pass ping

# 清理并重建(数据会丢失)
docker-compose down -v
docker-compose up -d --build

Image / Container / Network Naming Conventions

Image purposeNameBuild targetNotes
Production backendfulla-backendbackend-runtimeRuntime only, small footprint; multi-arch GHCR release
Debug backendfulla-backend-debugbackend-devIncludes the full compilation toolchain
Production frontendfulla-frontendfrontend-runtimeNginx + static assets

Container naming: fulla-{service}[-debug] (backend/frontend/postgres/redis); networks: oauth2-net for Release, fulla-debug-net for Debug (see the compose files for legacy retained names). Three compose matrices: docker-compose.yml (development, 6 services), docker-compose.debug.yml (debug, 3 services), and docker-compose.prod.yml (production, 8 services including Nginx and a migrate job). All compose commands are run from the repository root with -f deploy/docker/....

Debug Environment (source mounts / GDB)

docker build -f deploy/docker/Dockerfile --target backend-dev -t fulla-backend-debug:v1.0.0 .
docker compose -f deploy/docker/docker-compose.debug.yml up -d
docker compose -f deploy/docker/docker-compose.debug.yml run --rm debug-env bash

Automated Verification

  • deploy/docker/docker-quick-verify-debug.sh (full in-container pipeline: dependency check → wait for PG/Redis readiness → create the database → parallel build → unit tests);
  • scripts/backend/full_test_docker.bat (one-click on the host: start containers → initialize → regenerate the ORM → build → test → start the server → OAuth2/Admin endpoint tests → cleanup).