FROM python:3.14-slim # All subsequent commands run from here inside the container. WORKDIR /app # Copy ONLY requirements.txt first, not the whole app. Docker caches each # layer — as long as requirements.txt hasn't changed, this layer (and the # slow pip install below) gets reused on every rebuild, even if you've # edited your Python files. Copying everything first would bust that cache # on every single code change. COPY requirements.txt . RUN python -m pip install --no-cache-dir -r requirements.txt # Now copy the rest of the application code. RUN useradd --create-home --uid 10001 steady \ && mkdir -p /app/instance \ && chown -R steady:steady /app COPY --chown=steady:steady . . USER steady # Documents which port the app listens on. This does NOT actually publish # the port anywhere — that happens in compose.yaml via `expose`. EXPOSE 5000 # Production entrypoint. Never use `flask run` or `app.run()` in production — # that's Flask's single-threaded development server, not meant to handle # real traffic or run unattended. gunicorn is a proper WSGI server. # "wsgi:app" means: import the `app` object from wsgi.py. CMD ["gunicorn", "--config", "gunicorn.conf.py", "wsgi:app"]