When you switch USER
to a non-root user before running pip
, it's able to figure out that it can't write to the "system" Python directories, and so it instead runs in user mode. This puts both Python packages and Python entry point scripts into a subdirectory of the current user's home directory, which isn't especially well-defined in Docker. I'd guess that you have a /.local/bin/pipenv
script inside the image, but that directory isn't on the normal command search $PATH
.
The typical advice I've heard around Docker is that a container shouldn't run as root, but the Dockerfile is relatively trusted and it's okay to have RUN
commands as root (in a couple of cases this is required). If you RUN pip install
as root then the wrapper scripts will go into /usr/local/bin
, which you can find normally.
FROM python:3.9 as builder
RUN useradd -r sorted
# still as root
RUN pip install pipenv --no-cache-dir \
&& pipenv install --system --deploy
# only when you go to run the container
USER sorted
CMD ["./main.py"]
If you really can't run anything at all as root in the Dockerfile then you need to find the "user" directory. The pip documentation has many examples of using python -m pip
instead of the pip
wrapper and this will have an extended search path. You'll also need to run pipenv in its default "user" mode, which will mean wrapping every Python-related invocation in pipenv run
(also see How to get pipenv running in docker?).
FROM python:3.9 as builder
RUN useradd -r sorted
USER sorted
ENV PATH=$HOME/.local/bin:$PATH
RUN pip install pipenv --no-cache-dir \
&& pipenv install --deploy
CMD ["pipenv", "run", "./main.py"]
The one particular advantage of this setup is around multi-stage builds. Your Dockerfile uses multi-stage build syntax, and some Python libraries depend on C extensions that have heavy-weight dependencies, but only at build time. If the build and final images use the same base image then you can COPY
the entire virtual environment across, which will let you avoid installing large meta-packages like build-essential
in the final images. (Note, again, that the Debian apt-get
package manager must run as root.)