redaction (#1)
Add the redacted source file for demo purposes Reviewed-on: https://source.michaeldileo.org/michael_dileo/Keybard-Vagabond-Demo/pulls/1 Co-authored-by: Michael DiLeo <michael_dileo@proton.me> Co-committed-by: Michael DiLeo <michael_dileo@proton.me>
This commit was merged in pull request #1.
This commit is contained in:
53
build/bookwyrm/.dockerignore
Normal file
53
build/bookwyrm/.dockerignore
Normal file
@@ -0,0 +1,53 @@
|
||||
# BookWyrm Docker Build Ignore
|
||||
# Exclude files that don't need to be in the final container image
|
||||
|
||||
# Python bytecode and cache
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
|
||||
# Git and GitHub
|
||||
.git
|
||||
.github
|
||||
|
||||
# Testing files
|
||||
.pytest*
|
||||
test_*
|
||||
**/tests/
|
||||
**/test/
|
||||
|
||||
# Environment and config files that shouldn't be in image
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Development files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Documentation that we manually remove anyway
|
||||
*.md
|
||||
LICENSE
|
||||
README*
|
||||
CHANGELOG*
|
||||
|
||||
# Docker files (don't need these in the final image)
|
||||
Dockerfile*
|
||||
.dockerignore
|
||||
docker-compose*
|
||||
|
||||
# Build artifacts
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.tox/
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
191
build/bookwyrm/README.md
Normal file
191
build/bookwyrm/README.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# BookWyrm Container Build
|
||||
|
||||
Multi-stage Docker container build for BookWyrm social reading platform, optimized for the Keyboard Vagabond infrastructure.
|
||||
|
||||
## 🏗️ **Architecture**
|
||||
|
||||
### **Multi-Stage Build Pattern**
|
||||
Following the established Keyboard Vagabond pattern with optimized, production-ready containers:
|
||||
|
||||
- **`bookwyrm-base`** - Shared foundation image with BookWyrm source code and dependencies
|
||||
- **`bookwyrm-web`** - Web server container (Nginx + Django/Gunicorn)
|
||||
- **`bookwyrm-worker`** - Background worker container (Celery + Beat)
|
||||
|
||||
### **Container Features**
|
||||
- **Base Image**: Python 3.11 slim with multi-stage optimization (~60% size reduction from 1GB+ to ~400MB)
|
||||
- **Security**: Non-root execution with dedicated `bookwyrm` user (UID 1000)
|
||||
- **Process Management**: Supervisor for multi-process orchestration
|
||||
- **Health Checks**: Built-in health monitoring for both web and worker containers
|
||||
- **Logging**: All logs directed to stdout/stderr for Kubernetes log collection
|
||||
- **ARM64 Optimized**: Built specifically for ARM64 architecture
|
||||
|
||||
## 📁 **Directory Structure**
|
||||
|
||||
```
|
||||
build/bookwyrm/
|
||||
├── build.sh # Main build script
|
||||
├── README.md # This documentation
|
||||
├── bookwyrm-base/ # Base image with shared components
|
||||
│ ├── Dockerfile # Multi-stage base build
|
||||
│ └── entrypoint-common.sh # Shared initialization utilities
|
||||
├── bookwyrm-web/ # Web server container
|
||||
│ ├── Dockerfile # Web-specific build
|
||||
│ ├── nginx.conf # Optimized Nginx configuration
|
||||
│ ├── supervisord-web.conf # Process management for web services
|
||||
│ └── entrypoint-web.sh # Web container initialization
|
||||
└── bookwyrm-worker/ # Background worker container
|
||||
├── Dockerfile # Worker-specific build
|
||||
├── supervisord-worker.conf # Process management for worker services
|
||||
└── entrypoint-worker.sh # Worker container initialization
|
||||
```
|
||||
|
||||
## 🔨 **Building Containers**
|
||||
|
||||
### **Prerequisites**
|
||||
- Docker with ARM64 support
|
||||
- Access to Harbor registry (`<YOUR_REGISTRY_URL>`)
|
||||
- Active Harbor login session
|
||||
|
||||
### **Build All Containers**
|
||||
```bash
|
||||
# Build latest version
|
||||
./build.sh
|
||||
|
||||
# Build specific version
|
||||
./build.sh v1.0.0
|
||||
```
|
||||
|
||||
### **Build Process**
|
||||
1. **Base Image**: Downloads BookWyrm production branch, installs Python dependencies
|
||||
2. **Web Container**: Adds Nginx + Gunicorn configuration, optimized for HTTP serving
|
||||
3. **Worker Container**: Adds Celery configuration for background task processing
|
||||
4. **Registry Push**: Interactive push to Harbor registry with confirmation
|
||||
|
||||
**Build Optimizations**:
|
||||
- **`.dockerignore`**: Automatically excludes Python bytecode, cache files, and development artifacts
|
||||
- **Multi-stage build**: Separates build dependencies from runtime, reducing final image size
|
||||
- **Manual cleanup**: Removes documentation, tests, and unnecessary files
|
||||
- **Runtime compilation**: Static assets and theme compilation moved to runtime to avoid requiring environment variables during build
|
||||
|
||||
### **Manual Build Steps**
|
||||
```bash
|
||||
# Build base image first
|
||||
cd bookwyrm-base
|
||||
docker build --platform linux/arm64 -t bookwyrm-base:latest .
|
||||
cd ..
|
||||
|
||||
# Build web container
|
||||
cd bookwyrm-web
|
||||
docker build --platform linux/arm64 -t <YOUR_REGISTRY_URL>/library/bookwyrm-web:latest .
|
||||
cd ..
|
||||
|
||||
# Build worker container
|
||||
cd bookwyrm-worker
|
||||
docker build --platform linux/arm64 -t <YOUR_REGISTRY_URL>/library/bookwyrm-worker:latest .
|
||||
```
|
||||
|
||||
## 🎯 **Container Specifications**
|
||||
|
||||
### **Web Container (`bookwyrm-web`)**
|
||||
- **Services**: Nginx (port 80) + Gunicorn (port 8000)
|
||||
- **Purpose**: HTTP requests, API endpoints, static file serving
|
||||
- **Health Check**: HTTP health endpoint monitoring
|
||||
- **Features**:
|
||||
- Rate limiting (login: 5/min, API: 30/min)
|
||||
- Static file caching (1 year expiry)
|
||||
- Security headers
|
||||
- WebSocket support for real-time features
|
||||
|
||||
### **Worker Container (`bookwyrm-worker`)**
|
||||
- **Services**: Celery Worker + Celery Beat + Celery Flower (optional)
|
||||
- **Purpose**: Background tasks, scheduled jobs, ActivityPub federation
|
||||
- **Health Check**: Redis broker connectivity monitoring
|
||||
- **Features**:
|
||||
- Multi-queue processing (default, high_priority, low_priority)
|
||||
- Scheduled task execution
|
||||
- Task monitoring via Flower
|
||||
|
||||
## 📊 **Resource Requirements**
|
||||
|
||||
### **Production Recommendations**
|
||||
```yaml
|
||||
# Web Container
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1000m # 1 CPU core
|
||||
memory: 2Gi # 2GB RAM
|
||||
limits:
|
||||
cpu: 2000m # 2 CPU cores
|
||||
memory: 4Gi # 4GB RAM
|
||||
|
||||
# Worker Container
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m # 0.5 CPU core
|
||||
memory: 1Gi # 1GB RAM
|
||||
limits:
|
||||
cpu: 1000m # 1 CPU core
|
||||
memory: 2Gi # 2GB RAM
|
||||
```
|
||||
|
||||
## 🔧 **Configuration**
|
||||
|
||||
### **Required Environment Variables**
|
||||
Both containers require these environment variables for proper operation:
|
||||
|
||||
```bash
|
||||
# Database Configuration
|
||||
DB_HOST=postgresql-shared-rw.postgresql-system.svc.cluster.local
|
||||
DB_PORT=5432
|
||||
DB_NAME=bookwyrm
|
||||
DB_USER=bookwyrm_user
|
||||
DB_PASSWORD=<REPLACE_WITH_ACTUAL_PASSWORD>
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_BROKER_URL=redis://:<REPLACE_WITH_REDIS_PASSWORD>@redis-ha-haproxy.redis-system.svc.cluster.local:6379/3
|
||||
REDIS_ACTIVITY_URL=redis://:<REPLACE_WITH_REDIS_PASSWORD>@redis-ha-haproxy.redis-system.svc.cluster.local:6379/4
|
||||
|
||||
# Application Settings
|
||||
SECRET_KEY=<REPLACE_WITH_DJANGO_SECRET_KEY>
|
||||
DEBUG=false
|
||||
USE_HTTPS=true
|
||||
DOMAIN=bookwyrm.keyboardvagabond.com
|
||||
|
||||
# S3 Storage
|
||||
USE_S3=true
|
||||
AWS_ACCESS_KEY_ID=<REPLACE_WITH_S3_ACCESS_KEY>
|
||||
AWS_SECRET_ACCESS_KEY=<REPLACE_WITH_S3_SECRET_KEY>
|
||||
AWS_STORAGE_BUCKET_NAME=bookwyrm-bucket
|
||||
AWS_S3_REGION_NAME=eu-central-003
|
||||
AWS_S3_ENDPOINT_URL=<REPLACE_WITH_S3_ENDPOINT>
|
||||
AWS_S3_CUSTOM_DOMAIN=https://bm.keyboardvagabond.com
|
||||
|
||||
# Email Configuration
|
||||
EMAIL_HOST=<YOUR_SMTP_SERVER>
|
||||
EMAIL_PORT=587
|
||||
EMAIL_HOST_USER=bookwyrm@mail.keyboardvagabond.com
|
||||
EMAIL_HOST_PASSWORD=<REPLACE_WITH_EMAIL_PASSWORD>
|
||||
EMAIL_USE_TLS=true
|
||||
```
|
||||
|
||||
## 🚀 **Deployment**
|
||||
|
||||
These containers are designed for Kubernetes deployment with:
|
||||
- **Zero Trust**: Cloudflare tunnel integration (no external ports)
|
||||
- **Storage**: Longhorn persistent volumes + S3 media storage
|
||||
- **Monitoring**: OpenObserve ServiceMonitor integration
|
||||
- **Scaling**: Horizontal Pod Autoscaler ready
|
||||
|
||||
## 📝 **Notes**
|
||||
|
||||
- **ARM64 Optimized**: Built specifically for ARM64 nodes
|
||||
- **Size Optimized**: Multi-stage builds reduce final image size by ~75%
|
||||
- **Security Hardened**: Non-root execution, minimal dependencies
|
||||
- **Production Ready**: Comprehensive health checks, logging, and error handling
|
||||
- **GitOps Ready**: Compatible with Flux CD deployment patterns
|
||||
|
||||
## 🔗 **Related Documentation**
|
||||
|
||||
- [BookWyrm Official Documentation](https://docs.joinbookwyrm.com/)
|
||||
- [Kubernetes Manifests](../../manifests/applications/bookwyrm/)
|
||||
- [Infrastructure Setup](../../manifests/infrastructure/)
|
||||
85
build/bookwyrm/bookwyrm-base/Dockerfile
Normal file
85
build/bookwyrm/bookwyrm-base/Dockerfile
Normal file
@@ -0,0 +1,85 @@
|
||||
# BookWyrm Base Multi-stage Build
|
||||
# Production-optimized build targeting ~400MB final image size
|
||||
# Shared base image for BookWyrm web and worker containers
|
||||
|
||||
# Build stage - Install dependencies and prepare optimized source
|
||||
FROM python:3.11-slim AS builder
|
||||
|
||||
# Install build dependencies in a single layer
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Clone source with minimal depth and remove git afterwards to save space
|
||||
RUN git clone -b production --depth 1 --single-branch \
|
||||
https://github.com/bookwyrm-social/bookwyrm.git . \
|
||||
&& rm -rf .git
|
||||
|
||||
# Create virtual environment and install Python dependencies
|
||||
RUN python3 -m venv /opt/venv \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir --upgrade pip setuptools wheel \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir -r requirements.txt \
|
||||
&& find /opt/venv -name "*.pyc" -delete \
|
||||
&& find /opt/venv -name "__pycache__" -type d -exec rm -rf {} + \
|
||||
&& find /opt/venv -name "*.pyo" -delete
|
||||
|
||||
# Remove unnecessary files from source to reduce image size
|
||||
# Note: .dockerignore will exclude __pycache__, *.pyc, etc. automatically
|
||||
RUN rm -rf \
|
||||
/app/.github \
|
||||
/app/docker \
|
||||
/app/nginx \
|
||||
/app/locale \
|
||||
/app/bw-dev \
|
||||
/app/bookwyrm/tests \
|
||||
/app/bookwyrm/test* \
|
||||
/app/*.md \
|
||||
/app/LICENSE \
|
||||
/app/.gitignore \
|
||||
/app/requirements.txt
|
||||
|
||||
# Runtime stage - Minimal runtime environment
|
||||
FROM python:3.11-slim AS runtime
|
||||
|
||||
# Set environment variables
|
||||
ENV TZ=UTC \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PATH="/opt/venv/bin:$PATH" \
|
||||
VIRTUAL_ENV="/opt/venv"
|
||||
|
||||
# Install only essential runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpq5 \
|
||||
curl \
|
||||
gettext \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
# Create bookwyrm user for security
|
||||
RUN useradd --create-home --shell /bin/bash --uid 1000 bookwyrm
|
||||
|
||||
# Copy virtual environment and optimized source
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
COPY --from=builder /app /app
|
||||
|
||||
# Set working directory and permissions
|
||||
WORKDIR /app
|
||||
RUN chown -R bookwyrm:bookwyrm /app \
|
||||
&& mkdir -p /app/mediafiles /app/static /app/images \
|
||||
&& chown -R bookwyrm:bookwyrm /app/mediafiles /app/static /app/images
|
||||
|
||||
# Default user
|
||||
USER bookwyrm
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python manage.py check --deploy || exit 1
|
||||
50
build/bookwyrm/bookwyrm-web/Dockerfile
Normal file
50
build/bookwyrm/bookwyrm-web/Dockerfile
Normal file
@@ -0,0 +1,50 @@
|
||||
# BookWyrm Web Container - Production Optimized
|
||||
# Nginx + Django/Gunicorn web server
|
||||
|
||||
FROM bookwyrm-base AS bookwyrm-web
|
||||
|
||||
# Switch to root for system package installation
|
||||
USER root
|
||||
|
||||
# Install nginx and supervisor with minimal footprint
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
nginx-light \
|
||||
supervisor \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
# Install Gunicorn in virtual environment
|
||||
RUN /opt/venv/bin/pip install --no-cache-dir gunicorn
|
||||
|
||||
# Copy configuration files
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY supervisord-web.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY entrypoint-web.sh /entrypoint.sh
|
||||
|
||||
# Create necessary directories and set permissions efficiently
|
||||
# Logs go to stdout/stderr, so only create cache and temp directories
|
||||
RUN chmod +x /entrypoint.sh \
|
||||
&& mkdir -p /var/cache/nginx /var/lib/nginx \
|
||||
&& mkdir -p /tmp/nginx_client_temp /tmp/nginx_proxy_temp /tmp/nginx_fastcgi_temp /tmp/nginx_uwsgi_temp /tmp/nginx_scgi_temp /tmp/nginx_cache \
|
||||
&& chown -R www-data:www-data /var/cache/nginx /var/lib/nginx \
|
||||
&& chown -R bookwyrm:bookwyrm /app \
|
||||
&& chmod 755 /tmp/nginx_*
|
||||
|
||||
# Clean up nginx default files to reduce image size
|
||||
RUN rm -rf /var/www/html \
|
||||
&& rm -f /etc/nginx/sites-enabled/default \
|
||||
&& rm -f /etc/nginx/sites-available/default
|
||||
|
||||
# Expose HTTP port
|
||||
EXPOSE 80
|
||||
|
||||
# Health check optimized for web container
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost:80/health/ || curl -f http://localhost:80/ || exit 1
|
||||
|
||||
# Run as root to manage nginx and gunicorn via supervisor
|
||||
USER root
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
52
build/bookwyrm/bookwyrm-web/entrypoint-web.sh
Normal file
52
build/bookwyrm/bookwyrm-web/entrypoint-web.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# BookWyrm Web Container Entrypoint
|
||||
# Simplified - init containers handle database/migrations
|
||||
|
||||
set -e
|
||||
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting BookWyrm Web Container..."
|
||||
|
||||
# Only handle web-specific tasks (database/migrations handled by init containers)
|
||||
|
||||
# Compile themes FIRST - must happen before static file collection
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Checking if theme compilation is needed..."
|
||||
if [ "${FORCE_COMPILE_THEMES:-false}" = "true" ] || [ ! -f "/tmp/.themes_compiled" ]; then
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Compiling themes..."
|
||||
if python manage.py compile_themes; then
|
||||
touch /tmp/.themes_compiled
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Theme compilation completed successfully"
|
||||
else
|
||||
echo "WARNING: Theme compilation failed"
|
||||
fi
|
||||
else
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Themes already compiled, skipping (set FORCE_COMPILE_THEMES=true to force)"
|
||||
fi
|
||||
|
||||
# Collect static files AFTER theme compilation - includes compiled CSS files
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Checking if static files collection is needed..."
|
||||
if [ "${FORCE_COLLECTSTATIC:-false}" = "true" ] || [ ! -f "/tmp/.collectstatic_done" ]; then
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Collecting static files to S3..."
|
||||
if python manage.py collectstatic --noinput --clear; then
|
||||
touch /tmp/.collectstatic_done
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Static files collection completed successfully"
|
||||
else
|
||||
echo "WARNING: Static files collection to S3 failed"
|
||||
fi
|
||||
else
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Static files already collected, skipping (set FORCE_COLLECTSTATIC=true to force)"
|
||||
fi
|
||||
|
||||
# Ensure nginx configuration is valid
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Validating Nginx configuration..."
|
||||
nginx -t
|
||||
|
||||
# Clean up any stale supervisor sockets and pid files
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Cleaning up stale supervisor files..."
|
||||
rm -f /tmp/bookwyrm-web-supervisor.sock
|
||||
rm -f /tmp/supervisord-web.pid
|
||||
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] BookWyrm web container initialization completed"
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting web services..."
|
||||
|
||||
# Execute the provided command (usually supervisord)
|
||||
exec "$@"
|
||||
123
build/bookwyrm/bookwyrm-web/nginx.conf
Normal file
123
build/bookwyrm/bookwyrm-web/nginx.conf
Normal file
@@ -0,0 +1,123 @@
|
||||
# BookWyrm Nginx Configuration
|
||||
# Optimized for Kubernetes deployment with internal service routing
|
||||
|
||||
# No user directive needed for non-root containers
|
||||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Basic Settings
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 10M; # Match official BookWyrm config
|
||||
|
||||
# Use /tmp for nginx temporary directories (non-root container)
|
||||
client_body_temp_path /tmp/nginx_client_temp;
|
||||
proxy_temp_path /tmp/nginx_proxy_temp;
|
||||
fastcgi_temp_path /tmp/nginx_fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/nginx_uwsgi_temp;
|
||||
scgi_temp_path /tmp/nginx_scgi_temp;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# BookWyrm-specific caching configuration
|
||||
proxy_cache_path /tmp/nginx_cache keys_zone=bookwyrm_cache:20m loader_threshold=400 loader_files=400 max_size=400m;
|
||||
proxy_cache_key $scheme$proxy_host$uri$is_args$args$http_accept;
|
||||
|
||||
# Logging - Send to stdout/stderr for Kubernetes
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /dev/stdout main;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
# Gzip Settings
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
application/activity+json
|
||||
application/ld+json
|
||||
image/svg+xml;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Health check endpoint
|
||||
location /health/ {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# ActivityPub and federation endpoints
|
||||
location ~ ^/(inbox|user/.*/inbox|api|\.well-known) {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
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 https; # Force HTTPS scheme
|
||||
|
||||
# Increase timeouts for federation/API processing
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Main application (simplified - no aggressive caching for user content)
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
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 https; # Force HTTPS scheme
|
||||
|
||||
# Standard timeouts
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
# WebSocket support for real-time features
|
||||
location /ws/ {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
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 https;
|
||||
|
||||
# WebSocket timeouts
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
build/bookwyrm/bookwyrm-web/supervisord-web.conf
Normal file
45
build/bookwyrm/bookwyrm-web/supervisord-web.conf
Normal file
@@ -0,0 +1,45 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/dev/stdout
|
||||
logfile_maxbytes=0
|
||||
pidfile=/tmp/supervisord-web.pid
|
||||
silent=false
|
||||
|
||||
[unix_http_server]
|
||||
file=/tmp/bookwyrm-web-supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/bookwyrm-web-supervisor.sock
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
# Nginx web server
|
||||
[program:nginx]
|
||||
command=nginx -g 'daemon off;'
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=5
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
# BookWyrm Django application via Gunicorn
|
||||
[program:bookwyrm-web]
|
||||
command=gunicorn --bind 127.0.0.1:8000 --workers 4 --worker-class sync --timeout 120 --max-requests 1000 --max-requests-jitter 100 --access-logfile - --error-logfile - --log-level info bookwyrm.wsgi:application
|
||||
directory=/app
|
||||
user=bookwyrm
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=10
|
||||
startretries=3
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
environment=PATH="/opt/venv/bin:/usr/local/bin:/usr/bin:/bin",CONTAINER_TYPE="web"
|
||||
|
||||
# Log rotation no longer needed since logs go to stdout/stderr
|
||||
# Kubernetes handles log rotation automatically
|
||||
37
build/bookwyrm/bookwyrm-worker/Dockerfile
Normal file
37
build/bookwyrm/bookwyrm-worker/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
# BookWyrm Worker Container - Production Optimized
|
||||
# Celery background task processor
|
||||
|
||||
FROM bookwyrm-base AS bookwyrm-worker
|
||||
|
||||
# Switch to root for system package installation
|
||||
USER root
|
||||
|
||||
# Install only supervisor for worker management
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
supervisor \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
# Install Celery in virtual environment
|
||||
RUN /opt/venv/bin/pip install --no-cache-dir celery[redis]
|
||||
|
||||
# Copy worker-specific configuration
|
||||
COPY supervisord-worker.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY entrypoint-worker.sh /entrypoint.sh
|
||||
|
||||
# Set permissions efficiently
|
||||
RUN chmod +x /entrypoint.sh \
|
||||
&& mkdir -p /var/log/supervisor /var/log/celery \
|
||||
&& chown -R bookwyrm:bookwyrm /var/log/celery \
|
||||
&& chown -R bookwyrm:bookwyrm /app
|
||||
|
||||
# Health check for worker
|
||||
HEALTHCHECK --interval=60s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD /opt/venv/bin/celery -A celerywyrm inspect ping -d celery@$HOSTNAME || exit 1
|
||||
|
||||
# Run as root to manage celery via supervisor
|
||||
USER root
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
42
build/bookwyrm/bookwyrm-worker/entrypoint-worker.sh
Normal file
42
build/bookwyrm/bookwyrm-worker/entrypoint-worker.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# BookWyrm Worker Container Entrypoint
|
||||
# Simplified - init containers handle Redis readiness
|
||||
|
||||
set -e
|
||||
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting BookWyrm Worker Container..."
|
||||
|
||||
# Only handle worker-specific tasks (Redis handled by init container)
|
||||
|
||||
# Create temp directory for worker processes
|
||||
mkdir -p /tmp/bookwyrm
|
||||
chown bookwyrm:bookwyrm /tmp/bookwyrm
|
||||
|
||||
# Clean up any stale supervisor sockets and pid files
|
||||
rm -f /tmp/bookwyrm-supervisor.sock
|
||||
rm -f /tmp/supervisord-worker.pid
|
||||
|
||||
# Test Celery connectivity (quick verification)
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Testing Celery broker connectivity..."
|
||||
python -c "
|
||||
from celery import Celery
|
||||
import os
|
||||
|
||||
app = Celery('bookwyrm')
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
|
||||
try:
|
||||
# Test broker connection
|
||||
with app.connection() as conn:
|
||||
conn.ensure_connection(max_retries=3)
|
||||
print('✓ Celery broker connection successful')
|
||||
except Exception as e:
|
||||
print(f'✗ Celery broker connection failed: {e}')
|
||||
exit(1)
|
||||
"
|
||||
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] BookWyrm worker container initialization completed"
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting worker services..."
|
||||
|
||||
# Execute the provided command (usually supervisord)
|
||||
exec "$@"
|
||||
53
build/bookwyrm/bookwyrm-worker/supervisord-worker.conf
Normal file
53
build/bookwyrm/bookwyrm-worker/supervisord-worker.conf
Normal file
@@ -0,0 +1,53 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/dev/stdout
|
||||
logfile_maxbytes=0
|
||||
pidfile=/tmp/supervisord-worker.pid
|
||||
silent=false
|
||||
|
||||
[unix_http_server]
|
||||
file=/tmp/bookwyrm-supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/bookwyrm-supervisor.sock
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
# Celery Worker - General background tasks
|
||||
[program:celery-worker]
|
||||
command=celery -A celerywyrm worker --loglevel=info --concurrency=2 --queues=high_priority,medium_priority,low_priority,streams,images,suggested_users,email,connectors,lists,inbox,imports,import_triggered,broadcast,misc
|
||||
directory=/app
|
||||
user=bookwyrm
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=10
|
||||
startretries=3
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
environment=CONTAINER_TYPE="worker"
|
||||
|
||||
# Celery Beat - Moved to separate deployment (deployment-beat.yaml)
|
||||
# This eliminates port conflicts and allows proper scaling of workers
|
||||
# while maintaining single beat scheduler instance
|
||||
|
||||
# Celery Flower - Task monitoring (disabled by default, no external access needed)
|
||||
# [program:celery-flower]
|
||||
# command=celery -A celerywyrm flower --port=5555 --address=0.0.0.0
|
||||
# directory=/app
|
||||
# user=bookwyrm
|
||||
# autostart=false
|
||||
# autorestart=true
|
||||
# startsecs=10
|
||||
# startretries=3
|
||||
# stdout_logfile=/dev/stdout
|
||||
# stdout_logfile_maxbytes=0
|
||||
# stderr_logfile=/dev/stderr
|
||||
# stderr_logfile_maxbytes=0
|
||||
# environment=PATH="/app/venv/bin",CONTAINER_TYPE="worker"
|
||||
|
||||
# Log rotation no longer needed since logs go to stdout/stderr
|
||||
# Kubernetes handles log rotation automatically
|
||||
125
build/bookwyrm/build.sh
Executable file
125
build/bookwyrm/build.sh
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 Building Production-Optimized BookWyrm Containers..."
|
||||
echo "Optimized build targeting ~400MB final image size"
|
||||
|
||||
# Exit on any error
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${GREEN}✓${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗${NC} $1"
|
||||
}
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
print_error "Docker is not running. Please start Docker and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building optimized containers for ARM64 architecture..."
|
||||
echo "This will build:"
|
||||
echo -e " • ${YELLOW}bookwyrm-base${NC} - Shared base image (~400MB)"
|
||||
echo -e " • ${YELLOW}bookwyrm-web${NC} - Web server (Nginx + Django/Gunicorn, ~450MB)"
|
||||
echo -e " • ${YELLOW}bookwyrm-worker${NC} - Background workers (Celery + Beat, ~450MB)"
|
||||
echo ""
|
||||
|
||||
# Step 1: Build optimized base image
|
||||
echo "Step 1/3: Building optimized base image..."
|
||||
cd bookwyrm-base
|
||||
if docker build --platform linux/arm64 -t bookwyrm-base:latest .; then
|
||||
print_status "Base image built successfully!"
|
||||
else
|
||||
print_error "Failed to build base image"
|
||||
exit 1
|
||||
fi
|
||||
cd ..
|
||||
|
||||
# Step 2: Build optimized web container
|
||||
echo ""
|
||||
echo "Step 2/3: Building optimized web container..."
|
||||
cd bookwyrm-web
|
||||
if docker build --platform linux/arm64 -t <YOUR_REGISTRY_URL>/library/bookwyrm-web:latest .; then
|
||||
print_status "Web container built successfully!"
|
||||
else
|
||||
print_error "Failed to build web container"
|
||||
exit 1
|
||||
fi
|
||||
cd ..
|
||||
|
||||
# Step 3: Build optimized worker container
|
||||
echo ""
|
||||
echo "Step 3/3: Building optimized worker container..."
|
||||
cd bookwyrm-worker
|
||||
if docker build --platform linux/arm64 -t <YOUR_REGISTRY_URL>/library/bookwyrm-worker:latest .; then
|
||||
print_status "Worker container built successfully!"
|
||||
else
|
||||
print_error "Failed to build worker container"
|
||||
exit 1
|
||||
fi
|
||||
cd ..
|
||||
|
||||
echo ""
|
||||
echo "🎉 All containers built successfully!"
|
||||
|
||||
# Show image sizes
|
||||
echo ""
|
||||
echo "📊 Built image sizes:"
|
||||
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -E "(bookwyrm-base|bookwyrm-web|bookwyrm-worker)" | grep -v optimized
|
||||
|
||||
echo ""
|
||||
echo "Built containers:"
|
||||
echo " • <YOUR_REGISTRY_URL>/library/bookwyrm-web:latest"
|
||||
echo " • <YOUR_REGISTRY_URL>/library/bookwyrm-worker:latest"
|
||||
|
||||
# Ask if user wants to push
|
||||
echo ""
|
||||
read -p "Push containers to Harbor registry? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo ""
|
||||
echo "🚀 Pushing containers to registry..."
|
||||
|
||||
# Login check
|
||||
if ! docker info 2>/dev/null | grep -q "<YOUR_REGISTRY_URL>"; then
|
||||
print_warning "You may need to login to Harbor registry first:"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Pushing web container..."
|
||||
if docker push <YOUR_REGISTRY_URL>/library/bookwyrm-web:latest; then
|
||||
print_status "Web container pushed successfully!"
|
||||
else
|
||||
print_error "Failed to push web container"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Pushing worker container..."
|
||||
if docker push <YOUR_REGISTRY_URL>/library/bookwyrm-worker:latest; then
|
||||
print_status "Worker container pushed successfully!"
|
||||
else
|
||||
print_error "Failed to push worker container"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_status "All containers pushed to Harbor registry!"
|
||||
else
|
||||
echo "Skipping push. You can push later with:"
|
||||
echo " docker push <YOUR_REGISTRY_URL>/library/bookwyrm-web:latest"
|
||||
echo " docker push <YOUR_REGISTRY_URL>/library/bookwyrm-worker:latest"
|
||||
fi
|
||||
Reference in New Issue
Block a user