6

用Docker打包Python运行环境 - orion-orion

 1 year ago
source link: https://www.cnblogs.com/orion-orion/p/16268011.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

虽然Docker作为部署环境打包镜像的工具,和我的科研并没有直接的关系。但我觉得在项目中运用Docker来打包环境依赖也可以大大提高工作效率,于是准备专门学习一下Docker。

1. Docker基础

1.1 Docker架构

Docker使用客户端服务器架构。Docker客户端与Docker守护进程会话,后者复杂构建、运行和分发Docker容器的繁重工作。Docker客户端和守护程序可以在同一系统运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护程序通过REST API(采用一种简洁的URL风格规范)通信,其底层基于UNIX套接字或网络接口。其架构示意图如下:

NLP多任务学习

其中,Docker 守护程序 (dockerd) 监听Docker API 请求并管理Docker对象,例如镜像、容器、网络和磁盘分卷。守护进程还可以与其他守护进程通信以管理Docker服务。而Docker 客户端 ( docker) 是用户与 Docker 交互的主要方式。当我们使用诸如docker run之类的命令时,客户端会将这些命令发送到dockerd执行它们。docker命令使用 Docker API。Docker 客户端可以与多个守护进程通信。

Docker注册表存储Docker镜像(你可以类比为Maven的repo)。Docker Hub 是一个任何人都可以使用的公共注册表,并且 Docker 默认配置为在Docker Hub上查找镜像。我们也可以运行自己的私有注册表。我们可以调用docker pull从注册表中拉取镜像。当我们docker run命令时,系统会从先从本地寻找镜像,如果本地找不到,则会从Docker Hub拉取。当我们使用docker push命令时,镜像会被推送到我们配置的注册表中。可以看出,Docker镜像版本控制和Git类似。

1.2 Docker对象

当我们在使用Docker时,我们就正在创建和使用镜像、容器、网络、磁盘分卷、插件和其他对象了。下面简要介绍一下其中的镜像和容器对象。

  • 镜像 镜像可视为一个只读模板,其中包含创建 Docker 容器的指令。通常,一个镜像基于另一个镜像,并带有一些额外的自定义。例如可以基于现有的ubuntu镜像,来构建安装有其它应用程序的镜像。要构建我们自己的镜像,需要使用简单的语法创建一个Dockerfile ,用于定义创建和运行镜像所需的步骤。

  • 容器
    容器是镜像的可运行实例(类似于进程和程序的关系)。我们可以使用 Docker API 或 CLI 创建、启动、停止、移动或删除容器。我们可以将容器连接到一个或多个网络。

2. 启动Docker进程并运行镜像

2.1 启动Docker守护进程

Linux

Linux上的docker同时包括客户端和守护进程两部分,故安装好docker后,只需要用以下命令即可运行docker守护进程:

$ sudo service docker start # Ubuntu/Debian

如果您是RedHat/Centos,则需要运行:

$ sudo systemctl start docker

MacOS

然而,在Mac上docker二进制仅仅是client部分(因为docker守护进程使用了一些Linux内核的特点),我们不能使用它来运行docker守护进程。所以,我们还需要安装docker-machine来创建一个虚拟机并将守护进程运行在上面。如果你的Mac上已经有brew,可以直接运行以下命令安装:

brew install docker-machine

然后启动docker-machine:

(base) orion-orion@MacBook-Pro ~ % brew services start docker-machine
==> Successfully started `docker-machine` (label: homebrew.mxcl.docker-machine)

2.2 运行镜像

之后我们就可以尝试运行Docker镜像了。比如我们下面用docker run命令运行docker/getting-started镜像:

(base) orion-orion@MacBook-Pro ~ % docker run -d -p 80:80 docker/getting-started 
Unable to find image 'docker/getting-started:latest' locally
latest: Pulling from docker/getting-started
9981e73032c8: Pull complete 
e5f90f35b4bc: Pull complete 
ab1af07f990a: Pull complete 
bd5777bb8f79: Pull complete 
a47abff02990: Pull complete 
d4b8ebd00804: Pull complete 
6bec3724f233: Pull complete 
b95ca5a62dfb: Pull complete 
Digest: sha256:b558be874169471bd4e65bd6eac8c303b271a7ee8553ba47481b73b2bf597aae
Status: Downloaded newer image for docker/getting-started:latest
cc167092ff76941a25fe51da25fbbfe6a0a70cc07171fa5f56707f3bf7383e6a

可以看到由于没有在本地找到docker/getting-started:latest镜像,Docker从远处Docker Hub注册表上pull下来。

我们用docker ps查看目前在运行的镜像实例(即容器):

(base) orion-orion@MacBook-Pro ~ % docker ps       
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                NAMES
cc167092ff76   docker/getting-started   "/docker-entrypoint.…"   29 minutes ago   Up 29 minutes   0.0.0.0:80->80/tcp   epic_lehmann

可以用docker stop终止镜像运行:

(base) orion-orion@MacBook-Pro ~ % docker stop cc167092ff76
cc167092ff76
(base) orion-orion@MacBook-Pro ~ % docker ps   
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

