docker tensorflow_[工具篇] Docker快速入门

  想必不少人都经历过被深度学习复杂的环境配置所支配的绝望,当你在自己的电脑上辛苦配好了环境,写好了代码,训练好了模型,搞好了服务,大功告成准备部署到另一台服务器运行时,环境又要重新配.....

个人开发时,便捷的获得配置好的环境可以节约一大笔时间;多人开发同一个项目时,统一环境配置可能会解决很多不必要的问题;在企业中开发或者测试有着标准的环境配置,开发人员使用标准环境配置正常运行,部署过程能够更加的从容流畅...

之前见一位师兄很多工作都会使用Docker进行,当时并不理解,直到后来接触到并稍微熟悉了Docker的操作,才发觉真的很好很强大。轻量级,启动迅速,可移植性高,隔离性强,功能强大的Docker,让环境配置和移植不再是令人头疼的难题。

一、认识Docker

Docker的安装本文就不详细展开了,搜索系统版本+Docker安装(例如:Ubuntu 16.04 Docker安装) 即可获得一大批的教程文章,接下来简单讲一下Docker中的几个概念:

  • Docker:用于支持创建和使用linux容器的容器化技术;

  • 镜像(Image):特定环境/配置/文件的集合;

  • 容器(Container):与系统其它部分隔离的一系列进程,从镜像运行,由镜像提供支持进程的全部文件;

  • 仓库(Repository):镜像统一存放的场所,Docker hub 类似于github。

在使用过程中,我们可以通过拉取公开的镜像或者自己通过Dockerfile创建指定环境镜像的方式获得Docker镜像,然后运行这个镜像为一个容器,在容器中可以下载/安装应用,创建/修改文档,编写/运行程序等等,这个容器就类似于一个配置好特定环境及文件的全新的linux系统,可以在里面自由自在的操作而不影响容器之外的其他环境。

Docker,镜像,容器,仓库的关系如下图:

a150190fc21ff0c0057788af538f4982.png

通过Dockerfile可以构建镜像;

镜像可以通过tag来打标签或更改名字;可以打包为压缩包,并可以从压缩包中加载;可以推送至镜像仓库,也可以从镜像仓库中拉取。

容器由镜像运行,可以停止、重启以及进入内部修改;也可以从容器重新构建镜像。这些操作在接下来都会一一展示。

二、使用Docker

1. Docker常用命令

# 查看本机的镜像及IDdocker images# 查看全部容器及IDdocker ps -a# 停止容器docker stop # 删除容器:docker rm   # 如果该容器正在运行,需要先停止容器;或者添加参数-f直接停止并删除容器# 删除镜像docker rmi   # 如果该镜像有容器正在使用,需要先删除容器# 重启容器docker restart 

2. Docker hello world

# 拉取hello-world镜像docker pull hello-world# 运行hello-worlddocker run hello-world# 输出 ‘Hello from Docker!’ 字样,表示hello-world成功运行。
运行后输出‘Hello from Docker!’等字样,表示hello-world成功运行。

通过 docker ps -a 可以以看到当前机器上容器的信息,分别为 容器的ID ,容器从哪个镜像启动的,容器内的默认指令,容器的创建时间,容器当前的状态,端口情况,容器的名字。

98fe5466e7b3435a12c53e7244b932fd.png

这里我们运行hello-word时并未指定名字,所以docker随机给了个名字,可通过 docker run --name hello_test hello-world 为容器指定名字。

3. Docker 国内镜像源

Docker hub提供大量官方及用户上传的镜像:https://hub.docker.com/

可以为docker添加国内镜像源来提升拉取的速度。编辑 /etc/docker/daemon.json 文件(若不存在则新建),添加内容:

{"registry-mirrors":     "https://docker.mirrors.ustc.edu.cn","https://alzgoonw.mirror.aliyuncs.com","https://registry.docker-cn.com"    ]}

配置之后,重启docker令配置生效,查看配置。

sudo systemctl restart dockerdocker info

4. 拉取镜像

  • 查询镜像

docker search tensorflow
  • 拉取TensorFlow镜像

docker pull tensorflow/tensorflow:1.12.0-py3   # CPU版docker pull tensorflow/tensorflow:1.12.0-gpu-py3   # CPU版

拉取镜像后可以通过 docker images 查看本机存在的镜像及对应的镜像ID等信息。

3201ff9a075be50de1b37f00e2b66486.png

