From d1e2b95678e77c5884a9474a44e39ba15e91c1fd Mon Sep 17 00:00:00 2001 From: ske087 Date: Sat, 9 Aug 2025 16:40:49 +0300 Subject: [PATCH] Implement data persistence for safe app updates - Add external volume mounting for database, uploads, and media files - Update Dockerfile to conditionally initialize database only if it doesn't exist - Move database to external /data volume for persistence across rebuilds - Configure production environment with proper FLASK_CONFIG - Add volume mappings for complete data persistence: * ./data:/data - Database persistence * ./uploads:/opt/moto_site/uploads - File uploads persistence * ./static/media:/opt/moto_site/static/media - Media files persistence - Create init script that skips database creation if DB already exists - Enable safe app updates without losing users, posts, or tracks This ensures all user data persists across Docker container rebuilds and app updates. --- Dockerfile | 19 +++++++++++++++---- docker-compose.yml | 8 +++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index a1c4b91..cca5aa2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,15 +23,26 @@ RUN mkdir -p uploads/images uploads/gpx # Set FLASK_APP so Flask CLI commands are available ENV FLASK_APP=run.py -# Initialize the database and create admin at build time (as root, before switching user) -RUN flask --app run.py init-db && flask --app run.py create-admin +# Create a script to conditionally initialize database +RUN echo '#!/bin/sh\n\ +if [ ! -f /data/moto_adventure.db ]; then\n\ + echo "Database not found, initializing..."\n\ + flask --app run.py init-db\n\ + flask --app run.py create-admin\n\ + echo "Database initialized successfully"\n\ +else\n\ + echo "Database already exists, skipping initialization"\n\ +fi' > /opt/moto_site/init_db_if_needed.sh && chmod +x /opt/moto_site/init_db_if_needed.sh # Create non-root user and set permissions -RUN adduser --disabled-password --gecos '' appuser && chown -R appuser:appuser /opt/moto_site +RUN adduser --disabled-password --gecos '' appuser && \ + chown -R appuser:appuser /opt/moto_site && \ + mkdir -p /data && \ + chown -R appuser:appuser /data USER appuser # Expose port EXPOSE 5000 # Run the application with Gunicorn, looking for run:app in /opt/moto_site -ENTRYPOINT ["/bin/sh", "-c", "exec gunicorn --bind 0.0.0.0:5000 run:app"] +ENTRYPOINT ["/bin/sh", "-c", "/opt/moto_site/init_db_if_needed.sh && exec gunicorn --bind 0.0.0.0:5000 run:app"] diff --git a/docker-compose.yml b/docker-compose.yml index 247c3d7..b78ff3d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,10 +8,12 @@ services: ports: - "8100:5000" environment: - - FLASK_ENV=production - - DATABASE_URL=sqlite:///moto_adventure.db + - FLASK_CONFIG=production + - DATABASE_URL=sqlite:////data/moto_adventure.db - SECRET_KEY=ana_are_mere_si-si-pere_cat-cuprinde_in_cos working_dir: /opt/moto_site volumes: - - ./uploads:/opt/moto_site/uploads + - ./data:/data # Database persistence + - ./uploads:/opt/moto_site/uploads # File uploads persistence + - ./static/media:/opt/moto_site/static/media # Media files persistence restart: unless-stopped