31 lines
1.2 KiB
Docker
31 lines
1.2 KiB
Docker
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"]
|