命令中的第一个 tensorflow 为镜像仓库的名称,第二个 tensorflow 为镜像的名称,最后的 1.12.0-py3为镜像的标签(tag),通过tag可以区分镜像的版本。

5. 镜像标签

通过docker tag命令,可以为镜像更改标签或名字,默认标签为latest

docker tag tensorflow/tensorflow:1.12.0-py3 my_image:v1

6. 启动容器 

docker run -it -p 8888:8888  --name tf_test tensorflow/tensorflow:1.12.0-py3# docker run 参数说明--name : 设定容器名字为tf_test-it : 以交互形式运行,像linux命令行一般与镜像“对话”-p : 进行端口映射(例如8008:8888为将容器内的8888端口映射到本地的8008端口,外部可通过8008端口访问)-d : 后台运行--rm : 运行结束后删除此容器 (不可与-d同时使用)--gpus:指定显卡(例如--gpus device=5,则令此容器使用5号显卡)
tensorflow镜像设定默认以运行jupyter,复制显示的链接,将ip替换为自己的ip,即可进入jupyter页面。

9ae0690690b9a3a63139a90997e21f1e.png

5b6de986b705a3408facb465ea290839.png

  • 程序参数

若项目中默认启动程序需要指定输入参数,可以在docker run 命令的最后添加程序中的指定参数,例如--batch_size=16

  • 退出当前容器

以交互式方式运行容器后。镜像内程序正在运行使用CTRL+C终止程序后,容器即退出并停止。可用 docker ps -a 查看容器id, docker rm 删除容器;若容器正在运行,想同时停止并删除容器,可在 rm 后加 -f 参数直接停止并删除容器。

(删除容器并不会影响镜像,若不删除容器则下次不可以以相同名字启动新的容器)

  • 若不需要长期运行的容器,也可以在 docker run 后加参数 --rm 完成上述操作,退出容器后直接删除容器。

7. 重启停止的容器

docker stop      # 停止容器docker restart   # 重启容器

为了让容器能够一直运行,防止关机等操作使容器停止,也可以在docker run 后加 --restart=always 参数,让容器在停止后可以自动重启。容器重启后,与退出前的最后状态一致,例如我们在容器中创建了新文件 test.py ,停止容器并重新启动后,文件仍然在容器中。

8. Docker拷贝文件

通过 docker cp 命令,可以方便的将本地文件拷贝至容器内,或将容器内文件拷贝至本地。

docker cp  :# 为本地文件路径# 为容器内路径

648610ba7d5a7bff4856a1ffe932f210.png

9. 进入正在运行的容器

docker exec -it  bash# bash : 运行bash,可以使用命令行像操作本机一样操作镜像

0619ae8da4ff4ca52c5a3b4152868db2.png

退出时可输入 exit ,退出后容器仍在运行。

进入容器后,我们可以像在本机操作一样在容器内进行操作,例如创建/修改文件,安装/删除应用等等。例如可以通过 touch test.py 新建一个文件;可以通过 apt-get update 后 apt install vim 安装 vim ,从而修改文件内容;可以通过 pip install numpy 安装 numpy 包。

至此,我们可以像使用一台新的机器一样在容器内自由自在的操作了。

10. Docker挂载文件

如果有配置文件需要经常变动,又不想每次都进入容器修改,那么可以将本地文件夹映射到容器路径下,让容器启动后访问本地路径的文件。

docker run -v :# 为本地文件夹绝对路径# 为容器内文件夹绝对路径

0e78684ad63e05ad4e9fbba660ec6f6e.png

若容器内没有此文件夹,则会在容器内自动新建,若容器内有此文件夹,则会覆盖掉容器内的文件夹。 

11. 查看容器的log

当容器运行起来后,我们想实时查看容器的log输出,可使用 docker logs 命令。

docker logs -f -t --tail 100 # docker logs 参数说明-f: 实时跟踪容器日志-t:显示时间戳--tail 100:查看最新100行的日志

查看某段时间内的日志:

docker logs -t--since="2020-06-22T10:00:00" --until "2018-06-22T11:00:00" # docker logs 参数说明--since:从此时间戳开始的日志(也可为相对时间,如30m,则为最近30分钟的日志)--until:截止至此时间戳的日志

12. 提交镜像

如果我们修改了容器内的文件,想保留这个修改,以便将镜像部署至其他机器后仍保持此改动,可将容器创建为镜像。

