Over the last few months, I have worked extensively on several Wagtail projects. Off the back of this, I have decided to pivot from focusing on WordPress development in favour of Django and Wagtail. A big consideration that has come with this decision is managing the deployment of my projects. As a big Docker advocate, I decided to put together an optimised image for my workflow.

The Docker Image for Wagtail, Poetry and Node

This image supports:

  • Python – you can use any version you like that is tagged up in Dockerhub.
  • Poetry
  • Node/NPM
# Python build stage for dependencies via Poetry
FROM python:3.13-slim AS pythonbuilder

RUN pip install poetry

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

WORKDIR /app

COPY pyproject.toml poetry.lock ./
RUN touch README.md

RUN poetry install --without dev --no-root && rm -rf $POETRY_CACHE_DIR

# Node build stage for static assets
FROM node:20-slim AS nodebuilder

WORKDIR /app

COPY . .

RUN npm install

RUN npm run build

# Final runtime stage
FROM python:3.13-slim AS runtime

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

COPY --from=pythonbuilder ${VIRTUAL_ENV} ${VIRTUAL_ENV}

WORKDIR /app

COPY . .

# This is copying the files that I build with the npm run build command.
# You'll need to update these paths to suite your project.
COPY --from=nodebuilder /app/website/static ./website/static

RUN python manage.py collectstatic --noinput

EXPOSE 8000

ENTRYPOINT [ "sh", "entrypoint.sh" ]

How It Works

The image utilises 3 stages:

  • pythonbuilder
  • nodebuilder
  • runtime

The Python build stage installs Poetry uses it to install the required packages. The Node build stage does the same for NPM, but then also runs npm run build to build the assets required for the site. Finally, the runtime stage then copies the packages from the Python build stage (minus Poetry and its dependencies) and copies the built assets from the Node build stage.

By utilising a multi-stage build, the final image size is really small, as it doesn’t include Poetry or Node and its dependencies. Beyond image size, this is also great for security, as we don’t have to be concerned with recent Node package exploits since it doesn’t exist in the final container, which runs in production.

Leave a Reply

Your email address will not be published. Required fields are marked *