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

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

 python <path_to/my_project/setup.py> develop 

以便我可以使用我的代码的最新版本。 由于我主要开发统计学或机器学习algorithm,所以我做了很多原型并每天更改我的代码。 然而,最近推荐的方式来运行在我有权访问的集群上的实验是通过docker。 我了解到docker工人,我想我对如何使它工作有一个粗略的想法,但是如果我的解决scheme是好的,或者如果有更好的解决scheme,我不太确定。

我认为第一个解决scheme是将数据复制到我的Docker镜像中的解决scheme:

 COPY /path_to/my_project pip install /path_to/my_project 

然后点安装它。 这个解决scheme的问题是,我必须每次都build立一个新的图像,看起来很傻,希望能有更好的东西。 要做到这一点,我想有一个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 

正如我所说,我的直觉告诉我这是愚蠢的,所以我希望有一个单一的命令的方式来做到这一点与Docker或一个单一的Dockerfile。 另外,请注意,命令应该使用-v ~/data/:/data在完成训练时能够获取数据以及某些其他卷/装载(在主机中)写入。

我认为另一个解决scheme是拥有我的库在Dockerfile(因此在图像中)所需的所有python依赖关系或其他依赖关系,然后以某种方式在正在运行的容器中执行我的库的安装。 也许与docker exec [OPTIONS] CONTAINER COMMAND为:

 docker exec CONTAINER pip install /path_to/my_project 

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

 docker exec CONTAINER python run_ML_experiment_file.py 

尽pipe如此,我仍然不知道如何系统地获取容器ID(因为我可能不想每次都查找容器ID)。

理想情况下,最好的概念解决scheme是简单地让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 

而不必每次都自己显式更新图像(包括不必重新安装应该是静态的图像部分),因为它总是与真实的库同步。 另外,有一些其他的脚本每次从头开始创build一个新的图像是不是我所期待的。 另外,如果可能的话,能够避免写任何bash是很好的。


我觉得我非常接近一个很好的解决scheme。 我会做什么,而不是每次我只是运行CMD命令来做python开发,如下创build一个新的图像:

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

好处是只要我运行一个新的容器就可以安装我的库。 这解决了发展问题,因为重新创build一个新的形象需要很长的时间。 虽然我刚刚意识到,如果我使用CMD命令,那么我不能运行给我的docker运行的其他命令,所以我其实是要运行ENTRYPOINT

现在唯一需要解决的问题就是我在使用卷时遇到问题,因为我无法成功链接到Dockerfile中的主机项目库 (由于某种原因,这似乎需要一个绝对path)。 我目前正在做(似乎不工作):

 VOLUME /absolute_path_to/my_tf_proj /my_tf_proj 

为什么我不能使用我的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 apt-get update ,以便能够在我的容器中安装pip或vim。 人们知道为什么吗? 我想这样做,因为万一我想用bashterminal附加到容器,这将是非常有帮助的。

似乎Docker只是强迫你安装到容器中总是有最新版本的软件?

对于部署/分发,可以无缝地为你的软件包提供一个docker镜像。 如果不是图像,则需要将源代码转移到需要运行的环境中,将容器中的源代码configuration为容器内的源代码,以便它可以被构build等。出来了。

但为了方便起见,摆脱build立图像的手动步骤,可以考虑使用docker-compose。

docker-compose.yml可能看起来像这样:

 ml_experiment: build: <path/to/Dockerfile> volumes: - ~/data/:/data command: ["python", "run_ML_experiment_file.py"] 

现在要build立一个图像,并提出一个你只需要做的容器

 docker-compose up --build 

选项–build必须每次重build图像,否则docker-composeselect使用已经build好的图像

请参阅https://docs.docker.com/compose/

在开发过程中,IMO完全可以将hostdirectory映射/挂载到Docker容器中。 其余部分(python版本,其他依赖于你的库都可以正常的方式安装在docker容器中。

一旦稳定,我删除地图/安装,并将包添加到项目列表,以安装pip 。 我有一个单独的容器运行devpi所以我可以devpi安装软件包,无论我一直推到PyPI或只是推到我的本地devpi容器。

即使您使用通用(但更有限)的python [path_to_project/setup.py] develop也可以加快容器的创build速度。 在这种情况下,您的Dockerfile应该如下所示:

  # the following seldom changes, only when a package is added to setup.py COPY /some/older/version/of/project/plus/dependent/packages /older/setup RUN pip /older/setup/your_package.tar.gz # the following changes all the time, but that is only a small amount of work COPY /latest/version/of/project RUN python [path_to_project/setup.py] develop 

如果第一个副本会导致更改/older/setup下的文件,那么容器将从那里重build。

运行python ... develop仍然有更多的时间,你需要重build/重新启动容器。 由于我的软件包全部也可以被复制到/链接到(除了被安装),这仍然是一个很大的开销。 我在容器中运行一个小程序,检查(挂载/映射)源是否改变,然后重新运行我正在开发/testing的任何东西。 所以我只需要保存一个新的版本并观察容器的输出。