docs refactor
All checks were successful
All checks were successful
This commit is contained in:
735
docs/content/deployment/docker.md
Normal file
735
docs/content/deployment/docker.md
Normal file
@ -0,0 +1,735 @@
|
||||
---
|
||||
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.
|
Reference in New Issue
Block a user