🐳 docker

This commit is contained in:
mi
2025-11-06 22:30:56 +10:00
parent 08bc888df0
commit a3f0132c7e
4 changed files with 162 additions and 8 deletions

42
.dockerignore Normal file
View File

@@ -0,0 +1,42 @@
# Git
.git
.gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
.venv
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Documentation
README.md
*.md
# Docker
Dockerfile
.dockerignore
docker-compose.yml
# Logs
*.log
# Testing
.pytest_cache/
.coverage
htmlcov/

47
Dockerfile Normal file
View File

@@ -0,0 +1,47 @@
# Production Dockerfile for Sunday Comics
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
# Copy requirements first for better caching
COPY --chown=appuser:appuser requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt gunicorn
# Copy application code
COPY --chown=appuser:appuser . .
# Switch to non-root user
USER appuser
# Expose port
EXPOSE 3000
# Environment variables
ENV PYTHONUNBUFFERED=1 \
PORT=3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:3000').read()"
# Run with Gunicorn
CMD gunicorn app:app \
--bind 0.0.0.0:${PORT} \
--workers 4 \
--threads 2 \
--worker-class gthread \
--access-logfile - \
--error-logfile - \
--log-level info

View File

@@ -17,6 +17,9 @@ sunday/
├── app.py # Main Flask application ├── app.py # Main Flask application
├── comics_data.py # Comic data (edit this to add comics) ├── comics_data.py # Comic data (edit this to add comics)
├── requirements.txt # Python dependencies ├── requirements.txt # Python dependencies
├── Dockerfile # Production Docker image
├── docker-compose.yml # Docker Compose configuration
├── .dockerignore # Docker build exclusions
├── scripts/ # Utility scripts ├── scripts/ # Utility scripts
│ ├── add_comic.py # Script to add new comic entries │ ├── add_comic.py # Script to add new comic entries
│ └── generate_rss.py # Script to generate RSS feed │ └── generate_rss.py # Script to generate RSS feed
@@ -108,15 +111,54 @@ This creates/updates `static/feed.rss`
## Production Deployment ## Production Deployment
For production, you should **NOT** use Flask's built-in development server. Instead: For production, you should **NOT** use Flask's built-in development server. Choose one of the following deployment methods:
### 1. Generate a Secure Secret Key ### Option 1: Docker (Recommended)
**1. Generate a secure secret key:**
```bash
python -c "import secrets; print(secrets.token_hex(32))"
```
**2. Create a `.env` file:**
```bash
SECRET_KEY=your-generated-secret-key-here
```
**3. Build and run with Docker Compose:**
```bash
docker-compose up -d
```
**Or build and run manually:**
```bash
# Build the image
docker build -t sunday-comics .
# Run the container
docker run -d \
-p 3000:3000 \
-e SECRET_KEY="your-secret-key" \
-v $(pwd)/comics_data.py:/app/comics_data.py:ro \
-v $(pwd)/static/images:/app/static/images:ro \
--name sunday-comics \
sunday-comics
```
**View logs:**
```bash
docker-compose logs -f
```
### Option 2: Manual Deployment with Gunicorn
**1. Generate a Secure Secret Key**
```bash ```bash
python -c "import secrets; print(secrets.token_hex(32))" python -c "import secrets; print(secrets.token_hex(32))"
``` ```
### 2. Set Environment Variables **2. Set Environment Variables**
```bash ```bash
export SECRET_KEY="generated-secret-key-from-above" export SECRET_KEY="generated-secret-key-from-above"
@@ -124,7 +166,7 @@ export DEBUG=False
export PORT=3000 export PORT=3000
``` ```
### 3. Use a Production WSGI Server **3. Use a Production WSGI Server**
**Install Gunicorn:** **Install Gunicorn:**
```bash ```bash
@@ -136,17 +178,17 @@ pip install gunicorn
gunicorn app:app --bind 0.0.0.0:3000 --workers 4 gunicorn app:app --bind 0.0.0.0:3000 --workers 4
``` ```
### 4. Use a Reverse Proxy (Recommended) ### Using a Reverse Proxy (Recommended)
Set up Nginx or another reverse proxy in front of Gunicorn for: Set up Nginx or another reverse proxy in front of your app for:
- HTTPS/SSL termination - HTTPS/SSL termination
- Static file serving - Static file serving
- Load balancing - Load balancing
- Better security - Better security
### 5. Additional Production Considerations ### Additional Production Considerations
- Use a process manager (systemd, supervisor) - Use a process manager (systemd, supervisor) for non-Docker deployments
- Set appropriate file permissions - Set appropriate file permissions
- Enable HTTPS with Let's Encrypt - Enable HTTPS with Let's Encrypt
- Consider using a CDN for static assets - Consider using a CDN for static assets

23
docker-compose.yml Normal file
View File

@@ -0,0 +1,23 @@
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- SECRET_KEY=${SECRET_KEY:-please-change-this-secret-key}
- PORT=3000
- DEBUG=False
volumes:
# Mount comics data for easy updates without rebuilding
- ./comics_data.py:/app/comics_data.py:ro
- ./static/images:/app/static/images:ro
- ./static/feed.rss:/app/static/feed.rss:ro
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3000').read()"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s