7.2 The run image installs no group

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

This walk goes through rahuldave/cheesecracker on GitHub. This part starts from the code at 2a28a5c704d6, partway through step-07. The code before this part

This part does not start where the part before it ends, because the walk skips some changes. This command puts the files that this part starts from in place of yours. Run it, and then go on:

git restore --source f3ad230bf911 --staged -- :/ && git restore --source 2a28a5c704d6 --staged --worktree -- :/

If you start at this part, make your clone as Get the project says, and then run this command. It puts in your clone the files that this part starts from. A file that the project deleted before this part stays, so delete it if git check lists it:

git rm -rq --cached --ignore-unmatch -- :/ && git restore --source 2a28a5c704d6 --staged --worktree -- :/
just setup

The whole tutorial then writes the checks of pre-commit, and .dockerignore. The run image is the server as it runs in production. It needs the dependencies of the project, and no group.

7.2 the run image, the server as it runs in production

The run image needs Python, the dependencies of the server, and the code. It does not need uv, the tests, ruff or pre-commit. The Dockerfile builds the image in stages, and the run image takes only what the server needs.

Apply the patch to Dockerfile, from the top of the project:

curl -fsSL https://github.com/rahuldave/cheesecracker/commit/0acb4556f724cd94e4a71ab4fff739a974413fc0.diff | git apply --include=Dockerfile

Apply the patch, and read the three stages, which start at each FROM. Read the line RUN uv sync in the stage build, and the line COPY --from=build and the CMD in the stage run.

docker build --target run --tag cheesecracker-run .

Docker prints each line of the Dockerfile as it runs. Near the end, the line naming to docker.io/library/cheesecracker-run names the image.

docker image ls cheesecracker-run

The image is about 173 MB, nearly all of it Python and the dependencies of the server.

Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:

git check 0acb4556f724

If you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:

git restore --source 2a28a5c704d6 --staged -- :/ && git restore --source 0acb4556f724 --staged --worktree -- :/

What changed

  • Dockerfile: the stages uv, build and run. New, 34 lines. The file
    • look at RUN uv sync --locked --no-default-groups

The patch to Dockerfile
@@ -0,0 +1,34 @@
+# The images of the API server, built from uv.lock, so they hold the versions that the lockfile names.
+#
+#   docker build --target run --tag cheesecracker-run .
+#       the production image: Python, the dependencies of the server and its code. It starts the server
+#
+# The environment lives in /opt/venv, never in the project folder.
+
+# uv itself, copied from its own image
+FROM ghcr.io/astral-sh/uv:0.12.13 AS uv
+
+# The environment of the server, without the dependency groups: no tests, no ruff, no pre-commit
+FROM python:3.12-slim-bookworm AS build
+COPY --from=uv /uv /usr/local/bin/uv
+ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
+    UV_PYTHON_DOWNLOADS=never \
+    UV_COMPILE_BYTECODE=1 \
+    UV_LINK_MODE=copy \
+    UV_NO_CACHE=1
+WORKDIR /app
+COPY pyproject.toml uv.lock .python-version ./
+RUN uv sync --locked --no-default-groups
+
+# The run image: Python, the environment from the build stage, and the code. No uv, and no dev tools
+FROM python:3.12-slim-bookworm AS run
+RUN useradd --create-home --uid 1000 app
+COPY --from=build /opt/venv /opt/venv
+WORKDIR /app
+COPY src/api-service/api ./api
+ENV PATH=/opt/venv/bin:$PATH \
+    PYTHONUNBUFFERED=1
+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"]

This change on GitHub

This part ends at the code at 0acb4556f724, partway through step-07. The code after this part