Compare commits
6 Commits
918fc91604
...
docker-ref
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7deeb681c0 | ||
|
|
8814dd8994 | ||
|
|
02247340d4 | ||
|
|
f3c14d649c | ||
|
|
b71187009b | ||
|
|
77cea8cbc5 |
@@ -1,46 +1,44 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Database files (will be mounted as volume)
|
||||||
|
*.db
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
# Git
|
# Git
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
||||||
# Python
|
# IDE files
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
*.so
|
|
||||||
.Python
|
|
||||||
env/
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
|
|
||||||
# Virtual Environment
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.idea/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
# Database
|
# Logs
|
||||||
*.db
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
# Uploads
|
# Development files
|
||||||
static/uploads/*
|
.env
|
||||||
!static/uploads/.gitkeep
|
.env.local
|
||||||
|
|
||||||
# Docker
|
# Cache directories
|
||||||
Dockerfile
|
.cache/
|
||||||
.dockerignore
|
|
||||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -8,3 +8,16 @@ wheels/
|
|||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db
|
||||||
|
pet_pictures.db
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
10
Dockerfile
10
Dockerfile
@@ -15,11 +15,13 @@ RUN pip install uv
|
|||||||
# Copy project files
|
# Copy project files
|
||||||
COPY pyproject.toml .
|
COPY pyproject.toml .
|
||||||
COPY main.py .
|
COPY main.py .
|
||||||
COPY templates/ templates/
|
COPY app/ app/
|
||||||
|
COPY migrate_session_changes.py .
|
||||||
|
COPY README_MIGRATION.md .
|
||||||
COPY README.md .
|
COPY README.md .
|
||||||
|
|
||||||
# Create uploads directory
|
# Create uploads directory in the correct location
|
||||||
RUN mkdir -p static/uploads
|
RUN mkdir -p app/static/uploads
|
||||||
|
|
||||||
# Create and activate virtual environment, then install dependencies
|
# Create and activate virtual environment, then install dependencies
|
||||||
RUN uv venv && \
|
RUN uv venv && \
|
||||||
@@ -30,7 +32,7 @@ RUN uv venv && \
|
|||||||
ENV FLASK_APP=main.py
|
ENV FLASK_APP=main.py
|
||||||
ENV FLASK_ENV=production
|
ENV FLASK_ENV=production
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
ENV GUNICORN_CMD_ARGS="--workers=4 --bind=0.0.0.0:5000 --timeout=120"
|
ENV GUNICORN_CMD_ARGS="--workers=1 --bind=0.0.0.0:5000 --timeout=120"
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|||||||
160
README_DOCKER.md
Normal file
160
README_DOCKER.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# Docker Setup for Pets of Powerwashing
|
||||||
|
|
||||||
|
## Updated for Refactored Architecture
|
||||||
|
|
||||||
|
The Docker setup has been updated to work with the refactored Flask application structure.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Build and Run
|
||||||
|
```bash
|
||||||
|
# Build and start the application
|
||||||
|
docker compose up --build
|
||||||
|
|
||||||
|
# Or run in detached mode
|
||||||
|
docker compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Run Database Migration
|
||||||
|
```bash
|
||||||
|
# Run the migration (first time setup or after schema changes)
|
||||||
|
docker compose --profile migrate up migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Access the Application
|
||||||
|
- **Web Interface**: http://localhost:54321
|
||||||
|
- **Admin Login**: username: `admin`, password: `password123`
|
||||||
|
|
||||||
|
## File Structure Changes
|
||||||
|
|
||||||
|
The refactored application now uses this structure:
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
├── static/uploads/ # Upload directory (mounted as volume)
|
||||||
|
├── templates/ # HTML templates
|
||||||
|
├── models/ # Database models
|
||||||
|
├── routes/ # Route handlers (blueprints)
|
||||||
|
├── utils/ # Utilities and helpers
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
You can customize the application through environment variables:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
# Flask settings
|
||||||
|
- FLASK_ENV=production
|
||||||
|
|
||||||
|
# Application settings
|
||||||
|
- UPLOAD_FOLDER=app/static/uploads
|
||||||
|
- DATABASE_PATH=pet_pictures.db
|
||||||
|
- ADMIN_USERNAME=admin
|
||||||
|
- ADMIN_PASSWORD=password123
|
||||||
|
|
||||||
|
# Optional: Override secret key for production
|
||||||
|
- SECRET_KEY=your-secret-key-here
|
||||||
|
```
|
||||||
|
|
||||||
|
### Volume Mounts
|
||||||
|
|
||||||
|
- `./app/static/uploads:/app/app/static/uploads` - Persistent file uploads
|
||||||
|
- `./pet_pictures.db:/app/pet_pictures.db` - Persistent database
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
### Web Service (`web`)
|
||||||
|
- **Port**: 54321 (maps to internal port 5000)
|
||||||
|
- **Process**: Gunicorn with 4 workers
|
||||||
|
- **Health Check**: HTTP check every 30 seconds
|
||||||
|
- **Restart Policy**: unless-stopped
|
||||||
|
|
||||||
|
### Migration Service (`migrate`)
|
||||||
|
- **Purpose**: Database schema updates
|
||||||
|
- **Usage**: `docker compose --profile migrate up migrate`
|
||||||
|
- **Script**: Uses `migrate_session_changes.py`
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Development
|
||||||
|
```bash
|
||||||
|
# Build only
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Stop services
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Remove everything including volumes
|
||||||
|
docker compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production
|
||||||
|
```bash
|
||||||
|
# Start in production mode
|
||||||
|
FLASK_ENV=production docker compose up -d
|
||||||
|
|
||||||
|
# Update and restart
|
||||||
|
docker compose pull
|
||||||
|
docker compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**1. Permission Issues with Uploads**
|
||||||
|
```bash
|
||||||
|
# Fix upload directory permissions
|
||||||
|
sudo chown -R 1000:1000 ./app/static/uploads
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Database Migration Fails**
|
||||||
|
```bash
|
||||||
|
# Run migration manually
|
||||||
|
docker compose exec web python migrate_session_changes.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Build Fails**
|
||||||
|
```bash
|
||||||
|
# Clean build
|
||||||
|
docker compose build --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
The application includes a health check that:
|
||||||
|
- Tests HTTP connectivity on port 5000
|
||||||
|
- Retries 3 times with 5-second delays
|
||||||
|
- Runs every 30 seconds
|
||||||
|
- Allows 40 seconds for startup
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
**For Production:**
|
||||||
|
1. Change default admin credentials via environment variables
|
||||||
|
2. Set a secure `SECRET_KEY`
|
||||||
|
3. Use HTTPS reverse proxy (nginx/traefik)
|
||||||
|
4. Limit file upload sizes
|
||||||
|
5. Regular database backups
|
||||||
|
|
||||||
|
## File Locations in Container
|
||||||
|
|
||||||
|
- **Application**: `/app/`
|
||||||
|
- **Database**: `/app/pet_pictures.db`
|
||||||
|
- **Uploads**: `/app/app/static/uploads/`
|
||||||
|
- **Logs**: `/app/logs/` (if logging enabled)
|
||||||
|
|
||||||
|
## Changes from Previous Version
|
||||||
|
|
||||||
|
✅ **Updated paths** for refactored app structure
|
||||||
|
✅ **New migration script** (`migrate_session_changes.py`)
|
||||||
|
✅ **Added environment variables** for configuration
|
||||||
|
✅ **Improved .dockerignore** for smaller builds
|
||||||
|
✅ **Removed obsolete version** from docker-compose.yml
|
||||||
|
✅ **Better volume mapping** for uploads directory
|
||||||
@@ -15,7 +15,10 @@ def create_app():
|
|||||||
app.config.from_object(Config)
|
app.config.from_object(Config)
|
||||||
|
|
||||||
# Ensure upload directory exists
|
# Ensure upload directory exists
|
||||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
upload_path = os.path.join(app.static_folder, 'uploads')
|
||||||
|
os.makedirs(upload_path, exist_ok=True)
|
||||||
|
# Update config to use absolute path for file operations
|
||||||
|
app.config['UPLOAD_FOLDER'] = upload_path
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
from app.utils.logging_config import setup_logging
|
from app.utils.logging_config import setup_logging
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ class Config:
|
|||||||
# Flask settings
|
# Flask settings
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') or os.urandom(24)
|
SECRET_KEY = os.environ.get('SECRET_KEY') or os.urandom(24)
|
||||||
|
|
||||||
# Upload settings
|
# Upload settings
|
||||||
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER') or 'app/static/uploads'
|
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER') or 'static/uploads'
|
||||||
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB max file size
|
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB max file size
|
||||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
version: "3.8"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "54321:5000"
|
- "54321:5000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./static/uploads:/app/static/uploads
|
- ./app/static/uploads:/app/app/static/uploads
|
||||||
- ./pet_pictures.db:/app/pet_pictures.db
|
- ./pet_pictures.db:/app/pet_pictures.db
|
||||||
environment:
|
environment:
|
||||||
- FLASK_APP=main.py
|
- FLASK_APP=main.py
|
||||||
- FLASK_ENV=production
|
- FLASK_ENV=production
|
||||||
- GUNICORN_CMD_ARGS=--workers=4 --bind=0.0.0.0:5000 --timeout=120 --keep-alive=5 --worker-class=sync --worker-connections=1000 --max-requests=1000 --max-requests-jitter=50
|
- GUNICORN_CMD_ARGS=--workers=1 --bind=0.0.0.0:5000 --timeout=120 --keep-alive=5 --worker-class=sync --worker-connections=1000 --max-requests=1000 --max-requests-jitter=50
|
||||||
|
# Application configuration
|
||||||
|
- UPLOAD_FOLDER=app/static/uploads
|
||||||
|
- DATABASE_PATH=pet_pictures.db
|
||||||
|
- ADMIN_USERNAME=admin
|
||||||
|
- ADMIN_PASSWORD=password123
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
@@ -36,6 +39,6 @@ services:
|
|||||||
build: .
|
build: .
|
||||||
volumes:
|
volumes:
|
||||||
- ./pet_pictures.db:/app/pet_pictures.db
|
- ./pet_pictures.db:/app/pet_pictures.db
|
||||||
command: python migrate.py
|
command: python migrate_session_changes.py
|
||||||
profiles:
|
profiles:
|
||||||
- migrate
|
- migrate
|
||||||
|
|||||||
3
main.py
3
main.py
@@ -15,4 +15,5 @@ app = create_app()
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Development server configuration
|
# Development server configuration
|
||||||
debug_mode = os.environ.get('FLASK_ENV') == 'development'
|
debug_mode = os.environ.get('FLASK_ENV') == 'development'
|
||||||
app.run(debug=debug_mode, host='0.0.0.0', port=5000)
|
port = int(os.environ.get('PORT', 5001)) # Use port 5001 to avoid AirPlay conflict
|
||||||
|
app.run(debug=debug_mode, host='0.0.0.0', port=port)
|
||||||
|
|||||||
Reference in New Issue
Block a user