From 57dc3700e7bcc289aa31c8d5f75c087f41082a18 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 15 Nov 2024 10:05:33 +0000 Subject: [PATCH 1/4] refactor(Dockerfile): copy less files to node builder This reduces the build time from 89s to 70s. Final runtime image is unchanged. --- Dockerfile | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 82359bbd..6db947bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,25 +3,29 @@ 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 # Install dependencies for npm install command RUN apk add --no-cache bash WORKDIR /app -COPY . . - +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 +#### PYTHON BUILD + 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 WORKDIR /app -COPY --from=node_builder /app . +COPY . . # set environment variables ENV PYTHONDONTWRITEBYTECODE=1 @@ -42,7 +46,8 @@ COPY locale ./ 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 @@ -58,7 +63,7 @@ ENV VIRTUAL_ENV=/app/.venv \ # copy project and dependencies COPY . . -COPY --from=python_builder /app/static ./static +COPY --from=node_builder /app/static ./static COPY --from=python_builder /app/locale ./locale COPY --from=python_builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} From f3660cfc76910e12e671908e8e09e4b987cf64be Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 15 Nov 2024 11:33:53 +0000 Subject: [PATCH 2/4] 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. --- Dockerfile | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6db947bc..9746a5aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,11 +6,12 @@ ARG node_version=node:23 #### 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 +# 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 @@ -20,31 +21,23 @@ RUN npm install --omit=dev #### PYTHON BUILD 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 - WORKDIR /app -COPY . . + +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 #### FINAL RUNTIME IMAGE @@ -54,7 +47,7 @@ FROM ${ecr_path}${python_version}-${alpine_version} AS runtime 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 WORKDIR /app @@ -64,12 +57,11 @@ ENV VIRTUAL_ENV=/app/.venv \ # copy project and dependencies COPY . . COPY --from=node_builder /app/static ./static -COPY --from=python_builder /app/locale ./locale COPY --from=python_builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} - RUN chmod +x ./scripts/app-entrypoint.sh RUN python manage.py collectstatic --noinput +RUN python manage.py compilemessages # Use a non-root user RUN addgroup --gid 31337 --system appuser \ From 80935cda2d52d78f360057834161679af9eeac45 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 15 Nov 2024 12:19:46 +0000 Subject: [PATCH 3/4] 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. --- Dockerfile | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9746a5aa..2c54879b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,26 +49,41 @@ RUN pip install -U setuptools # Install dependencies for the runtime image 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=node_builder /app/static ./static -COPY --from=python_builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} -RUN chmod +x ./scripts/app-entrypoint.sh +# 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 python manage.py collectstatic --noinput -RUN python manage.py compilemessages +# 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 ./ -# Use a non-root user -RUN addgroup --gid 31337 --system appuser \ - && adduser --uid 31337 --system appuser --ingroup appuser -RUN chown --recursive appuser:appuser /app +# 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 -USER 31337 +# Run django commands +RUN python manage.py collectstatic --noinput +RUN python manage.py compilemessages EXPOSE 8000 From 2673858d6d4de1ba474de6ffa010448e1f91c3cf Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 15 Nov 2024 12:37:25 +0000 Subject: [PATCH 4/4] minor comment changes --- Dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2c54879b..a19858b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ WORKDIR /app RUN apk add --no-cache gcc musl-dev libffi-dev -# set environment variables +# Set environment variables ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 ENV POETRY_NO_INTERACTION=1 \ @@ -59,17 +59,16 @@ 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 entrypoints +# Copy entrypoints COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} scripts/app-entrypoint.sh ./scripts/app-entrypoint.sh COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} manage.py ./ -# copy compiled assets +# 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 ./