Using uv with RedHat Python Images
When deploying web apps, I use containers almost exclusively. Containerization lets you package up everything your app needs and ship all of it to a container runtime in a single archive. While it has some drawbacks, it’s still a significant net improvement over web app deployment methods that pre-date it.
I use uv to install dependencies into a container image, but I typically don’t want to create a Python virtualenv within the container because then there are two levels of isolation to contend with. Just the container alone is sufficient. However, I still want all the benefits of using uv, particularly the specific tree of dependency versions and their hashes listed in the uv.lock file. For this reason, I configure uv to install the listed dependencies into the container’s “system” Python at install time, rather than a virtualenv .venv/ directory:
FROM registry.redhat.io/rhel9/python-312:latest
WORKDIR /opt/app-root/src
# Use the "system" Python for uv (the container's)
ENV UV_SYSTEM_PYTHON=1
ENV UV_PROJECT_ENVIRONMENT=/opt/app-root
# Install uv
RUN pip install --upgrade pip==26.0.1 && pip install --upgrade uv==0.11.4
# Copy only dependency files first to cache the dependency installation as its own container image layer.
# --active: prefer the environment specified by VIRTUAL_ENV (in the upstream RedHat Python base image)
# --frozen: treat the versions in uv.lock as the source of truth and skips updating the lockfile
# --no-dev: skip dev dependencies, since this is a non-development environment
# --compile-bytecode: compile Python files to .pyc files to trade CI build time for faster container start time
COPY pyproject.toml uv.lock .
RUN uv sync --active --frozen --no-dev --compile-bytecode
# Copy the rest of the codebase in a separate layer
COPY . .
CMD ["granian", "app:app"]
Those options will use uv to install dependencies into the container-provided Python environment at /opt/app-root/ in the Python image rather than creating a new virtualenv at /opt/app-root/src/.venv/. With this, you can omit uv run ... from container commands, cron jobs, etc. Opening a shell into this container will drop you into a place where the dependencies are installed and readily available without having to activate a virtualenv, prefix tool invocations with uv run, or specify a container ENTRYPOINT).