Skip to content

Commit

Permalink
Docker file refactor (#1066)
Browse files Browse the repository at this point in the history
* refactor(Dockerfile): copy less files to node builder

This reduces the build time from 89s to 70s. Final runtime image is
unchanged.

* refactor(Dockerfile) move compilemessages to runtime image

compilemessages depends on the whole Django app, whereas the poetry
install doesn't, so moving this into the runtime image should simplify that
initial build stage and makes it more cachable.

This doesn't affect the overall build time without cache. The gettext
package adds about 8mb to the final image.

* refactor(Dockerfile) limit runtime image

This refactor simplifies the runtime image stage and limits
the files copied into the image.

This halves the image size from 505MB to 221MB, and reduces the build
time from 70s to 56s when cache is not used.

* minor comment changes
  • Loading branch information
MatMoore authored Nov 18, 2024
1 parent 1f90f07 commit 395a902
Showing 1 changed file with 45 additions and 34 deletions.
79 changes: 45 additions & 34 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,86 @@ ARG alpine_version=alpine3.20
ARG python_version=python:3.11
ARG node_version=node:23

# The node builder image, used to build the virtual environment
#### NODE.JS BUILD

FROM ${ecr_path}${node_version}-${alpine_version} AS node_builder
WORKDIR /app

# Install dependencies for npm install command
RUN apk add --no-cache bash

WORKDIR /app
COPY . .

# Compile static assets
COPY package.json package-lock.json ./
COPY scripts/import-static.sh ./scripts/import-static.sh
COPY static/assets/js ./static/assets/js
COPY scss ./scss
RUN npm install --omit=dev

# The builder image, used to build the virtual environment
FROM ${ecr_path}${python_version}-${alpine_version} AS python_builder

# Install dependencies for compiling .po files
RUN apk add --no-cache bash make gettext gcc musl-dev libffi-dev
#### PYTHON BUILD

FROM ${ecr_path}${python_version}-${alpine_version} AS python_builder
WORKDIR /app
COPY --from=node_builder /app .

# set environment variables
RUN apk add --no-cache gcc musl-dev libffi-dev

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Install poetry via pip
RUN pip install poetry==1.8.4

ENV POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_VIRTUALENVS_CREATE=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache

COPY pyproject.toml poetry.lock Makefile ./
# Install python dependencies to a virtualenv
COPY pyproject.toml poetry.lock ./
COPY lib ./lib
COPY locale ./

RUN pip install poetry==1.8.4
RUN poetry install --without dev --no-root && rm -rf $POETRY_CACHE_DIR
RUN make compilemessages

# The runtime image, used to just run the code provided its virtual environment
#### FINAL RUNTIME IMAGE

FROM ${ecr_path}${python_version}-${alpine_version} AS runtime

# Workaround for CVE-2024-6345 upgrade the installed version of setuptools to the latest version
RUN pip install -U setuptools

# Install dependencies for the runtime image
RUN apk add --no-cache bash make netcat-openbsd
RUN apk add --no-cache bash make netcat-openbsd gettext

# Use a non-root user
ENV CONTAINER_USER=appuser \
CONTAINER_GROUP=appuser \
CONTAINER_UID=31337 \
CONTAINER_GID=31337

RUN addgroup --gid ${CONTAINER_GID} --system ${CONTAINER_GROUP} \
&& adduser --uid ${CONTAINER_UID} --system ${CONTAINER_USER} --ingroup ${CONTAINER_GROUP}

USER ${CONTAINER_UID}
WORKDIR /app

ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"

# copy project and dependencies
COPY . .
COPY --from=python_builder /app/static ./static
COPY --from=python_builder /app/locale ./locale
COPY --from=python_builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
# Copy entrypoints
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} scripts/app-entrypoint.sh ./scripts/app-entrypoint.sh
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} manage.py ./

RUN chmod +x ./scripts/app-entrypoint.sh
# Copy compiled assets
COPY --from=node_builder --chown=${CONTAINER_USER}:${CONTAINER_GROUP} /app/static ./static
COPY --from=python_builder --chown=${CONTAINER_USER}:${CONTAINER_GROUP} ${VIRTUAL_ENV} ${VIRTUAL_ENV}
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} manage.py ./

RUN python manage.py collectstatic --noinput
# Copy application code
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} core ./core
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} users ./users
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} feedback ./feedback
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} home ./home
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} templates ./templates

# Use a non-root user
RUN addgroup --gid 31337 --system appuser \
&& adduser --uid 31337 --system appuser --ingroup appuser
RUN chown --recursive appuser:appuser /app

USER 31337
# Run django commands
RUN python manage.py collectstatic --noinput
RUN python manage.py compilemessages

EXPOSE 8000

Expand Down

0 comments on commit 395a902

Please sign in to comment.