Docker python项目实战部署入门

For whom

  点开这篇文章的童鞋大多数是刚听过docker这个词或者是早就听过这个词但是却没有仔细了解过,但是发现网上的教程又太过理论,初学者难以快速入门或者不知道从何学起,那么恭喜你,这篇文章就是为你而写。

Outline

  Docker是什么?先来一段百度百科上的定义:
  Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
  上面的一段话总结起来主要有三点:1.docker的作用是可以将项目及其所需环境一起打包起来,完整移植到另外一个机器上。2.docker是一项虚拟化技术,虚拟化的目的是为了在同一个主机上运行多个系统或应用,提高资源利用率。3.docker的产生的多个环境是完全独立的,不能相互影响。

认识两个概念

  Docker里有两个非常重要的概念, images,container,这两个概念都跟打包好的项目环境有关。简单来说,images是镜像,相当于面向对象里面的类,container是容器,相当于面向对象里面的实例,那么我们知道类是可以产生实例的,但在dcoker里不同的是 容器也可以生成镜像.
  总体步骤:主机A build镜像---push到docker hub---主机B pull镜像

实战

  话不多说,下面就举个实际例子,来帮助大家快速入门docker python项目部署。
  假如我的朋友小Xi(又无中生友了..)是一个深度学习炼丹师,最近在忙活一个人脸检测项目,经过多次优化,终于得到了一个精度和速度都非常棒的模型,现在他的Leader要让他给甲方当面展示下模型,甲方提出了一个要求:模型必须在甲方提供的主机上运行,以防乙方得到的模型数据是在硬件配置非常高的环境下得到的。小Xi理解甲方的顾虑,但是这万一甲方的电脑环境配置有问题,到时候现场演示代码报错怎么弄啊,这时候小Xi的同事小Liu站出来说,你可以试试docker啊,小Xi一拍脑袋,对啊,docker的作用不正是将项目和依赖环境一起打包吗,说干就干,甩了(暴露了《鬼吹灯》铁粉的身份)!
  本地的项目文件如下图所示,我们要给甲方运行的主文件是evaluate_image.py, 那么我们接下来的任务是把这个项目用docker打包起来,并上传到docker_hub,在另一台主机上把这个项目pull下来。


  • 安装
    参考docker菜鸟教程

  • 准备工作
      当你敲了几个docker指令你就会发现,docker怎么这么烦啊,每次都要root权限,那么怎么解决这个问题呢?

groups  #查看现在用户所在组的组成员,这时候应该是没有docker的
sudo groupadd docker # 添加docker用户组
sudo gpasswd -a xi docker   #"xi"是自己的用户名,将你的用户名加到docker用户组里
newgrp docker  #更新用户组
groups #这时再查看用户所在组的组成员,发现这时候有docker了,但是很可能你再开一个shell groups还是没有docker,我弄了好久,电脑重启以后就有了.

  这时应该就解决了权限问题。

  • build镜像
      首先按照这样的方式建立目录,其中docker_file里面是所有的项目代码,Dockerfile是我们自己建立的文件用于生成镜像
    .
    ├── docker_file
    └── Dockerfile
      现在你的目录应该是这个样子



      下面来填写Dockerfile的内容:

FROM python:2.7 #你的项目的工作环境
ADD ./docker_file /file #./docker_file是本地的项目的相对路径, /file是你要建立的镜像里面的项目的相对路径
WORKDIR /file #镜像的工作路径
##下面三行用于添加阿里源,官方源pip安装速度太慢
RUN pip install -U pip 
RUN pip config set global.index-url http://mirrors.aliyun.com/pypi/simple
RUN pip config set install.trusted-host mirrors.aliyun.com:
RUN pip install -r requirements.txt #用pip为镜像安装项目的依赖库
CMD ["python", "/file/evaluate_image.py"] #指定项目主文件

  需要着重关注的是requirements.txt的生成方法,这个文件里面包含了项目所有的依赖库,当然你可以一行一行的打进去,幸运的是,Python里面提供了一个包可以自动生成项目的依赖库pipreqs,首先你需要安装这个库:

