一文教会你用Docker打包Python运行环境

 更新时间:2022年05月14日 08:26:34   作者:orion-orion  
Docker提供了容器级别的资源隔离,由于Python的外部依赖管理中存在的问题,我们通常会使用virtualenv来对不同的项目创建其唯一的依赖环境,下面这篇文章主要给大家介绍了如何通过一篇文章教会你用Docker打包Python运行环境的相关资料,需要的朋友可以参考下

前言

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

1. Docker基础

1.1 Docker架构

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

其中,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

参考

总结

到此这篇关于用Docker打包Python运行环境的文章就介绍到这了,更多相关Docker打包Python环境内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mysql 在 Docker 中的时区问题记录

    Mysql 在 Docker 中的时区问题记录

    Mysql 时区一般是跟着系统走的,而在 Docker 中安装 Mysql 默认时区是 UTC,下面介绍,创建Docker容器前、后,分别如何设置 Mysql 时区,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • 连接docker里面的mysql失败解决方法

    连接docker里面的mysql失败解决方法

    这篇文章主要介绍了连接docker里面的mysql失败解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)

    idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)

    使用docker镜像,可以快速地部署和运行应用程序,而无需担心环境差异、依赖项问题等,本文主要介绍了idea使用docker生成镜像,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • 解决Docker x509 insecure registry的问题

    解决Docker x509 insecure registry的问题

    这篇文章主要介绍了解决Docker x509 insecure registry的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • docker镜像导入导出的两种方法

    docker镜像导入导出的两种方法

    本文主要介绍了docker镜像导入导出的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • docker安装RocketMQ的实现步骤

    docker安装RocketMQ的实现步骤

    本文主要介绍了docker安装RocketMQ的实现步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • MySQL容器中docker-entrypoint-initdb.d目录的使用

    MySQL容器中docker-entrypoint-initdb.d目录的使用

    这篇文章主要介绍了MySQL容器中docker-entrypoint-initdb.d目录的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • 解决Docker Image镜像无法删除问题的方法

    解决Docker Image镜像无法删除问题的方法

    这篇文章主要给大家介绍了关于如何解决Docker Image镜像无法删除问题的方法,文中通过示例代码将解决的方法介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • docker安装sentinel的实现示例

    docker安装sentinel的实现示例

    本文主要介绍了docker安装sentinel的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12
  • docker安装RabbitMQ详细步骤

    docker安装RabbitMQ详细步骤

    大家好,本篇文章主要讲的是docker安装RabbitMQ详细步骤,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01

最新评论