9.1 The dev image installs every group

Read the tutorial. Build it yourself is the other way to read this part.

This walk goes through rahuldave/cheesecracker on GitHub. This part starts from the code at step-08. The code before this part

To look at this code on your machine, run these commands. The first one makes a clone, if this folder has none:

[ -d cheesecracker ] || git clone https://github.com/rahuldave/cheesecracker
cd cheesecracker
git fetch --quiet --tags --force origin
git switch --detach step-08
just setup

The whole tutorial then adds the system tests, and the recipe just test-system. The dev image is for working on the project, so it installs every group.

9.1 the dev image, to work on the project in Linux

The dev image is a fourth stage of the Dockerfile, dev. It takes uv from the stage uv, and nothing from the run image.

± See the change to Dockerfile

The stage dev installs git and curl, copies uv, and installs just as a package of PyPI. It installs every group of uv.lock into /opt/venv, copies the project into /work, and starts a shell. /opt/venv is outside /work, so a .venv of this machine in a mounted folder is never used.

docker build --target dev --tag cheesecracker-dev .

Near the end, the line naming to docker.io/library/cheesecracker-dev names the image.

docker image ls cheesecracker-dev

The image is about 353 MB, twice the run image, because it has every tool.

What changed

  • Dockerfile: the stage dev, and its lines in the comment at the top. 26 lines added. The file
    • look at FROM python:3.12-slim-bookworm AS dev

The diff of Dockerfile
@@ -2,6 +2,8 @@
 #
 #   docker build --target run --tag cheesecracker-run .
 #       the production image: Python, the dependencies of the server and its code. It starts the server
+#   docker build --target dev --tag cheesecracker-dev .
+#       the development image: every dependency group, uv, just and git. It starts a shell
 #
 # The environment lives in /opt/venv, never in the project folder.
 
@@ -32,3 +34,27 @@ USER app
 EXPOSE 9000
 # Four workers, and no restart on a change: the server as it runs in production
 CMD ["uvicorn", "api.service:app", "--host", "0.0.0.0", "--port", "9000", "--workers", "4"]
+
+# The dev image: the whole project with every dependency group, and uv, just and git to work in it
+FROM python:3.12-slim-bookworm AS dev
+# hadolint ignore=DL3008
+RUN apt-get update \
+    && apt-get install --yes --no-install-recommends ca-certificates curl git \
+    && rm -rf /var/lib/apt/lists/*
+COPY --from=uv /uv /uvx /usr/local/bin/
+ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
+    UV_PYTHON_DOWNLOADS=never \
+    UV_LINK_MODE=copy \
+    UV_NO_CACHE=1 \
+    UV_TOOL_BIN_DIR=/usr/local/bin \
+    PATH=/opt/venv/bin:$PATH \
+    PYTHONUNBUFFERED=1
+# just, as a wheel from PyPI. git refuses a folder that another user owns, and a mounted folder
+# belongs to the user of the host, so every folder is safe
+RUN uv tool install "rust-just==1.50.0" \
+    && git config --system --add safe.directory '*'
+WORKDIR /work
+COPY pyproject.toml uv.lock .python-version ./
+RUN uv sync --locked
+COPY . .
+CMD ["bash"]

This change on GitHub

This part ends at the code at ccf62d330f28, partway through step-09. The code after this part