How to use uv instead of pip in Docker

Tags:
  • Python
  • Docker

Published


uv is a package installer for Python written in Rust. It's a pip replacement and it's significantly faster.

In CI at work replacing pip with uv in our Dockerfiles makes the build 30s faster. Here's how you can do it with a multi-stage Dockerfile so the uv binary, which is relatively big at 25MB, is not included in your final image.

FROM ghcr.io/astral-sh/uv:0.1.37 AS uv

FROM python:3.12-slim AS python

ENV VIRTUAL_ENV=/opt/venv
RUN  \
    # we use a cache --mount to reuse the uv cache across builds
    --mount=type=cache,target=/root/.cache/uv \
    # we use a bind --mount to use the uv binary from the uv stage
    --mount=type=bind,from=uv,source=/uv,target=/uv \
    # we use a bind --mount to use the requirements.txt from the host instead of adding a COPY layer
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    /uv venv /opt/venv && \
    /uv pip install -r requirements.txt
CMD ["/opt/venv/bin/python"]

Using keyring for authentication

If you need to authenticate requests to a private registry with keyring, for example to GCP artifact registry, this is how you can do it:

FROM ghcr.io/astral-sh/uv:0.1.37 AS uv

FROM python:3.12-slim AS python

ENV VIRTUAL_ENV=/opt/venv
# make keyring available on PATH so uv can use it
ENV PATH="/opt/venv/bin:$PATH"
RUN  \
    --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,from=uv,source=/uv,target=/uv \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    # mount the secret with the GCP credentials
    --mount=type=secret,id=gcloud_application_default_credentials,target=/root/.config/gcloud/application_default_credentials.json \
    /uv venv /opt/venv && \
    /uv pip install keyring keyrings.google-artifactregistry-auth && \
    /uv pip install --keyring-provider subprocess -r requirements.txt && \
    # uninstall keyring to make image smaller
    /uv pip uninstall keyring keyrings.google-artifactregistry-auth
CMD ["/opt/venv/bin/python"]