docker images查看有哪些本地镜像:

(base) orion-orion@MacBook-Pro ~ % docker images                                 
REPOSITORY               TAG       IMAGE ID       CREATED       SIZE
docker/getting-started   latest    157095baba98   4 weeks ago   27.4MB

3. 用Docker打包Python环境

接下来我们看如何用Docker打包一个Python环境。
首先,我们编写一个Python小Demo:

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10, 10, 0.01)
y = x**2
plt.plot(x, y)
plt.savefig("/out/quad.png") 
# 此处的/out为容器内的绝对路径,无需手动创建,
# 后面我们会设置挂载参数自动生成该目录

然后我们编辑好requirements.txt

numpy==1.21.3
matplotlib==3.4.3  

再编辑好Dockerfile:

# syntax=docker/dockerfile:1

FROM python:3.9-slim-buster

WORKDIR /draw_quad

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt 

COPY . .

CMD [ "python3", "draw_quad.py"]

我们来细细看Dockerfile每一部分。

首先,# syntax是指解析器指令。这里使用docker/dockerfile:1,即始终指向版本1语法的最新版本。

之后,我们需要告诉Docker我们在应用中使用什么基础镜像。由于Docker镜像可以从其它镜像继承,因此我们并不构建自己的基础镜像,而是使用官方的Python镜像,即FROM python:3.9-slim-buster

然后我们建立一个工作目录/draw_quad,即后续命令的默认执行路径。这样我们后面就不必输入完整的文件路径,而是可以使用基于工作目录的相对路径。如COPY requirements.txt requirements.txt其实是将requirements(第一个参数)复制到到工作目录中(第二个参数)。

接着,我们将requirements.txt 放入镜像后,就可以使用RUN命令来执行pip3 install了,这和我们在本地安装的经验完全相同,不过这次是将模块安装到镜像中。

此时,我们有了一个基于Python 3.9的镜像,并且已经按照了我们的依赖项。下一步我们继续用COPY
命令将源代码添加到镜像中,即DockerFile中的COPY . .

之后,我们还需要Docker当我们的镜像在容器中运行时我们想要执行什么命令,即CMD [ "python3", "draw_quad.py"]

最终的项目目录如下:

draw
|____ draw_quad.py
|____ requirements.txt
|____ Dockerfile

然后我们就可以构建docker镜像了(用--tag参数指定镜像名称):

(base) orion-orion@MacBook-Pro draw % docker build --tag draw .                 
[+] Building 9.1s (14/14) FINISHED                                                                                             
 => [internal] load build definition from Dockerfile                                                                      0.0s
 => => transferring dockerfile: 37B                                                                                       0.0s
 => [internal] load .dockerignore                                                                                         0.0s
 => => transferring context: 2B                                                                                           0.0s
 => resolve image config for docker.io/docker/dockerfile:1                                                                4.9s
 => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:443aab4ca21183e069e7d8b2dc68006594f40bddf1b15bbd83f5137bd  0.0s
 => [internal] load build definition from Dockerfile                                                                      0.0s
 => [internal] load .dockerignore                                                                                         0.0s
 => [internal] load metadata for docker.io/library/python:3.9-slim-buster                                                 3.9s
 => [1/5] FROM docker.io/library/python:3.9-slim-buster@sha256:830e161433edfe047a23ebc99c12ee0eb1dc0a50e6b5f1c98e869ac27  0.0s
 => [internal] load build context                                                                                         0.0s
 => => transferring context: 594B                                                                                         0.0s
 => CACHED [2/5] WORKDIR /draw_quad                                                                                       0.0s
 => CACHED [3/5] COPY requirements.txt requirements.txt                                                                   0.0s
 => CACHED [4/5] RUN pip3 install -r requirements.txt                                                                     0.0s
 => [5/5] COPY . .                                                                                                        0.0s
 => exporting to image                                                                                                    0.0s
 => => exporting layers                                                                                                   0.0s
 => => writing image sha256:18f3a254f4ce46faa17142ece6bfd442e9157e79510ca60a789ab4d4b1a12498                              0.0s
 => => naming to docker.io/library/draw                                        0.0s

我们输入docker images命令可以看到名称为draw的镜像已经构建成功。

(base) orion-orion@MacBook-Pro Draw % docker images
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
draw                     latest    f1fc30becc34   46 seconds ago   251MB

然后就可以运行镜像了(包含文件系统挂载操作):

(base) orion-orion@MacBook-Pro draw % docker run -d -v ${PWD}/out:/out draw
0e04d81d254fcd963924ee2492b82a6c895789525f09943b43ce0b46ac0d63a9

注意,${PWD}/out为宿主机的目录,意思为当前目录下的out文件夹,如果不存在则会自动为我们创建。/out为该容器中的绝对路径,在容器启动会自动创建/out目录。

我们可以看到,quad.png成功在宿主机当前目录下的out文件中生成:

(base) orion-orion@MacBook-Pro draw % ls out           
quad.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK