如何使用在 docker 镜像或新容器中不断变化的 python 库?

Cha*_*ker 7 python docker dockerfile

我在 python 包中组织我的代码(通常在虚拟环境中virtualenv和/或conda),然后通常调用:

python <path_to/my_project/setup.py> develop
Run Code Online (Sandbox Code Playgroud)

这样我就可以使用我的代码的最新版本。由于我主要开发统计或机器学习算法,因此我会制作大量原型并每天更改代码。但是,最近在我可以访问的集群上运行我们的实验的推荐方法是通过 docker。我了解了 docker,我想我对如何使其工作有一个粗略的想法,但我不太确定我的解决方案是否好或者是否有更好的解决方案。

我认为的第一个解决方案是使用以下解决方案复制我的 docker 映像中的数据:

COPY /path_to/my_project
pip install /path_to/my_project
Run Code Online (Sandbox Code Playgroud)

然后pip安装它。这个解决方案的问题是我每次都必须实际构建一个新图像,这看起来很傻,并希望我能有更好的东西。为此,我想拥有一个 bash 文件,例如:

#BASH FILE TO BUILD AND REBUILD MY STUFF
# build the image with the newest version of 
# my project code and it pip installs it and its depedencies
docker build -t image_name .
docker run --rm image_name python run_ML_experiment_file.py 
docker kill current_container #not sure how to do get id of container
docker rmi image_name
Run Code Online (Sandbox Code Playgroud)

正如我所说,我的直觉告诉我这很愚蠢,所以我希望有一种使用 Docker 或单个 Dockerfile 执行此操作的单一命令方式。另外,请注意,该命令应该用于-v ~/data/:/data在完成训练后获取数据和其他一些要写入(在主机中)的卷/挂载。

我认为的另一个解决方案是将我的库需要的所有 python 依赖项或其他依赖项包含在 Dockerfile 中(因此在映像中),然后以某种方式在运行的容器中执行我的库的安装。也许与docker exec [OPTIONS] CONTAINER COMMAND

docker exec CONTAINER pip install /path_to/my_project
Run Code Online (Sandbox Code Playgroud)

在正在运行的容器中。之后,我可以使用相同的 exec 命令运行我想运行的真实实验:

docker exec CONTAINER python run_ML_experiment_file.py
Run Code Online (Sandbox Code Playgroud)

尽管如此,我仍然不知道如何系统地获取容器 id(因为我可能不想每次这样做时都查找容器 id)。

理想情况下,在我的脑海中,最好的概念解决方案是简单地让 Dockerfile 从一开始就知道它应该挂载到哪个文件(即/path_to/my_project),然后以某种方式python [/path_to/my_project] develop在图像内部进行操作,以便它始终链接到可能发生变化的 python 包/项目。这样我就可以使用单个 docker 命令运行我的实验,如下所示:

docker run --rm -v ~/data/:/data python run_ML_experiment_file.py
Run Code Online (Sandbox Code Playgroud)

并且不必每次都自己显式更新图像(包括不必重新安装应该是静态的图像部分),因为它始终与真实库同步。此外,每次让其他脚本从头开始构建新图像也不是我想要的。此外,如果可能的话,能够避免编写任何 bash 也很好。


我想我非常接近一个好的解决方案。每次我将简单地运行CMD命令来执行 python 开发时,我将做什么而不是构建一个新图像,如下所示:

# install my library (only when the a container is spun)
CMD python ~/my_tf_proj/setup.py develop
Run Code Online (Sandbox Code Playgroud)

优点是它只会在我运行新容器时安装我的库。这解决了开发问题,因为重新创建新图像需要很长时间。虽然我刚刚意识到,如果我使用该CMD命令,那么我将无法运行给我的 docker run 的其他命令,所以我实际上是想运行ENTRYPOINT .

现在唯一要完成的问题是我在使用 volume 时遇到了问题,因为我无法在 Dockerfile 中成功链接到我的宿主项目库(出于某种原因,这似乎需要一个绝对路径)。我目前正在做(这似乎不起作用):

VOLUME /absolute_path_to/my_tf_proj /my_tf_proj
Run Code Online (Sandbox Code Playgroud)

为什么我不能在 Dockerfile 中使用 VOLUME 命令进行链接?我使用 VOLUME 的主要目的是在 CMD 命令尝试安装我的库时使我的库(以及此图像始终需要的其他文件)可访问。是否可以在启动容器时始终让我的库可用?

理想情况下,我只想在容器运行时自动安装库,如果可能的话,因为总是需要最新版本的库,所以在容器初始化时安装它。

作为现在的参考,我的非工作 Dockerfile 如下所示:

# This means you derive your docker image from the tensorflow docker image
# FROM gcr.io/tensorflow/tensorflow:latest-devel-gpu
FROM gcr.io/tensorflow/tensorflow
#FROM python
FROM ubuntu

RUN mkdir ~/my_tf_proj/
# mounts my tensorflow lib/proj from host to the container
VOLUME /absolute_path_to/my_tf_proj

#
RUN apt-get update

#
apt-get install vim

#
RUN apt-get install -qy python3
RUN apt-get install -qy python3-pip
RUN pip3 install --upgrade pip

#RUN apt-get install -y python python-dev python-distribute python-pip

# have the dependecies for my tensorflow library
RUN pip3 install numpy
RUN pip3 install keras
RUN pip3 install namespaces
RUN pip3 install pdb

# install my library (only when the a container is spun)
#CMD python ~/my_tf_proj/setup.py develop
ENTRYPOINT python ~/my_tf_proj/setup.py develop
Run Code Online (Sandbox Code Playgroud)

作为旁注:

此外,出于某种原因,它要求我什RUN apt-get update至能够在我的容器中安装 pip 或 vim。人们知道为什么吗?我想这样做是因为以防万一我想用bash终端连接到容器,这真的很有帮助。

似乎 Docker 只是强迫您 apt install 以在容器中始终拥有最新版本的软件?


赏金:

有什么解决办法COPY?也许docker build -f path/Docker .。请参阅:如何从主用户目录构建 docker 映像?

Yuv*_*uva 3

对于部署/分发,为您的包提供 docker 映像将是无缝的。如果不是图像,您需要将源代码传输到需要运行的环境,配置一个卷以将源代码包含在容器内,以便可以构建它等,使用图像只需拉取并运行容器出来了。

但为了方便起见并摆脱构建映像的手动步骤,请考虑使用 docker-compose。

docker-compose.yml 可能如下所示:

ml_experiment:
  build: <path/to/Dockerfile>
  volumes:
    - ~/data/:/data
  command: ["python", "run_ML_experiment_file.py"] 
Run Code Online (Sandbox Code Playgroud)

现在要构建图像并启动容器,您只需要做

docker-compose up --build
Run Code Online (Sandbox Code Playgroud)

选项--build必须每次重建镜像,否则 docker-compose 选择使用已经构建的镜像

参考https://docs.docker.com/compose/