pip install pipreqs

  然后cd到项目目录:

pipreqs ./

这时,你会发现docker_file文件夹下面出现了一个requirements.txt,打开里面的内容如下:

tensorflow==1.4.1
easydict==1.9
numpy==1.13.3

  切回到docker项目根目录,使用下面的指令,新建镜像


  用下面的指令查看目前存在的所有镜像,我们看到了刚才建立的xi_test镜像,你会发现,怎么每个镜像文件都这么大啊,会不会把我的硬盘空间吃完,别担心,docker采用的技术可以和已有镜像共享相同的部分,因此实际并没有占据那么多空间。

docker images
  • push镜像到docker hub
      既然本地已经有新建的镜像了,那么我们就把它上传到docker hub,先去docker hub注册一个账号,比如我的账号是xyl123,然后建立一个仓库,如first,那么这个仓库就可以用xyl123/first来指代.
docker login #登录docker
docker tag xi_test xyl123/first   #必须给本地镜像打上这样的tag标签,才可以传到docker hub上
docker push xyl123/first

  这时打开自己的docker hub主页会发现已经存在了刚上传的image


  • pull镜像到本地
      经过上面的步骤小Xi已经把自己的镜像传到docker hub上面了,只需要甲方安装docker环境,并且在演示的时候用甲方的主机把docker hub上的镜像pull下来就好了。
docker pull xyl123/first #通过运行docker images 你会发现本地多出了一个镜像,接下来你就可以利用images的相关指令对pull下来的images进行操作了.
  • 运行镜像
      运行镜像的结果是产生一个container,这个container就是我们的项目及其环境。
docker run -it xyl123/first /bin/bash  #运行镜像,产生一个容器,并以shell的交互形式运行容器.

  可以看到我们产生了一个容器,并且进入了该容器,而且进入的文件夹正是我们在Dockerfile里面设置的工作目录/file,一旦进入了容器,你就可以像操作本地文件的方式操作容器里的文件。
  root@50666281fef3:/file# 中的50666281fef3是该容器的id,如果你想查一下本地还有哪些容器,可以新建一个终端使用(不要在容器内使用):

docker ps #查看正在运行的container,
docker ps -a # -a可以查看所有的container

  那如果你想删除、开启,停止,进入,退出一个容器呢?

docker rm container_id #运行某个container
docker stop container_id #停止某个container
docker start container_id #运行某个container
docker stop container_id #停止某个container
docker exec -it container_id /bin/bash #进入某个container
exit #退出container,退出后容器并不停止,这是和 docker attach container_id 方式进入容器的根本的不同
  • 容器生成镜像
      如果在跟甲方演示的时候,甲方提了一些建议,小 Xi修改了生成的容器的内容,为了将修改之后的环境上传到docker hub,供后续改进,这时候需要用改好的容器生成一个镜像。
docker commit 50666281fef3 modified_test_xi

  这时候再运行docker images,就可以发现新生成的images了。

  • 容器和本地文件互传

      假如说,甲方要保存刚才容器内运行的结果到本地,用docker -ps 指令找到刚才容器对应的name
docker cp epic_elbakyan:/file/image/result/宋茜_2.jpeg   ./

  这时本地就出现了容器内跑出的结果,这不是宋茜的人脸(大)人头(长腿)吗?真的很方便。

  如果想反过来的,只需要颠倒本地和容器地址的位置。

docker cp epic_elbakyan: ./ 宋茜_2.jpeg  /file/image/result/ 

  注意上面两个指令不是在容器内部运行的,是在本地运行的。

日常鸡汤

  工欲善其事必先利其器,对一个算法工程师而言,每天仅仅沉醉于阅读paper不可自拔,是远远不够的,要睁开眼睛看看世界,合理利用日新月异的技术帮助自己提高效率,同样的,对于一个负责落地的开发工程师来说,也应该了解必要的理论知识,提升代码的准确性。因此想要成为一个领域内极其优秀的人才,理论和工程能力如人之双腿,缺一不可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容