Docker Deployment¶
Deploy SQLatte with Docker for production-ready, containerized environments.
Quick Start (5 Minutes)¶
1. Prerequisites¶
2. Clone & Configure¶
# Clone repository
git clone https://github.com/osmanuygar/sqlatte.git
cd sqlatte
# Create config file
cp config/config.example.yaml config/config.yaml
nano config/config.yaml
3. Start SQLatte¶
# Start with Docker Compose
docker-compose up -d
# Check logs
docker-compose logs -f
# Access SQLatte
http://localhost:8000
Done! SQLatte is running in Docker.
Docker Compose (Recommended)¶
Basic Setup¶
docker-compose.yml:
version: '3.8'
services:
sqlatte:
build: .
container_name: sqlatte
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./config:/app/config
- ./logs:/app/logs
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- DB_PASSWORD=${DB_PASSWORD}
env_file:
- .env
Start:
With PostgreSQL Analytics¶
docker-compose.yml:
version: '3.8'
services:
sqlatte:
build: .
container_name: sqlatte
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./config:/app/config
- ./logs:/app/logs
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- ANALYTICS_DB_PASSWORD=${ANALYTICS_DB_PASSWORD}
depends_on:
- postgres
networks:
- sqlatte_network
postgres:
image: postgres:15-alpine
container_name: sqlatte_postgres
restart: unless-stopped
environment:
- POSTGRES_USER=sqlatte
- POSTGRES_PASSWORD=${ANALYTICS_DB_PASSWORD}
- POSTGRES_DB=sqlatte_analytics
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- sqlatte_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sqlatte"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_data:
networks:
sqlatte_network:
driver: bridge
config.yaml:
analytics:
enabled: true
storage: "postgresql"
postgresql:
host: "postgres" # Container name
port: 5432
database: "sqlatte_analytics"
user: "sqlatte"
password: "${ANALYTICS_DB_PASSWORD}"
Start:
# Set password in .env
echo "ANALYTICS_DB_PASSWORD=strong_password" >> .env
# Start services
docker-compose up -d
# Check health
docker-compose ps
Production Deployment¶
With Nginx Reverse Proxy¶
docker-compose.production.yml:
version: '3.8'
services:
sqlatte:
build: .
container_name: sqlatte_prod
restart: unless-stopped
expose:
- "8000"
volumes:
- ./config:/app/config
- ./logs:/app/logs
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- DB_PASSWORD=${DB_PASSWORD}
- ANALYTICS_DB_PASSWORD=${ANALYTICS_DB_PASSWORD}
env_file:
- .env.production
depends_on:
- postgres
networks:
- sqlatte_network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
postgres:
image: postgres:15-alpine
container_name: sqlatte_postgres
restart: unless-stopped
environment:
- POSTGRES_USER=sqlatte
- POSTGRES_PASSWORD=${ANALYTICS_DB_PASSWORD}
- POSTGRES_DB=sqlatte_analytics
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- sqlatte_network
nginx:
image: nginx:alpine
container_name: sqlatte_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- sqlatte
networks:
- sqlatte_network
volumes:
postgres_data:
networks:
sqlatte_network:
driver: bridge
nginx.conf:
events {
worker_connections 1024;
}
http {
upstream sqlatte {
server sqlatte:8000;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name analytics.company.com;
return 301 https://$server_name$request_uri;
}
# HTTPS Server
server {
listen 443 ssl http2;
server_name analytics.company.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
client_max_body_size 50M;
location / {
proxy_pass http://sqlatte;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
Deploy:
# Create SSL directory
mkdir -p ssl
# Get SSL certificate (Let's Encrypt)
sudo certbot certonly --standalone -d analytics.company.com
sudo cp /etc/letsencrypt/live/analytics.company.com/fullchain.pem ssl/cert.pem
sudo cp /etc/letsencrypt/live/analytics.company.com/privkey.pem ssl/key.pem
# Start production stack
docker-compose -f docker-compose.production.yml up -d
# Verify
curl https://analytics.company.com/health
Dockerfile¶
SQLatte includes a production-ready Dockerfile:
FROM python:3.10-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Run application
CMD ["python", "run.py"]
Build manually:
Environment Variables¶
.env.production:
# LLM Provider
ANTHROPIC_API_KEY=sk-ant-xxxxx
# Database Credentials
DB_HOST=trino.company.com
DB_PORT=443
DB_USER=sqlatte_service
DB_PASSWORD=secure_password
# Analytics Database
ANALYTICS_DB_PASSWORD=analytics_password
# Email/SMTP
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=app_password
# Application
SQLATTE_ENV=production
LOG_LEVEL=INFO
Load in Docker Compose:
Docker Commands¶
Start/Stop¶
# Start all services
docker-compose up -d
# Stop all services
docker-compose down
# Restart
docker-compose restart
# Stop and remove volumes (⚠️ deletes data!)
docker-compose down -v
Logs¶
# Follow all logs
docker-compose logs -f
# SQLatte logs only
docker-compose logs -f sqlatte
# Last 100 lines
docker-compose logs --tail=100 sqlatte
# PostgreSQL logs
docker-compose logs -f postgres
Execute Commands¶
# Access SQLatte container
docker-compose exec sqlatte bash
# Run Python command
docker-compose exec sqlatte python -c "from src.core.config import load_config; print(load_config())"
# Access PostgreSQL
docker-compose exec postgres psql -U sqlatte -d sqlatte_analytics
Health Checks¶
# Check container health
docker-compose ps
# Check SQLatte health endpoint
curl http://localhost:8000/health
# Check PostgreSQL
docker-compose exec postgres pg_isready -U sqlatte
Volumes & Persistence¶
Important Volumes¶
volumes:
# Config files (editable from host)
- ./config:/app/config
# Logs (accessible from host)
- ./logs:/app/logs
# PostgreSQL data (persistent)
- postgres_data:/var/lib/postgresql/data
Backup PostgreSQL¶
# Backup
docker-compose exec postgres pg_dump -U sqlatte sqlatte_analytics > backup.sql
# Restore
docker-compose exec -T postgres psql -U sqlatte sqlatte_analytics < backup.sql
Scaling & Performance¶
Horizontal Scaling (Multiple Instances)¶
version: '3.8'
services:
sqlatte:
build: .
restart: unless-stopped
deploy:
replicas: 3 # Run 3 instances
# ... rest of config
nginx:
# Load balancer
# ... upstream config
Note: Requires Redis for shared session storage (future feature)
Resource Limits¶
services:
sqlatte:
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
Monitoring¶
With Prometheus & Grafana¶
docker-compose.monitoring.yml:
version: '3.8'
services:
# ... (sqlatte, postgres, nginx)
prometheus:
image: prom/prometheus
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
networks:
- sqlatte_network
grafana:
image: grafana/grafana
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
networks:
- sqlatte_network
volumes:
prometheus_data:
grafana_data:
prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'sqlatte'
static_configs:
- targets: ['sqlatte:8000']
Troubleshooting¶
Container Won't Start¶
# Check logs
docker-compose logs sqlatte
# Check config
docker-compose config
# Validate Dockerfile
docker build -t sqlatte:test .
Connection Issues¶
# Check network
docker network ls
docker network inspect sqlatte_sqlatte_network
# Ping containers
docker-compose exec sqlatte ping postgres
Database Connection Failed¶
# Check PostgreSQL is running
docker-compose ps postgres
# Test connection
docker-compose exec postgres psql -U sqlatte -d sqlatte_analytics
# Check config.yaml
docker-compose exec sqlatte cat /app/config/config.yaml
Port Already in Use¶
# Find process using port
lsof -i :8000
# or
netstat -tulpn | grep 8000
# Kill process or change port in docker-compose.yml
ports:
- "8001:8000" # Use 8001 on host
Security Best Practices¶
1. Use Secrets¶
# Don't commit .env files
echo ".env" >> .gitignore
echo ".env.production" >> .gitignore
# Use Docker secrets (Swarm mode)
echo "sk-ant-xxxxx" | docker secret create anthropic_key -
2. Non-Root User¶
Dockerfile:
3. Read-Only Filesystem¶
4. Network Isolation¶
Updates & Upgrades¶
Update SQLatte¶
# Pull latest code
git pull origin main
# Rebuild image
docker-compose build sqlatte
# Restart with new image
docker-compose up -d sqlatte
Update Dependencies¶
# Update requirements.txt
pip install -r requirements.txt --upgrade
pip freeze > requirements.txt
# Rebuild
docker-compose build --no-cache
docker-compose up -d
Production Checklist¶
Before deploying to production:
- [ ] Use environment variables for secrets
- [ ] Enable HTTPS with valid SSL certificate
- [ ] Set up PostgreSQL for analytics persistence
- [ ] Configure email/SMTP for scheduled reports
- [ ] Enable health checks
- [ ] Set resource limits (CPU, memory)
- [ ] Configure log rotation
- [ ] Set up monitoring (Prometheus + Grafana)
- [ ] Create backup strategy for PostgreSQL
- [ ] Use read-only config volume
- [ ] Restrict CORS to specific domains
- [ ] Enable rate limiting (nginx)
- [ ] Test disaster recovery
Next Steps¶
- Configure Database: Database Providers
- Configure LLM: LLM Providers
- Enable Analytics: Analytics Setup
- Setup Email: Email Settings
Need help? Check GitHub Issues or Installation Guide.