Skip to content

Commit 1c593aa

Browse files
authored
Add a multistage Docker build example that uses the standalone builds (#15)
1 parent 39b5768 commit 1c593aa

File tree

4 files changed

+69
-1
lines changed

4 files changed

+69
-1
lines changed

.github/workflows/ci.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ jobs:
3939
cache-to: type=gha,mode=min,scope=uv-docker-example-multistage
4040
outputs: type=docker,dest=/tmp/uv-docker-example-multistage.tar
4141

42+
- name: Build and export (standalone)
43+
uses: docker/build-push-action@v6
44+
with:
45+
file: standalone.Dockerfile
46+
tags: uv-docker-example-standalone:latest
47+
cache-from: type=gha,scope=uv-docker-example-standalone
48+
cache-to: type=gha,mode=min,scope=uv-docker-example-standalone
49+
outputs: type=docker,dest=/tmp/uv-docker-example-standalone.tar
50+
4251
- name: Upload artifact
4352
uses: actions/upload-artifact@v4
4453
with:
@@ -51,6 +60,12 @@ jobs:
5160
name: uv-docker-example-multistage
5261
path: /tmp/uv-docker-example-multistage.tar
5362

63+
- name: Upload artifact (standalone)
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: uv-docker-example-standalone
67+
path: /tmp/uv-docker-example-standalone.tar
68+
5469
test:
5570
name: "test image"
5671
runs-on: ubuntu-latest
@@ -70,10 +85,17 @@ jobs:
7085
name: uv-docker-example-multistage
7186
path: /tmp
7287

88+
- name: Download artifact (standalone)
89+
uses: actions/download-artifact@v4
90+
with:
91+
name: uv-docker-example-standalone
92+
path: /tmp
93+
7394
- name: Load images
7495
run: |
7596
docker load --input /tmp/uv-docker-example.tar
7697
docker load --input /tmp/uv-docker-example-multistage.tar
98+
docker load --input /tmp/uv-docker-example-standalone.tar
7799
docker image ls -a
78100
79101
- name: Test command line
@@ -86,3 +108,6 @@ jobs:
86108
87109
- name: Test command line (multistage)
88110
run: docker run uv-docker-example-multistage:latest hello
111+
112+
- name: Test command line (standalone)
113+
run: docker run uv-docker-example-standalone:latest hello

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ The [`Dockerfile`](./Dockerfile) defines the image and includes:
5353
The [`multistage.Dockerfile`](./multistage.Dockerfile) example extends the `Dockerfile` example to
5454
use multistage builds to reduce the final size of the image.
5555

56+
The [`standalone.Dockerfile`](./standalone.Dockerfile) example extends the `multistage.Dockerfile`
57+
example to use a managed Python interpreter in a multistage build instead of the system interpreter
58+
that comes with the base image.
59+
5660
### Dockerignore file
5761

5862
The [`.dockerignore`](./.dockerignore) file includes an entry for the `.venv` directory to ensure the

multistage.Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
77

88
# Disable Python downloads, because we want to use the system interpreter
99
# across both images. If using a managed Python version, it needs to be
10-
# copied from the build image into the final image.
10+
# copied from the build image into the final image; see `standalone.Dockerfile`
11+
# for an example.
1112
ENV UV_PYTHON_DOWNLOADS=0
1213

1314
WORKDIR /app

standalone.Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# An example of using standalone Python builds with multistage images.
2+
3+
# First, build the application in the `/app` directory
4+
FROM ghcr.io/astral-sh/uv:bookworm-slim AS builder
5+
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
6+
7+
# Configure the Python directory so it is consistent
8+
ENV UV_PYTHON_INSTALL_DIR /python
9+
10+
# Only use the managed Python version
11+
ENV UV_PYTHON_PREFERENCE=only-managed
12+
13+
# Install Python before the project for caching
14+
RUN uv python install 3.12
15+
16+
WORKDIR /app
17+
RUN --mount=type=cache,target=/root/.cache/uv \
18+
--mount=type=bind,source=uv.lock,target=uv.lock \
19+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
20+
uv sync --frozen --no-install-project --no-dev
21+
ADD . /app
22+
RUN --mount=type=cache,target=/root/.cache/uv \
23+
uv sync --frozen --no-dev
24+
25+
# Then, use a final image without uv
26+
FROM debian:bookworm-slim
27+
28+
# Copy the Python version
29+
COPY --from=builder --chown=python:python /python /python
30+
31+
# Copy the application from the builder
32+
COPY --from=builder --chown=app:app /app /app
33+
34+
# Place executables in the environment at the front of the path
35+
ENV PATH="/app/.venv/bin:$PATH"
36+
37+
# Run the FastAPI application by default
38+
CMD ["fastapi", "dev", "--host", "0.0.0.0", "/app/src/uv_docker_example"]

0 commit comments

Comments
 (0)