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