
想象一下,您完成了一个端到端的机器学习问题,并用最优模型得出了最佳解。但当您把代码交付给工程团队时,却发现能在您电脑上运行的代码,在他们的服务器上却跑不起来——这可能是因为操作系统不同、库版本不一致等原因。
尽管您已经十分认真努力,这样令人沮丧的情况仍可能发生。大多数开发者至少都会经历一次。那么解决方案是什么?这正是 Docker 大显身手的地方。借助 Docker,您可以为项目定义一个精确、一致的运行环境,确保无论底层环境或配置如何变化,您的代码都能顺利运行。
本教程将介绍 Docker 及其相关概念,并解释其对数据科学家的重要性。随后,本文将帮助您完成工具的安装,并通过示例引导您在下一个项目中使用它。最后——您还将了解在使用 Docker 时应遵循的行业通用最佳实践,并获得针对常见问题的解答。
什么是 Docker、容器与镜像?
Docker 是一个用于构建、运行和分发应用的平台。
容器 是轻量级、独立、可执行的打包单元,包含运行应用所需的一切:代码、运行时、库、环境变量和配置文件。
Docker 镜像 是只读文件,内含创建容器所需的全部指令。运行时会据此创建并启动新的容器。
Docker 帮助开发者将应用与其依赖一起打包到容器中,只要目标机器安装了 Docker,就可以运行该容器。
某种意义上,这就像您为新项目拿到了一台新机器:安装所需软件包、拷贝必要文件并运行脚本。您也可以把这台“新机器”运到别处。虽然这个比喻简单,但意思不难理解。
Docker 容器与虚拟机有何不同?
当我们定义了容器,您可能会想它与虚拟机有何不同,毕竟两者都能在同一台物理机器上运行多个隔离环境。
看看下面这张架构差异图,看看您能否找出不同之处。

图片作者自制
每个虚拟机都是一个隔离环境,可以运行不同的操作系统和配置。这也意味着每个虚拟机都需要完整的操作系统副本,会消耗大量资源。相较之下,容器化的应用在隔离环境中运行,但不需要完整的操作系统副本,因此更轻量、更高效。
虚拟机固然有用,但在分发应用方面,容器通常已经足够且更理想。
为什么数据科学家需要 Docker?
您可能会想,作为数据科学家,为什么还要学习 Docker?难道不是有 DevOps 团队负责基础设施吗?
这是个好问题——但即使有 DevOps 团队,Docker 对数据科学家仍然非常重要。下面来看看 Docker 的用处。
与 DevOps 团队的协作
有了 DevOps 团队,并不意味着使用 Docker 的好处就消失了;相反,它还能帮助弥合开发与运维之间的鸿沟。数据科学家可以用 Docker 打包代码,并交给 DevOps 团队进行部署与扩缩容。在更成熟的数据科学团队中,您很可能会这样做。
环境一致性与可复现性
数据科学家经常要处理复杂的依赖和配置,这些需要被正确设置并持续维护。为了获得相同的结果,环境必须保持一致。Docker 让数据科学家能够创建并共享一个包含所有必要依赖和配置的统一环境,其他人也能轻松复现。
可移植性
只要安装了 Docker,容器就能在任何环境中运行,包括笔记本电脑、服务器和云平台。这样数据科学家就可以在不同环境之间轻松迁移工作。
资源隔离
Docker 允许在同一台机器上运行多个容器,每个容器都有各自隔离的资源。这有助于数据科学家更高效地管理资源,并避免与其他应用发生冲突。当您同时进行多个机器学习项目时,这个特性尤为关键。
促进协作
Docker 让数据科学家可以将自己的工作打包成容器,分享给任何人,包括远程团队。协作是数据科学团队工作的关键,而 Docker 大大降低了协作的摩擦。
多数经验丰富的数据科学家都会认可:有了 Docker,数据科学家就能把精力集中在工作本身,而不用为底层基础设施操心。
Docker 教程:在下一个项目中使用 Docker
既然我们已经明确了数据科学家使用 Docker 的必要性,那就尽快上手吧。首先需要在本机安装 Docker,并熟悉常用命令。
在您的电脑或本地服务器上安装 Docker
Docker 可用于主流操作系统,如 Linux、Windows 和 Mac。安装过程很简单,最佳做法是参考官方文档。
如果您希望创建自己的镜像并将其推送到 Docker Hub(正如下文某些命令所示),需要在 Docker Hub 上创建一个账号。把 Docker Hub 想象成一个中心仓库,开发者可以在此存储并共享他们的 Docker 镜像。
熟悉常用 Docker 命令
在您的机器(或服务器)上完成 Docker 的安装后,下一步就是熟悉一些 Docker 命令。以下是您应参考的官方 Docker 文档中的命令列表。
为帮助您起步,我们梳理了十条最常用且您一定会用到的 Docker 命令。
- docker run:从镜像运行一个容器。-p 标志用于将主机上的端口映射到容器上的端口。例如,下面的命令将从“nginx”镜像运行一个容器,并将主机的 80 端口映射到容器的 80 端口。
docker run -p 80:80 nginx- docker ps:列出所有正在运行的容器。当同一台机器上运行多个隔离容器时,这个命令很有用。
docker ps- docker stop:停止一个正在运行的容器。
docker stop <container_id>- docker rm:用于移除一个已停止的容器。
docker rm <container_id>- docker images:列出主机上的所有镜像。在运行镜像以创建容器之前,这个命令可以帮助我们查看本地可用镜像。
docker images- docker rmi:移除一个镜像。
docker rmi <image_id>- docker build:从 Dockerfile 构建镜像。-t 标志用于为镜像命名,末尾的 . 指定构建上下文为当前目录。
docker build -t my_image .- docker exec:在一个正在运行的容器内执行命令。
docker exec -it <container_id> /bin/bash- docker pull:从镜像仓库(如 Docker Hub)拉取镜像。
docker pull <image_name>- docker push:将镜像推送到镜像仓库。
docker push <image_name>
现在我们已经学会了 Docker 的安装与常用命令,下一步就是将一个机器学习应用容器化。
想获得 Docker 认证吗?请查看我们的Docker 认证入门指南!
将简单的机器学习应用容器化
如果遵循一个简单的三步法,将任何机器学习应用容器化并不难。