docker commit  

通过 docker exec 和 docker commit ,在我们想修改镜像时,不需要再重新 build ,可以直接从现有的容器修改生成新的镜像。

13.   推送镜像

例如我们在名为 tf_test 的容器中,新建了 test.py 文件,此时使用 docker commit tf_test tensorflow/tensorflow:1.12.0-py3 ,则此镜像中就包含了 test.py 这个文件。若新的镜像名和标签与之前一致,则会直接覆盖掉之前的镜像。若不一致,则新的镜像依赖于之前的镜像,删除时若不删除新的镜像,则无法删除旧的镜像。

要把镜像推送至仓库时,可通过 docker login 登陆镜像仓库,然后给自己的镜像打标签后直接推送至镜像仓库。

docker tag  docker push # [REPO]:镜像仓库的地址

14. 打包镜像

镜像不仅可以通过镜像仓库的 push 和 pull 来传输,也可以打包为压缩包。

  • 在本机打包镜像

docker save -o  # example:docker save -o ./get_time_image.tar get_time:latest
  • 将压缩包复制到其他机器,加载镜像

sudo docker load # example:sudo docker load 

加载后即可使用 docker images 查看新的镜像,也可以使用之前的命令运行镜像了。

三、Docker部署

1. 使用Dockerfile制作镜像

假设我们要建立一个获取当前时间的接口的简单项目,名为 get_time ,设定端口为 80 (通常将默认端口设置为80,在容器启动时再映射至指定端口)。创建镜像时需要安装一些项目所需的python库,可以先 pip install pipreqs ,然后在项目根目录下执行 pipreqs ./ 生成 requirements.txt 。

  •  创建Dockerfile

在项目根目录下创建文件Dockerfile,并写入以下内容
FROM python:3.6ENV LANG C.UTF-8# Set the working directory to /get_timeWORKDIR /get_time# Copy the current directory contents into the container at /get_timeCOPY ./ /get_time# Install any needed packages specified in requirements.txtRUN pip install -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt# Run api_get_time.py when the container launchesENTRYPOINT ["python", "./api_get_time.py"]
  • 指令说明:

FROM:此镜像基于哪个基础镜像(若基础镜像在本机不存在,则会自动拉取)WORKDIR:设定当前的工作目录,相当于linux指令cdCOPY:复制文件RUN:执行的指令ENTRYPOINT:容器启动后执行的命令
  • 使用 Dockerfile,通过 docker build 命令来构建一个镜像
docker build -t get_time .# docker build 参数说明-t : 指定要创建的目标镜像名. : Dockerfile 文件所在目录相对路径,也可以指定Dockerfile 的绝对路径
创建成功后,可以用 docker images 来查看我们创建的镜像。

f07dd872267fc17228e60e79739c64a1.png

2. 后续操作

  • 运行验证镜像

docker run -it -p 8123:80 --name get_time_api get_time

查看容器是否正常运行,并验证其功能。

若验证正常后需要直接运行在本机,则将其挂在后台运行即可。

docker run -d -p 8123:80 --restart=always --name get_time_api get_time
  • 修改镜像

若镜像存在问题,或需要为镜像添加/修改功能等,可以修改项目后重新 docker build 生成新的镜像,也可以使用 docker cp 覆盖文件, docker run -v 挂载路径,或使用 docker exec 进入运行中的容器,进行修改,修改后重新 docker commit 为新的镜像再次验证。
  • 提交镜像

验证完成后,可通过 docker push 推送镜像至镜像仓库,或通过 docker save 打包为压缩包后移动到另一台机器上加载运行。

四、docker-compose

如果一个项目中需要多个docker镜像,每次手动的创建、运行、管理将变得十分繁琐。通过docker-compose可以实现Docker容器集群的快速编排,便捷的管理、运行多容器的docker项目。

1. 安装

Compose是Docker官方开源的项目,主要由python编写,可以直接通过pip安装。

pip install docker-compose

2. 常用命令

docker-compose 的使用与docker的使用命令较为相似

  • 部分命令:

docker-compose version:查看版本信息docker-compose up:根据模板文件自动构建镜像/创建服务/启动服务等docker-compose down:停止并删除容器/网络等docker-compose exec:与docker exec相同,进入到运行中的容器内docker-compose pull:拉取服务依赖的镜像docker-compose push:推送服务依赖的镜像docker-compose rm:删除停止状态的服务容器docker-compose ps:列出项目中当前的容器docker-compose logs:查看当前项目的log输出,不同服务用不同颜色标识
  • 部分参数:

