Files
webmail-client/docker/Dockerfile.backend
T

81 lines
2.9 KiB
Docker
Raw Normal View History

# Production backend image: API, both worker roles, and the migration/admin CLI.
#
# One image, several commands (see docker/entrypoint.sh) — matches SPEC §6.3's
# WORKER_ROLE split. Build context is the REPO ROOT, because the image needs
# backend/ *and* plugins/ (the plugins are separate distributions that the
# loader discovers through the `webmail.plugins` entry-point group, SPEC §11).
#
# docker build -f docker/Dockerfile.backend -t webmail/backend .
# ---------- builder: resolve wheels into a self-contained venv ----------------
FROM python:3.11-slim AS builder
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_NO_CACHE_DIR=1 \
PYTHONDONTWRITEBYTECODE=1
# Only needed if a pinned dep has no manylinux wheel for this platform; the
# whole stage is discarded, so it costs nothing in the runtime image.
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Backend first: its dependency set is the slowest layer and changes least often.
COPY backend/pyproject.toml /src/backend/pyproject.toml
COPY backend/app /src/backend/app
COPY backend/workers /src/backend/workers
RUN pip install /src/backend
# Plugins are ordinary distributions installed on top (each owns its own deps).
COPY plugins /src/plugins
RUN pip install \
/src/plugins/webmail_plugin_calendar \
/src/plugins/webmail_plugin_contacts \
/src/plugins/webmail_plugin_labels \
/src/plugins/webmail_plugin_filters \
/src/plugins/webmail_plugin_antispam
# ---------- runtime -----------------------------------------------------------
FROM python:3.11-slim
ARG APP_VERSION=dev
ARG GIT_SHA=unknown
LABEL org.opencontainers.image.title="webmail-backend" \
org.opencontainers.image.version="${APP_VERSION}" \
org.opencontainers.image.revision="${GIT_SHA}"
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/opt/venv/bin:$PATH" \
APP_VERSION="${APP_VERSION}" \
GIT_SHA="${GIT_SHA}"
# tini reaps zombies and forwards SIGTERM, which the workers need for the <10 s
# graceful lease release in workers/run.py.
RUN apt-get update \
&& apt-get install -y --no-install-recommends tini \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --uid 10001 --create-home --home-dir /home/webmail webmail
COPY --from=builder /opt/venv /opt/venv
WORKDIR /app
# Alembic's core tree lives outside the installed package, so it is copied in.
COPY backend/alembic.ini ./alembic.ini
COPY backend/migrations ./migrations
COPY backend/scripts ./scripts
COPY docker/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint
# Blob store mount point (BLOB_ROOT). Ownership is set by the compose `init`
# service, which runs before anything else touches the bind mount.
RUN mkdir -p /data/blobs && chown webmail:webmail /data/blobs
VOLUME ["/data/blobs"]
USER webmail
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint"]
CMD ["api"]