图片作者自制。
为保持简单,我们以一个入门级的机器学习脚本为例,因为我们的目标是演示如何容器化一个脚本。示例将基于鸢尾花数据集构建一个简单的逻辑回归模型。
# Load the libraries
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# Load the iris dataset
iris = load_iris()
X = iris.data
y = iris.target
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Train a logistic regression model
clf = LogisticRegression()
clf.fit(X_train, y_train)
# Make predictions
y_pred = clf.predict(X_test)
# Print the accuracy of the model
accuracy_score = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy_score}')
1. 定义环境
要想在其他位置复现当前环境,您需要精确了解当前环境。最简单(也是最常见)的方法是创建一个 requirements.txt 文件,列出项目使用的所有库及其版本。
该文件的内容如下所示:
scikit-learn==1.2.0
注意:更复杂的机器学习应用会用到更多库,例如 NumPy、pandas、matplotlib 等。因此,创建 requirements.txt 文件会比直接安装单个库更合理(后文的行业最佳实践中会有更多说明)。
2. 编写 Dockerfile
接下来我们创建一个名为 Dockerfile 的文件,用于创建环境并在其中执行我们的应用。简单说,这就像是给 Docker 的“说明书”,指出环境应当是什么样、包含哪些内容,以及需要执行哪些步骤。
FROM python:3.9
WORKDIR /src
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python","iris_classification.py"]
这个 Dockerfile 使用官方的 Python 镜像作为基础镜像,设置工作目录,拷贝 requirements.txt 并安装依赖,拷贝应用代码,最后通过运行 python iris_classification.py 来启动应用。
3. 构建镜像
创建可复现环境的最后一步是构建镜像(也可理解为模板),它可以用于创建任意数量、配置相同的容器。
您可以在与 Dockerfile 同一目录下运行命令 docker build -t <image-name> . 来构建镜像。
现在,您已经将这个简单的机器学习应用容器化了。您可以使用 docker run 命令来创建容器,并在需要时停止它们。我们之前已经介绍过一些常用命令。
接下来,让我们把知识从基础提升到行业级标准。
使用 Docker 的行业通用最佳实践
掌握基础足以入门,但在实际工作中,遵循最佳实践至关重要。
尽量减少层数
Dockerfile 中的每条指令都会生成一个新层。层数过多会导致镜像体积增大、传输变慢。
请看下面的代码示例:
# Use the official Python image as the build image
FROM python:3.9
# Install the dependencies
RUN pip install pandas
RUN pip install matplotlib
RUN pip install seaborn
# Copy neccesary files
COPY my_script.py .
COPY data/ .
# Run the script
CMD ["python","my_script.py"]
您发现问题了吗?这里用了多条不必要的 run 和 copy 命令。我们可以这样改进:
# Use the official Python image as the build image
FROM python:3.9
# Install the dependencies using requirements.txt
COPY my_script.py requirements.txt data/ .
RUN pip install --no-cache-dir -r requirements.txt
# Run the script
CMD ["python","my_script.py"]
在这样的小文件里问题很明显,但您会惊讶地发现,我们常常写出比需要更臃肿的 Dockerfile。将功能相近或会修改同一文件的操作合并,是减少 Dockerfile 层数的简便方法。
使用官方镜像
官方镜像由镜像发布方维护和支持,通常被认为比其他镜像更稳定、更安全。
有时为了赶进度,我们会草率地使用非官方镜像。能用官方镜像时,请尽量将其作为自定义镜像的基础。
使用多阶段构建优化性能
Docker 的多阶段构建允许您在同一个 Dockerfile 中使用多个 FROM 指令。
我们可以在构建阶段使用较大的镜像来构建应用,然后把必要文件拷贝到更小的运行时镜像中。通过不包含不必要的文件,我们不仅减少了最终镜像的体积,优化了性能,也提升了应用的安全性。
下面通过一个行业中反复使用的示例来说明:
# Use the official Python image as the build image
FROM python:3.9 AS build
# Set the working directory
WORKDIR /app
# Copy the requirements.txt file
COPY requirements.txt ./
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the application files
COPY . .
# Train the model
RUN python train.py
# Use the official Alpine Linux image as the runtime image
FROM alpine:3
# Set the working directory
WORKDIR /app
# Copy the model files from the build image
COPY --from=build /app/models /app/models
# Copy the requirements.txt file
COPY --from=build /app/requirements.txt /app
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Run the application
CMD ["python","predict.py"]
拆解来看,首先使用官方 Python 镜像作为构建镜像,并在该阶段安装所有依赖。
运行 train.py 后,我们将生成的模型文件和 requirements.txt 复制到更小的 Alpine Linux 运行时镜像,用于运行应用。通过使用多阶段构建,并且不在最终镜像中包含构建依赖和 Python 解释器,我们有效缩小了最终镜像的体积。
使用卷(volume)持久化数据
容器内的数据在容器停止并被删除后将不可用,但有时您需要保留实验结果以备后用,或者希望在多个容器之间共享数据。
使用 volume 指令可以确保数据保存在容器外部。下面是一个示例:
# Use the official Python image as the base image
FROM python:3.9
# Set the working directory
WORKDIR /app
# Copy the requirements.txt file
COPY requirements.txt ./
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application files
COPY . .
# Create a directory for storing data
RUN mkdir /app/data
# Define a volume for the data directory
VOLUME /app/data
# Run the application
CMD ["python","main.py"]
组织与版本化 Docker 镜像
当您开始使用多个 Docker 镜像时,管理就会变得混乱,因此有必要进行组织。尽管各组织有各自的做法,但我们可以概括一些常见的镜像管理实践:
- 为每个镜像遵循一致的命名规范。例如使用 <registry>/<organization>/<image>:<version> 的格式。这有助于在仓库中识别镜像及其版本。
- 遵循镜像版本管理的实践至关重要,以便在必要时能够回滚。您已经看到版本如何体现在命名规范中,版本号可以扩展为 主版本>.<次版本>.<修订版本>。
- 使用有意义的标签(如 latest、staging、production)为镜像打标签,也有助于组织和管理。这样可以快速识别用于不同环境和部署流水线阶段的镜像。
建议与您所在组织达成一致,整个团队都应遵循相同的规范。
结语
本文介绍了数据科学家如何借助 Docker 等工具创建可复现的代码与应用。从阐述 Docker 对数据科学家的重要性、安装指引到常用命令,再到通过示例将机器学习应用容器化,以及在使用 Docker 时应遵循的行业最佳实践。
如需进一步学习,您可以参加我们的Docker 入门课程,其中涵盖许多基础要点。如果您正从事相关领域的工作,也可以考虑获取Docker 认证。
多数数据科学家往往专注于统计、数学、机器学习、深度学习和编程等核心技能,却忽视了业界期望遵循的软件工程最佳实践。
如果您想夯实数据科学核心能力,请查看Python 数据科学家学习路径,其中包含项目驱动的引导式学习。或者,如果您需要强化软件工程技能,可以学习面向数据科学家的 Python 软件工程课程,涵盖模块化、文档编写与自动化测试等关键概念。
面向数据科学家的 Docker 常见问题
数据科学家是否应该学习 Docker?
学习 Docker 对数据科学家很有帮助,因为它可以轻松管理依赖与环境,确保代码在不同系统上表现一致。这也意味着他们不必完全依赖 DevOps 团队。
如何在 Docker 容器中使用 Jupyter Notebook?
要在 Docker 容器中使用 Jupyter Notebook,类似上面的教程,您可以新建一个 Dockerfile,然后使用 RUN 命令安装 Jupyter,并通过 CMD 命令启动 Jupyter Notebook 服务。或者,您也可以使用 Docker Hub 上 预构建的镜像(已包含 Jupyter)。这里有一份使用 Jupyter Notebook 的详细指南,也包括通过 Docker 的用法。
如何通过 Docker 分享我的数据科学项目?
您可以将镜像推送到 Docker Hub 等容器镜像仓库,从而用 Docker 分享数据科学项目。之后,其他人即可拉取该镜像并在其环境中运行项目。