-d:在后台运行-v:挂载目录--name:为容器指定名字--rm:容器退出后自动删除 

3. 模板文件

在项目根目录下创建 docker-compose.yml 文件,该文件相当于将项目所需的docker操作都写在同一个文件下,自动执行。文件内容包含version /services /networks /volumes 几部分,结构如下:

version: '2'services:  service1:    image: my_image    ports:      - "8000:80"    container_name: "my_service_1"  service2:    image: my_image    ports:      - "8001:80"    container_name: "my_service_2"# networks:# volumes:
  • 文件说明:

version:目前版本为1,2,3;version2支持更多指令,version1未来将被禁用services:项目内的服务networks:配置容器连接的网络(非必须)volumes:挂载目录(非必须)# 其中services下的内容相当于docker的操作更改了写法build: Dockerfile的相对路径或绝对路径image: 服务镜像,若不存在则自动拉取container_name:指定容器名字,若不指定则随机生成ports: 端口映射(相当于docker的-p)volumes:数据卷挂载(相当于docker的-v)command: 覆盖容器启动后的默认执行命令depends_on: 服务依赖关系,定义启动顺序,先启动被依赖的服务networks:设定网络,若两个服务设定在同一个网络下,则可以互相访问容器内部的端口

4. 实例

接下来我们根据之前提到的获取当前时间的任务来进行一次 docker-compose 的实战。首先创建 compose 文件夹,目录结构如下:

5d26e463179b1cd8d8d714d078d2753b.png

 docker-compose.yml 为模板文件, get_time_now 为获取时间的项目,其中包含主程序文件,Dockerfile和依赖文件,另外我们发现程序中获取的时间和当前时间相差8个小时,然后建立 get_time_now_new 文件夹内的代码中更新了代码。

接下来编辑 yml 文件为如下内容:

version: '2'services:  task1:    image: get_time_now:v1.0      # 从此镜像启动容器,但此时还没有这个镜像,此镜像在task2中构建,所以下方定义依赖与task2    ports:       - "8001:80"                 # 容器内的80端口映射至宿主机的8001端口    container_name: "get_time_1"  # 设定容器名称    depends_on:      - task2                     # 依赖于task2,启动时task2先启动    networks:      - dev                       # 定义网络 (与task2在同一个网络下,可以与task2互相访问容器内部端口,但不能与task3互相访问容器内部端口)  task2:    build: ./get_time_now/        # Dockerfile所在的相对路径    image: get_time_now:v1.0      # 为构建好的镜像起个名字,若不指定,则默认名字为compose_task2    ports:       - "8002:80"    container_name: "get_time_2"    networks:      - dev                       # 定义网络, 可以与task1互相访问容器内部端口      - pro                       # 定义网络, 可以与task2互相访问容器内部端口  task3:    image: get_time_now:v1.0    ports:       - "8003:80"    container_name: "get_time_3"    depends_on:      - task2                     # 依赖于task2,启动时task2先启动    networks:      - pro                       # 定义网络 (与task2在同一个网络下,可以与task2互相访问容器内部端口,但不能与task1互相访问容器内部端口)    volumes:      - ./get_time_now_new/:/get_time_now   # 将修正好的get_time_now_new内的代码映射至容器内,该服务可以显示正确的时间networks:  dev:    driver: bridge  pro:    driver: bridge
在项目根目录下,执行 docker-compose up -d ,服务挂在后台运行。项目中在 task2 构建镜像, task1 和 task3 依赖于 task2 , task2 最先启动。 task1 和 task2 都是原生镜像,显示的时间为8个小时前, task3 中我们将修正后的代码映射至了容器内部,故 task3 可以显示正确的时间。

440daf88d94003b890537d477ca6c748.png

3b8980fce1447a3aaab81a835f342849.png

b46cb08a15b18346d07e94cb45a25f51.png

参考链接:

[1] https://www.runoob.com/docker/docker-tutorial.html

[2] https://www.cnblogs.com/clsn/p/8410309.html

[3] https://blog.csdn.net/yimenglin/article/details/92624549

[4] https://www.jianshu.com/p/18bb54978bc0

[5] https://blog.csdn.net/Anumbrella/article/details/80877643

[6] https://www.cnblogs.com/minseo/p/11548177.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值