736 lines
14 KiB
Markdown
736 lines
14 KiB
Markdown
---
|
|
version: "1.0"
|
|
date: "2025-01-15"
|
|
author: "DWS Foldsite Team"
|
|
title: "Docker Deployment"
|
|
description: "Running Foldsite in Docker containers"
|
|
summary: "Complete guide to deploying Foldsite with Docker for consistent, isolated, and portable deployments."
|
|
quick_tips:
|
|
- "Docker ensures consistent environments across development and production"
|
|
- "Use docker-compose for easy multi-container setup"
|
|
- "Mount content as volumes for live updates without rebuilding"
|
|
---
|
|
|
|
# Docker Deployment
|
|
|
|
Docker provides isolated, reproducible deployments of Foldsite. Perfect for testing, staging, and production environments.
|
|
|
|
## Why Docker?
|
|
|
|
**Benefits:**
|
|
- **Consistency** - Same environment everywhere
|
|
- **Isolation** - Dependencies don't conflict with system
|
|
- **Portability** - Run anywhere Docker runs
|
|
- **Easy deployment** - Single command to start
|
|
- **Version control** - Docker images are versioned
|
|
|
|
**Use cases:**
|
|
- Team development (everyone has same environment)
|
|
- Staging environments before production
|
|
- Production deployments
|
|
- CI/CD pipelines
|
|
- Cloud platform deployments
|
|
|
|
## Prerequisites
|
|
|
|
### Install Docker
|
|
|
|
**macOS:**
|
|
```bash
|
|
# Download Docker Desktop from docker.com
|
|
# Or use Homebrew
|
|
brew install --cask docker
|
|
```
|
|
|
|
**Linux (Ubuntu/Debian):**
|
|
```bash
|
|
# Update package index
|
|
sudo apt update
|
|
|
|
# Install Docker
|
|
sudo apt install docker.io docker-compose
|
|
|
|
# Add your user to docker group
|
|
sudo usermod -aG docker $USER
|
|
|
|
# Log out and back in for group changes
|
|
```
|
|
|
|
**Windows:**
|
|
```bash
|
|
# Download Docker Desktop from docker.com
|
|
# Requires WSL2
|
|
```
|
|
|
|
**Verify installation:**
|
|
```bash
|
|
docker --version
|
|
docker-compose --version
|
|
```
|
|
|
|
## Quick Start with Docker Compose
|
|
|
|
### Step 1: Create docker-compose.yml
|
|
|
|
In your Foldsite directory:
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
foldsite:
|
|
image: python:3.11-slim
|
|
container_name: foldsite
|
|
working_dir: /app
|
|
command: >
|
|
sh -c "pip install -r requirements.txt &&
|
|
python main.py --config config.toml"
|
|
ports:
|
|
- "8081:8081"
|
|
volumes:
|
|
- .:/app
|
|
- ./my-site/content:/app/content
|
|
- ./my-site/templates:/app/templates
|
|
- ./my-site/styles:/app/styles
|
|
environment:
|
|
- PYTHONUNBUFFERED=1
|
|
restart: unless-stopped
|
|
```
|
|
|
|
### Step 2: Create config.toml for Docker
|
|
|
|
```toml
|
|
[paths]
|
|
content_dir = "/app/content"
|
|
templates_dir = "/app/templates"
|
|
styles_dir = "/app/styles"
|
|
|
|
[server]
|
|
listen_address = "0.0.0.0" # Important: bind to all interfaces
|
|
listen_port = 8081
|
|
admin_browser = false
|
|
max_threads = 4
|
|
debug = false
|
|
access_log = true
|
|
```
|
|
|
|
### Step 3: Start Container
|
|
|
|
```bash
|
|
# Start in background
|
|
docker-compose up -d
|
|
|
|
# View logs
|
|
docker-compose logs -f
|
|
|
|
# Stop
|
|
docker-compose down
|
|
```
|
|
|
|
Visit `http://localhost:8081` to see your site!
|
|
|
|
## Building a Custom Docker Image
|
|
|
|
For production, build a dedicated Foldsite image:
|
|
|
|
### Create Dockerfile
|
|
|
|
```dockerfile
|
|
# Dockerfile
|
|
FROM python:3.11-slim
|
|
|
|
# Set working directory
|
|
WORKDIR /app
|
|
|
|
# Install system dependencies
|
|
RUN apt-get update && apt-get install -y \
|
|
build-essential \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Copy requirements first (for caching)
|
|
COPY requirements.txt .
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
# Copy application code
|
|
COPY . .
|
|
|
|
# Create directories for content
|
|
RUN mkdir -p /content /templates /styles
|
|
|
|
# Expose port
|
|
EXPOSE 8081
|
|
|
|
# Run application
|
|
CMD ["python", "main.py", "--config", "/app/config.toml"]
|
|
```
|
|
|
|
### Build Image
|
|
|
|
```bash
|
|
# Build image
|
|
docker build -t foldsite:latest .
|
|
|
|
# Tag for versioning
|
|
docker tag foldsite:latest foldsite:1.0.0
|
|
```
|
|
|
|
### Run Container
|
|
|
|
```bash
|
|
docker run -d \
|
|
--name foldsite \
|
|
-p 8081:8081 \
|
|
-v $(pwd)/my-site/content:/content \
|
|
-v $(pwd)/my-site/templates:/templates \
|
|
-v $(pwd)/my-site/styles:/styles \
|
|
foldsite:latest
|
|
```
|
|
|
|
## Development with Docker
|
|
|
|
### Hot Reload Setup
|
|
|
|
Mount your code as volumes for live updates:
|
|
|
|
```yaml
|
|
# docker-compose.dev.yml
|
|
version: '3.8'
|
|
|
|
services:
|
|
foldsite:
|
|
build: .
|
|
container_name: foldsite-dev
|
|
ports:
|
|
- "8081:8081"
|
|
volumes:
|
|
# Mount everything for development
|
|
- .:/app
|
|
- ./my-site/content:/app/content
|
|
- ./my-site/templates:/app/templates
|
|
- ./my-site/styles:/app/styles
|
|
environment:
|
|
- PYTHONUNBUFFERED=1
|
|
- FLASK_ENV=development
|
|
command: >
|
|
sh -c "pip install -r requirements.txt &&
|
|
python main.py --config config.toml"
|
|
```
|
|
|
|
**Usage:**
|
|
```bash
|
|
# Start development environment
|
|
docker-compose -f docker-compose.dev.yml up
|
|
|
|
# Changes to content, templates, and styles appear immediately
|
|
# Code changes require restart
|
|
```
|
|
|
|
### Interactive Development
|
|
|
|
Run commands inside container:
|
|
|
|
```bash
|
|
# Start bash session in running container
|
|
docker exec -it foldsite bash
|
|
|
|
# Inside container, you can:
|
|
python main.py --config config.toml
|
|
pip install new-package
|
|
ls /app/content
|
|
```
|
|
|
|
## Production Docker Setup
|
|
|
|
### Multi-Stage Build
|
|
|
|
Optimize image size with multi-stage build:
|
|
|
|
```dockerfile
|
|
# Dockerfile.production
|
|
# Stage 1: Build dependencies
|
|
FROM python:3.11-slim as builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Install build dependencies
|
|
RUN apt-get update && apt-get install -y \
|
|
build-essential \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install Python dependencies
|
|
COPY requirements.txt .
|
|
RUN pip install --user --no-cache-dir -r requirements.txt
|
|
|
|
# Stage 2: Runtime
|
|
FROM python:3.11-slim
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy Python dependencies from builder
|
|
COPY --from=builder /root/.local /root/.local
|
|
|
|
# Copy application
|
|
COPY . .
|
|
|
|
# Create non-root user
|
|
RUN useradd -m -u 1000 foldsite && \
|
|
chown -R foldsite:foldsite /app
|
|
|
|
# Switch to non-root user
|
|
USER foldsite
|
|
|
|
# Make sure scripts in .local are usable
|
|
ENV PATH=/root/.local/bin:$PATH
|
|
|
|
EXPOSE 8081
|
|
|
|
# Use Gunicorn for production
|
|
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8081", "main:app"]
|
|
```
|
|
|
|
### Production docker-compose.yml
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
foldsite:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.production
|
|
container_name: foldsite-prod
|
|
ports:
|
|
- "8081:8081"
|
|
volumes:
|
|
- ./content:/app/content:ro # Read-only
|
|
- ./templates:/app/templates:ro
|
|
- ./styles:/app/styles:ro
|
|
environment:
|
|
- PYTHONUNBUFFERED=1
|
|
restart: always
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8081/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
```
|
|
|
|
## Docker Compose Examples
|
|
|
|
### With Nginx Reverse Proxy
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
foldsite:
|
|
build: .
|
|
container_name: foldsite
|
|
expose:
|
|
- "8081"
|
|
volumes:
|
|
- ./content:/app/content:ro
|
|
- ./templates:/app/templates:ro
|
|
- ./styles:/app/styles:ro
|
|
restart: always
|
|
|
|
nginx:
|
|
image: nginx:alpine
|
|
container_name: nginx
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
|
- ./ssl:/etc/nginx/ssl:ro
|
|
depends_on:
|
|
- foldsite
|
|
restart: always
|
|
```
|
|
|
|
**nginx.conf:**
|
|
```nginx
|
|
events {
|
|
worker_connections 1024;
|
|
}
|
|
|
|
http {
|
|
upstream foldsite {
|
|
server foldsite:8081;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name your-domain.com;
|
|
|
|
location / {
|
|
proxy_pass http://foldsite;
|
|
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;
|
|
}
|
|
|
|
# Cache static assets
|
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
|
proxy_pass http://foldsite;
|
|
expires 30d;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Multiple Sites
|
|
|
|
Run multiple Foldsite instances:
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
blog:
|
|
build: .
|
|
ports:
|
|
- "8081:8081"
|
|
volumes:
|
|
- ./blog/content:/app/content
|
|
- ./blog/templates:/app/templates
|
|
- ./blog/styles:/app/styles
|
|
restart: always
|
|
|
|
portfolio:
|
|
build: .
|
|
ports:
|
|
- "8082:8081"
|
|
volumes:
|
|
- ./portfolio/content:/app/content
|
|
- ./portfolio/templates:/app/templates
|
|
- ./portfolio/styles:/app/styles
|
|
restart: always
|
|
```
|
|
|
|
## Volume Management
|
|
|
|
### Content Volumes
|
|
|
|
**Development** - Mount host directories:
|
|
```yaml
|
|
volumes:
|
|
- ./my-site/content:/app/content
|
|
- ./my-site/templates:/app/templates
|
|
- ./my-site/styles:/app/styles
|
|
```
|
|
|
|
**Production** - Read-only mounts:
|
|
```yaml
|
|
volumes:
|
|
- ./content:/app/content:ro
|
|
- ./templates:/app/templates:ro
|
|
- ./styles:/app/styles:ro
|
|
```
|
|
|
|
### Named Volumes
|
|
|
|
For persistent data:
|
|
|
|
```yaml
|
|
services:
|
|
foldsite:
|
|
volumes:
|
|
- content-data:/app/content
|
|
- templates-data:/app/templates
|
|
|
|
volumes:
|
|
content-data:
|
|
templates-data:
|
|
```
|
|
|
|
**Backup named volumes:**
|
|
```bash
|
|
# Backup
|
|
docker run --rm \
|
|
-v foldsite_content-data:/data \
|
|
-v $(pwd):/backup \
|
|
alpine tar czf /backup/content-backup.tar.gz -C /data .
|
|
|
|
# Restore
|
|
docker run --rm \
|
|
-v foldsite_content-data:/data \
|
|
-v $(pwd):/backup \
|
|
alpine tar xzf /backup/content-backup.tar.gz -C /data
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
Pass configuration via environment:
|
|
|
|
```yaml
|
|
services:
|
|
foldsite:
|
|
environment:
|
|
- FOLDSITE_DEBUG=false
|
|
- FOLDSITE_PORT=8081
|
|
- FOLDSITE_MAX_THREADS=4
|
|
```
|
|
|
|
**Use in config:**
|
|
```python
|
|
# In a config loader
|
|
import os
|
|
|
|
debug = os.getenv('FOLDSITE_DEBUG', 'false').lower() == 'true'
|
|
port = int(os.getenv('FOLDSITE_PORT', '8081'))
|
|
```
|
|
|
|
## Common Docker Commands
|
|
|
|
### Container Management
|
|
|
|
```bash
|
|
# Start containers
|
|
docker-compose up -d
|
|
|
|
# Stop containers
|
|
docker-compose down
|
|
|
|
# Restart
|
|
docker-compose restart
|
|
|
|
# View logs
|
|
docker-compose logs -f
|
|
|
|
# View logs for specific service
|
|
docker-compose logs -f foldsite
|
|
|
|
# Exec into running container
|
|
docker exec -it foldsite bash
|
|
|
|
# View running containers
|
|
docker ps
|
|
|
|
# View all containers (including stopped)
|
|
docker ps -a
|
|
```
|
|
|
|
### Image Management
|
|
|
|
```bash
|
|
# Build image
|
|
docker-compose build
|
|
|
|
# Pull images
|
|
docker-compose pull
|
|
|
|
# List images
|
|
docker images
|
|
|
|
# Remove unused images
|
|
docker image prune
|
|
|
|
# Remove all unused data
|
|
docker system prune -a
|
|
```
|
|
|
|
### Debugging
|
|
|
|
```bash
|
|
# Check container logs
|
|
docker logs foldsite
|
|
|
|
# Follow logs
|
|
docker logs -f foldsite
|
|
|
|
# Inspect container
|
|
docker inspect foldsite
|
|
|
|
# View container stats
|
|
docker stats foldsite
|
|
|
|
# Check container health
|
|
docker ps --filter health=healthy
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Port Already in Use
|
|
|
|
```
|
|
Error: port is already allocated
|
|
```
|
|
|
|
**Solution:** Change port mapping:
|
|
```yaml
|
|
ports:
|
|
- "8082:8081" # Map to different host port
|
|
```
|
|
|
|
### Permission Errors
|
|
|
|
```
|
|
PermissionError: [Errno 13] Permission denied
|
|
```
|
|
|
|
**Solution:** Fix volume permissions:
|
|
```bash
|
|
# Fix ownership
|
|
sudo chown -R $USER:$USER ./my-site
|
|
|
|
# Or run container as your user
|
|
docker run --user $(id -u):$(id -g) ...
|
|
```
|
|
|
|
### Container Won't Start
|
|
|
|
```bash
|
|
# Check logs
|
|
docker-compose logs
|
|
|
|
# Common issues:
|
|
# 1. Missing requirements.txt
|
|
# 2. Wrong working directory
|
|
# 3. Port conflicts
|
|
# 4. Volume mount errors
|
|
```
|
|
|
|
### Changes Not Appearing
|
|
|
|
**Content changes:**
|
|
- Should appear immediately (volumes mounted)
|
|
- Try hard refresh in browser
|
|
|
|
**Code changes:**
|
|
- Require container restart: `docker-compose restart`
|
|
|
|
**Template changes:**
|
|
- Should appear immediately
|
|
- Check volume mounts are correct
|
|
|
|
### Container Crashes
|
|
|
|
```bash
|
|
# View exit reason
|
|
docker ps -a
|
|
|
|
# Check logs
|
|
docker logs foldsite
|
|
|
|
# Try running interactively
|
|
docker run -it foldsite bash
|
|
```
|
|
|
|
## Performance Optimization
|
|
|
|
### Resource Limits
|
|
|
|
Limit container resources:
|
|
|
|
```yaml
|
|
services:
|
|
foldsite:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '2.0'
|
|
memory: 1G
|
|
reservations:
|
|
cpus: '0.5'
|
|
memory: 512M
|
|
```
|
|
|
|
### Build Cache
|
|
|
|
Speed up builds:
|
|
|
|
```bash
|
|
# Use BuildKit
|
|
DOCKER_BUILDKIT=1 docker build .
|
|
|
|
# Cache from registry
|
|
docker build --cache-from myregistry/foldsite:latest .
|
|
```
|
|
|
|
### Layer Optimization
|
|
|
|
Order Dockerfile for better caching:
|
|
|
|
```dockerfile
|
|
# Dependencies first (change rarely)
|
|
COPY requirements.txt .
|
|
RUN pip install -r requirements.txt
|
|
|
|
# Code last (changes often)
|
|
COPY . .
|
|
```
|
|
|
|
## CI/CD Integration
|
|
|
|
### GitHub Actions Example
|
|
|
|
```yaml
|
|
# .github/workflows/docker.yml
|
|
name: Build Docker Image
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v2
|
|
|
|
- name: Build image
|
|
run: docker build -t foldsite:${{ github.sha }} .
|
|
|
|
- name: Test
|
|
run: |
|
|
docker run -d --name test foldsite:${{ github.sha }}
|
|
docker logs test
|
|
docker stop test
|
|
```
|
|
|
|
## Cloud Platform Deployment
|
|
|
|
### Deploy to AWS ECS
|
|
|
|
```bash
|
|
# Build and push to ECR
|
|
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
|
|
docker tag foldsite:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/foldsite:latest
|
|
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/foldsite:latest
|
|
```
|
|
|
|
### Deploy to Google Cloud Run
|
|
|
|
```bash
|
|
# Build and push to GCR
|
|
gcloud builds submit --tag gcr.io/PROJECT_ID/foldsite
|
|
gcloud run deploy --image gcr.io/PROJECT_ID/foldsite --platform managed
|
|
```
|
|
|
|
### Deploy to Azure Container Instances
|
|
|
|
```bash
|
|
# Create container instance
|
|
az container create \
|
|
--resource-group myResourceGroup \
|
|
--name foldsite \
|
|
--image myregistry.azurecr.io/foldsite:latest \
|
|
--ports 8081
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
- **[Production Deployment](production.md)** - Production-grade setup
|
|
- **[Local Development](local-development.md)** - Development workflow
|
|
- **[Support](../support.md)** - Get help
|
|
|
|
Docker provides a solid foundation for deploying Foldsite anywhere. From development to production, containers ensure consistency and reliability.
|