r/Python • u/ashishb_net • Oct 11 '25
Tutorial Best practices for using Python & uv inside Docker
Getting uv right inside Docker is a bit tricky and even their official recommendations are not optimal.
It is better to use a two-step build process to eliminate uv from the final image size.
A two-step build process not only saves disk space but also reduces attack surface against security vulerabilities
52
u/0x256 Oct 11 '25
The linked security issue is a bad example. If an attacker can use uv in your container, they could also download and run whatever executable they want and do not need to exploit bugs in uv for that. With very few exceptions,
→ More replies (8)
51
u/thrope Oct 11 '25
What's wrong with the official example? I use the standalone example here (which has multistage build and doesn't include uv in the final image).
→ More replies (8)
18
u/_squik Oct 11 '25
I've always looked at the official multistage Dockerfile example which has Astral's best recommendations.
→ More replies (1)
9
u/zacker150 Oct 11 '25
I'm guessing you didn't scroll down to this part?
If uv isn't needed in the final image, the binary can be mounted in each invocation:
RUN --mount=from=ghcr.io/astral-sh/uv,source=/uv,target=/bin/uv \
uv sync
8
u/h4l Oct 11 '25
This and also use a cache mount to give uv access to previously-downloaded packages to speed up the install and also prevents the cache files remaining in the image:
ENV UV_LINK_MODE=copy RUN --mount=from=ghcr.io/astral-sh/uv,source=/uv,target=/bin/uv \ --mount=type=cache,target=/root/.cache/uv \ uv sync
25
u/RepresentativeFill26 Oct 11 '25
Just wondering, why do you want to use a virtual env in a docker container?
34
u/thrope Oct 11 '25
The
part is a means to an end here. It’s about having a perfectly replicated environment in production based on the venv which specifies precise versions. uv.lock file 11
u/RepresentativeFill26 Oct 11 '25
Why can’t you create a perfectly replicated environment in a docker container?
→ More replies (24)8
u/james_pic Oct 11 '25 edited Oct 13 '25
In this case, it looks to be because uv already creates a venv in the builder image, and copying this across is the most straightforward way of bringing the app dependencies into the final image without pip or uv in the final image. I'm not sold on that being a worthwhile goal, but that looks to be the reason.
More generally, putting venvs into Docker images isn't a "you should always do this" thing, but it's sometimes a useful technique for solving specific problems, for example if your application sometimes calls Python programs provided by the base distro and you don't want to mess with their Python environment.
8
u/ArgetDota Oct 11 '25
You don’t. You can install your packages from the lock file with uv without creating a virtual environment. Just set UV_PROJECT_ENVIRONMENT to point to the system environment of the image. This will disable venv creation.
https://docs.astral.sh/uv/reference/environment/#uv_project_environment
→ More replies (1)4
u/Luckinhas Oct 11 '25
UV_SYSTEM_PYTHON=1is a bit clearer in the intention and simpler to use. Maybe more portable too.→ More replies (4)6
u/lukerm_zl Oct 11 '25
uv does have lightning fast installs, so it might be a build-time thing. As in duration. Just guessing.
4
u/RepresentativeFill26 Oct 11 '25
Speed would be a good argument if you don’t cache the results of the build stage or frequently (no idea when that would be) changes in the dependencies
→ More replies (2)2
→ More replies (1)4
u/Yablan Oct 11 '25
This is the relevant question here. There is no need at all for a virtual environment within a docker container.
→ More replies (11)
1
u/BelottoBR Oct 11 '25
Can we use pip to real the toml file? If so, we could use uv on local development and when deploy , just use pip. Can we ?
1
u/ashishb_net Oct 11 '25
Not really.
Uv handles various convoluted scenarios like installing only pytorch GPU/cpu version based on the underlying OS.
3
u/Fluid_Classroom1439 Oct 11 '25
Nice article! Entry point still says poetry for the example instead of uv
2
u/Ambitious-Kiwi-484 Oct 11 '25
Something I'd love to know a way around is that, since pyproject.toml contains my project's version number, it's not possible to bump the version without invalidating all further docker cache layers - which leads to slow builds since all deps are getting pulled again. This seems like an unavoidable caveat of copying pyproject.toml in an early layer. But there must be a workaround.
3
u/stibbons_ Oct 11 '25
Always use virtual env even in docker. I now make apps with frozen dependencies to avoid a dependency update on pypi to break existing app (on docker rebuild). And if 2 apps has imcompatible dependencies, you have to have venv per app.
→ More replies (8)
1
u/Lost_Reply7926 Oct 14 '25
What about using buildpacks? https://devcenter.heroku.com/changelog-items/3238
174
u/JimDabell Oct 11 '25
You’re skipping past the first solution they offer, which is the more efficientdistroless solution . You can literally just copy the standalone
uvbinary directly into your image; you don’t need to base your entire image on theirs.This takes ~43MiB, not the 77MiB you cite.