如何使用非 root 用户权限构建 docker 以使用 pipenv 设置 python 应用程序?

How to build docker with non-root user privileges to setup python application with pipenv?

我使用 tornado 服务器创建了 python 网络应用程序,现在正在 docker 化。我正在尝试为持续集成和持续交付构建 docker 图像。我可以使用 root 用户创建 docker 图像。现在我想用非 root 用户构建 docker 图像并使用 pipenv

设置应用程序

Docker 文件

FROM python:3.6

RUN apt-get update -y

ENV USER dockeruser
ENV HOME /home/$USER

RUN useradd -m $USER && echo $USER:$USER | chpasswd && adduser $USER sudo
RUN chown $USER:$USER $HOME

USER $USER

RUN mkdir -p $HOME/myapp
COPY . $HOME/myapp
WORKDIR $HOME/myapp

RUN echo $(whoami)
RUN pip3 install pipenv --user
RUN echo $(which python)
RUN echo $(which pipenv)
RUN pipenv install --system --deploy --ignore-pipfile

EXPOSE 8002

# Run server.py when container launches
CMD gunicorn -k tornado server:app -b 0.0.0.0:8002 -w 4 -p server.pid

构建映像时找不到 pipenv

docker build -f Dockerfile -t myapp .
Sending build context to Docker daemon   51.2kB
Step 1/17 : FROM python:3.6
 ---> 1ec4d11819ad
Step 2/17 : RUN apt-get update -y
 ---> Using cache
 ---> 010d1ef4aee8
Step 3/17 : ENV USER dockeruser
 ---> Using cache
 ---> 9b9825691f31
Step 4/17 : ENV HOME /home/$USER
 ---> Using cache
 ---> 4002da8d84bf
Step 5/17 : RUN useradd -m $USER && echo $USER:$USER | chpasswd && adduser $USER sudo
 ---> Using cache
 ---> e6105957751e
Step 6/17 : RUN chown $USER:$USER $HOME
 ---> Using cache
 ---> e1b4d901ae9f
Step 7/17 : USER $USER
 ---> Using cache
 ---> e22af3515d86
Step 8/17 : RUN mkdir -p $HOME/myapp
 ---> Using cache
 ---> 6a7e99189ad8
Step 9/17 : COPY . $HOME/myapp
 ---> Using cache
 ---> f6e7ac570431
Step 10/17 : WORKDIR $HOME/myapp
 ---> Using cache
 ---> a0eaa4346a8c
Step 11/17 : RUN echo $(whoami)
 ---> Running in 60e249e38e94
dockeruser
Removing intermediate container 60e249e38e94
 ---> 015dfa644ff0
Step 12/17 : RUN pip3 install pipenv --user
 ---> Running in 5966183d82b0
Collecting pipenv
  Downloading https://files.pythonhosted.org/packages/13/b4/3ffa55f77161cff9a5220f162670f7c5eb00df52e00939e203f601b0f579/pipenv-2018.11.26-py3-none-any.whl (5.2MB)
Collecting virtualenv-clone>=0.2.5 (from pipenv)
  Downloading https://files.pythonhosted.org/packages/16/9d/6419a4f0fe4350db7fdc01e9d22e949779b6f2d2650e4884aa8aededc5ae/virtualenv_clone-0.4.0-py2.py3-none-any.whl
Collecting virtualenv (from pipenv)
  Downloading https://files.pythonhosted.org/packages/7c/17/9b7b6cddfd255388b58c61e25b091047f6814183e1d63741c8df8dcd65a2/virtualenv-16.1.0-py2.py3-none-any.whl (1.9MB)
Collecting certifi (from pipenv)
  Downloading https://files.pythonhosted.org/packages/9f/e0/accfc1b56b57e9750eba272e24c4dddeac86852c2bebd1236674d7887e8a/certifi-2018.11.29-py2.py3-none-any.whl (154kB)
Requirement already satisfied: pip>=9.0.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (18.1)
Requirement already satisfied: setuptools>=36.2.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (40.6.2)
Installing collected packages: virtualenv-clone, virtualenv, certifi, pipenv
  The script virtualenv-clone is installed in '/home/dockeruser/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  The script virtualenv is installed in '/home/dockeruser/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  The scripts pipenv and pipenv-resolver are installed in '/home/dockeruser/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed certifi-2018.11.29 pipenv-2018.11.26 virtualenv-16.1.0 virtualenv-clone-0.4.0
Removing intermediate container 5966183d82b0
 ---> 22aee2cc9a96
Step 13/17 : RUN echo $(which python)
 ---> Running in 140c3fa728f6
/usr/local/bin/python
Removing intermediate container 140c3fa728f6
 ---> 86816d83b846
Step 14/17 : RUN echo $(which pipenv)
 ---> Running in ac211799f058

Removing intermediate container ac211799f058
 ---> cf1b7ea148bb
Step 15/17 : RUN pipenv install --system --deploy --ignore-pipfile
 ---> Running in 47f0837ce1d7
/bin/sh: 1: pipenv: not found
The command '/bin/sh -c pipenv install --system --deploy --ignore-pipfile' returned a non-zero code: 127

您的安装日志给了您答案:

The script virtualenv-clone is installed in '/home/dockeruser/.local/bin' which is not on PATH.

它告诉您您将无法通过短名称访问已安装的包。要么通过像 /home/dockeruser/.local/bin/... 这样的完整路径调用它,要么将此目录添加到 PATH.

您需要将 pipenv 添加到 PATH 变量中。

RUN echo $(whoami)
RUN pip3 install pipenv --user
ENV PATH $PATH:$HOME/.local/bin

应该是这样的。

在 Docker 映像中安装软件 "globally"(通常只会做一件事)并提交一些实现细节(如容器内部用户名和路径)并没有错。以 root 身份安装软件并切换到非 root 用户以实际 运行 图像是完全没问题的。

我可能会这样写 Docker 文件:

FROM python:3.6

# Globally install pipenv
RUN pip3 install pipenv

# Set up the app directory (Docker will create it for us)
WORKDIR /myapp
COPY . ./
RUN pipenv install --system --deploy --ignore-pipfile

# Establish the runtime user (with no password and no sudo)
RUN useradd -m myapp
USER myapp

# Normal image metadata
EXPOSE 8002
CMD gunicorn -k tornado server:app -b 0.0.0.0:8002 -w 4 -p server.pid