doc: prod deploy
This commit is contained in:
parent
56c6ba536e
commit
5d28f6e6ee
|
|
@ -0,0 +1,234 @@
|
|||
# Banatie Production Deployment Plan
|
||||
|
||||
## Architecture
|
||||
|
||||
### Isolated Banatie Stack (5 containers):
|
||||
```
|
||||
banatie-landing - Landing Page (node:20-alpine)
|
||||
banatie-api - API Service (node:20-alpine)
|
||||
banatie-postgres - PostgreSQL 15 (isolated from VPS PostgreSQL)
|
||||
banatie-minio - MinIO storage (SNMD mode)
|
||||
banatie-minio-init - Initialization (one-shot)
|
||||
```
|
||||
|
||||
### Domains:
|
||||
```
|
||||
banatie.app → banatie-landing:3000
|
||||
api.banatie.app → banatie-api:3000
|
||||
storage.banatie.app → banatie-minio:9001 (MinIO Console)
|
||||
```
|
||||
|
||||
### File Structure:
|
||||
```
|
||||
~/workspace/projects/banatie-service/ # Git repository (code + config)
|
||||
├── apps/
|
||||
│ ├── api-service/Dockerfile
|
||||
│ └── landing/Dockerfile
|
||||
├── packages/database/
|
||||
└── prod-env/
|
||||
├── docker-compose.yml # Production compose (run from here!)
|
||||
├── .env # Config without secrets (in git)
|
||||
└── secrets.env # Secrets (NOT in git)
|
||||
|
||||
/opt/services/data/banatie/ # Runtime data only
|
||||
├── postgres/ # PostgreSQL data
|
||||
├── storage/drive{1-4}/ # MinIO SNMD
|
||||
├── logs/ # API logs
|
||||
├── results/ # Generated images
|
||||
└── uploads/ # Uploaded files
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Images
|
||||
|
||||
| Container | Image | Internal Port |
|
||||
|-----------|-------|---------------|
|
||||
| banatie-landing | Built from apps/landing/Dockerfile | 3000 |
|
||||
| banatie-api | Built from apps/api-service/Dockerfile | 3000 |
|
||||
| banatie-postgres | postgres:15-alpine | 5432 |
|
||||
| banatie-minio | quay.io/minio/minio:latest | 9000 (API), 9001 (Console) |
|
||||
|
||||
---
|
||||
|
||||
## Deployment Steps
|
||||
|
||||
### Step 1: Prepare VPS Directories
|
||||
|
||||
```bash
|
||||
# Create runtime data directory
|
||||
sudo mkdir -p /opt/services/data/banatie/{postgres,logs,results,uploads}
|
||||
sudo mkdir -p /opt/services/data/banatie/storage/drive{1,2,3,4}
|
||||
sudo chown -R $USER:$USER /opt/services/data/banatie
|
||||
```
|
||||
|
||||
### Step 2: Configure Repository
|
||||
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service
|
||||
|
||||
# Create secrets.env (not in git)
|
||||
cp prod-env/secrets.env.example prod-env/secrets.env
|
||||
nano prod-env/secrets.env
|
||||
# Fill in: GEMINI_API_KEY, etc.
|
||||
```
|
||||
|
||||
### Step 3: Configure Caddy
|
||||
|
||||
Add to `/opt/services/configs/caddy/Caddyfile`:
|
||||
```caddy
|
||||
banatie.app, www.banatie.app {
|
||||
reverse_proxy banatie-landing:3000
|
||||
encode gzip
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
}
|
||||
}
|
||||
|
||||
api.banatie.app {
|
||||
reverse_proxy banatie-api:3000
|
||||
encode gzip
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000"
|
||||
X-Content-Type-Options "nosniff"
|
||||
}
|
||||
}
|
||||
|
||||
storage.banatie.app {
|
||||
reverse_proxy banatie-minio:9001
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: First Launch
|
||||
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service/prod-env
|
||||
|
||||
# Start stack
|
||||
docker compose up -d
|
||||
|
||||
# Check status
|
||||
docker compose ps
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Restart Caddy to apply config
|
||||
docker restart caddy
|
||||
|
||||
# Create master key
|
||||
curl -X POST https://api.banatie.app/api/bootstrap/initial-key
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update Process
|
||||
|
||||
### Update Landing:
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service
|
||||
git pull origin main
|
||||
cd prod-env
|
||||
docker compose up -d --build banatie-landing
|
||||
```
|
||||
|
||||
### Update API:
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service
|
||||
git pull origin main
|
||||
cd prod-env
|
||||
docker compose up -d --build banatie-api
|
||||
```
|
||||
|
||||
### Update Both:
|
||||
```bash
|
||||
git pull origin main
|
||||
cd prod-env
|
||||
docker compose up -d --build banatie-landing banatie-api
|
||||
```
|
||||
|
||||
### Full Restart:
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service/prod-env
|
||||
docker compose down
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
**Downtime:** ~2-3 minutes for image build
|
||||
|
||||
---
|
||||
|
||||
## DNS Records (add in GoDaddy)
|
||||
|
||||
| Record | Type | Value |
|
||||
|--------|------|-------|
|
||||
| banatie.app | A | 62.146.239.118 |
|
||||
| www | CNAME | banatie.app |
|
||||
| api | A | 62.146.239.118 |
|
||||
| storage | A | 62.146.239.118 |
|
||||
|
||||
---
|
||||
|
||||
## Migration from Static Landing
|
||||
|
||||
After successful Docker deployment:
|
||||
1. Remove `/var/www/banatie.app/` (old static files)
|
||||
2. Replace banatie.app section in Caddyfile (static → reverse_proxy)
|
||||
3. `docker restart caddy`
|
||||
|
||||
---
|
||||
|
||||
## Network Architecture
|
||||
|
||||
### Internal Network (banatie-internal)
|
||||
- All containers communicate internally
|
||||
- No external port exposure
|
||||
- PostgreSQL and MinIO API only accessible internally
|
||||
|
||||
### External Network (proxy-network)
|
||||
- Shared with Caddy reverse proxy
|
||||
- Landing, API, and MinIO Console exposed to Caddy
|
||||
- SSL termination at Caddy
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **No exposed ports** - All traffic goes through Caddy with SSL
|
||||
2. **Isolated PostgreSQL** - Separate from VPS main database
|
||||
3. **Secrets management** - `secrets.env` not tracked in git
|
||||
4. **MinIO SNMD mode** - Erasure coding for data protection
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check container status:
|
||||
```bash
|
||||
cd ~/workspace/projects/banatie-service/prod-env
|
||||
docker compose ps
|
||||
docker compose logs banatie-api
|
||||
docker compose logs banatie-landing
|
||||
```
|
||||
|
||||
### Restart specific service:
|
||||
```bash
|
||||
docker compose restart banatie-api
|
||||
```
|
||||
|
||||
### Full rebuild:
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose build --no-cache
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Check Caddy logs:
|
||||
```bash
|
||||
docker logs caddy
|
||||
```
|
||||
|
|
@ -5,29 +5,29 @@
|
|||
NODE_ENV=production
|
||||
PORT=3000
|
||||
LOG_LEVEL=info
|
||||
API_BASE_URL=http://localhost:3000
|
||||
API_BASE_URL=https://api.banatie.app
|
||||
|
||||
# CORS Configuration
|
||||
CORS_ORIGIN=*
|
||||
|
||||
# Database Configuration (Docker internal network)
|
||||
DB_HOST=postgres
|
||||
DB_HOST=banatie-postgres
|
||||
DB_PORT=5432
|
||||
DB_NAME=banatie_db
|
||||
DB_USER=banatie_user
|
||||
DB_PASSWORD=banatie_secure_password
|
||||
DATABASE_URL=postgresql://banatie_user:banatie_secure_password@postgres:5432/banatie_db
|
||||
DATABASE_URL=postgresql://banatie_user:banatie_secure_password@banatie-postgres:5432/banatie_db
|
||||
|
||||
# MinIO Storage Configuration (Docker internal network)
|
||||
MINIO_ROOT_USER=banatie_admin
|
||||
MINIO_ROOT_PASSWORD=banatie_storage_secure_key_2024
|
||||
STORAGE_TYPE=minio
|
||||
MINIO_ENDPOINT=minio:9000
|
||||
MINIO_ENDPOINT=banatie-minio:9000
|
||||
MINIO_ACCESS_KEY=banatie_service
|
||||
MINIO_SECRET_KEY=banatie_service_key_2024
|
||||
MINIO_USE_SSL=false
|
||||
MINIO_BUCKET_NAME=banatie
|
||||
MINIO_PUBLIC_URL=http://localhost:9000
|
||||
MINIO_PUBLIC_URL=https://storage.banatie.app
|
||||
|
||||
# Multi-tenancy Configuration
|
||||
DEFAULT_ORG_ID=default
|
||||
|
|
|
|||
|
|
@ -1,23 +1,27 @@
|
|||
# Banatie Production Docker Compose
|
||||
# Run from: ~/workspace/projects/banatie-service/prod-env/
|
||||
# Data stored in: /opt/services/data/banatie/
|
||||
|
||||
services:
|
||||
# API Service
|
||||
app:
|
||||
banatie-api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/api-service/Dockerfile
|
||||
target: production
|
||||
container_name: banatie-app
|
||||
ports:
|
||||
- "3000:3000"
|
||||
container_name: banatie-api
|
||||
# No ports exposed - access through Caddy reverse proxy
|
||||
volumes:
|
||||
- ../apps/api-service/logs:/app/apps/api-service/logs
|
||||
- ../data/results:/app/results
|
||||
- ../data/uploads:/app/uploads
|
||||
- /opt/services/data/banatie/logs:/app/apps/api-service/logs
|
||||
- /opt/services/data/banatie/results:/app/results
|
||||
- /opt/services/data/banatie/uploads:/app/uploads
|
||||
networks:
|
||||
- banatie-network
|
||||
- banatie-internal
|
||||
- proxy-network
|
||||
depends_on:
|
||||
postgres:
|
||||
banatie-postgres:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
banatie-minio:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- .env
|
||||
|
|
@ -28,17 +32,17 @@ services:
|
|||
restart: unless-stopped
|
||||
|
||||
# Landing Page
|
||||
landing:
|
||||
banatie-landing:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/landing/Dockerfile
|
||||
container_name: banatie-landing
|
||||
ports:
|
||||
- "3001:3000"
|
||||
# No ports exposed - access through Caddy reverse proxy
|
||||
networks:
|
||||
- banatie-network
|
||||
- banatie-internal
|
||||
- proxy-network
|
||||
depends_on:
|
||||
- postgres
|
||||
- banatie-postgres
|
||||
env_file:
|
||||
- .env
|
||||
- secrets.env
|
||||
|
|
@ -47,21 +51,20 @@ services:
|
|||
- NODE_ENV=production
|
||||
restart: unless-stopped
|
||||
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
# PostgreSQL Database (isolated for Banatie)
|
||||
banatie-postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: banatie-postgres
|
||||
ports:
|
||||
- "5460:5432"
|
||||
# No ports exposed - internal access only
|
||||
volumes:
|
||||
- ../data/postgres:/var/lib/postgresql/data
|
||||
- /opt/services/data/banatie/postgres:/var/lib/postgresql/data
|
||||
- ../scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
|
||||
networks:
|
||||
- banatie-network
|
||||
- banatie-internal
|
||||
environment:
|
||||
POSTGRES_DB: banatie_db
|
||||
POSTGRES_USER: banatie_user
|
||||
POSTGRES_PASSWORD: banatie_secure_password
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-banatie_secure_password}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U banatie_user -d banatie_db"]
|
||||
interval: 30s
|
||||
|
|
@ -71,26 +74,25 @@ services:
|
|||
restart: unless-stopped
|
||||
|
||||
# MinIO Object Storage - Production Ready with SNMD
|
||||
minio:
|
||||
banatie-minio:
|
||||
image: quay.io/minio/minio:latest
|
||||
container_name: banatie-storage
|
||||
ports:
|
||||
- "9000:9000" # S3 API
|
||||
- "9001:9001" # Web Console
|
||||
container_name: banatie-minio
|
||||
# No ports exposed - Console through Caddy, API internal only
|
||||
volumes:
|
||||
# SNMD: 4 drives for full S3 compatibility and erasure coding
|
||||
- ../data/storage/drive1:/data1
|
||||
- ../data/storage/drive2:/data2
|
||||
- ../data/storage/drive3:/data3
|
||||
- ../data/storage/drive4:/data4
|
||||
- /opt/services/data/banatie/storage/drive1:/data1
|
||||
- /opt/services/data/banatie/storage/drive2:/data2
|
||||
- /opt/services/data/banatie/storage/drive3:/data3
|
||||
- /opt/services/data/banatie/storage/drive4:/data4
|
||||
networks:
|
||||
- banatie-network
|
||||
- banatie-internal
|
||||
- proxy-network # For MinIO Console access via Caddy
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
MINIO_BROWSER_REDIRECT_URL: http://localhost:9001
|
||||
MINIO_SERVER_URL: http://localhost:9000
|
||||
MINIO_DOMAIN: localhost
|
||||
# Production URLs (through Caddy)
|
||||
MINIO_BROWSER_REDIRECT_URL: https://storage.banatie.app
|
||||
MINIO_SERVER_URL: https://api.banatie.app
|
||||
# CRITICAL: SNMD command for full S3 compatibility
|
||||
command: server /data{1...4} --console-address ":9001"
|
||||
healthcheck:
|
||||
|
|
@ -102,29 +104,32 @@ services:
|
|||
restart: unless-stopped
|
||||
|
||||
# MinIO Storage Initialization
|
||||
storage-init:
|
||||
banatie-minio-init:
|
||||
image: minio/mc:latest
|
||||
container_name: banatie-storage-init
|
||||
container_name: banatie-minio-init
|
||||
networks:
|
||||
- banatie-network
|
||||
- banatie-internal
|
||||
depends_on:
|
||||
minio:
|
||||
banatie-minio:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
echo 'Setting up MinIO alias...'
|
||||
mc alias set storage http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}
|
||||
mc alias set storage http://banatie-minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}
|
||||
|
||||
echo 'Creating main bucket...'
|
||||
mc mb --ignore-existing storage/banatie
|
||||
|
||||
echo 'Creating service user...'
|
||||
mc admin user add storage banatie_service banatie_service_key_2024
|
||||
mc admin user add storage banatie_service banatie_service_key_2024 || true
|
||||
|
||||
echo 'Attaching readwrite policy to service user...'
|
||||
mc admin policy attach storage readwrite --user=banatie_service
|
||||
mc admin policy attach storage readwrite --user=banatie_service || true
|
||||
|
||||
echo 'Setting up lifecycle policy...'
|
||||
cat > /tmp/lifecycle.json <<'LIFECYCLE'
|
||||
|
|
@ -143,7 +148,7 @@ services:
|
|||
]
|
||||
}
|
||||
LIFECYCLE
|
||||
mc ilm import storage/banatie < /tmp/lifecycle.json
|
||||
mc ilm import storage/banatie < /tmp/lifecycle.json || true
|
||||
|
||||
echo 'Storage initialization completed!'
|
||||
echo 'Bucket: banatie'
|
||||
|
|
@ -153,11 +158,9 @@ services:
|
|||
restart: "no"
|
||||
|
||||
networks:
|
||||
banatie-network:
|
||||
# Internal network for service-to-service communication
|
||||
banatie-internal:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
driver: local
|
||||
storage-data:
|
||||
driver: local
|
||||
# External network shared with Caddy reverse proxy
|
||||
proxy-network:
|
||||
external: true
|
||||
|
|
|
|||
Loading…
Reference in New Issue