正如我们所说,机器学习工作流程对数据有很强的依赖。你需要数据集来训练模型,在长时间训练过程中可能会生成中间检查点,最终还需要保存训练好的模型文件。在使用容器时,了解数据如何处理非常重要,因为其默认行为不适合数据持久化。容器运行时,Docker 在只读镜像层之上创建了一个可写层。可以将镜像视为蓝图,容器则是根据该蓝图构建的运行实例。运行中的应用程序所做的任何更改,例如创建新文件、修改现有文件或下载数据,都会写入到这个容器特有的可写层。这里的重点是,这个可写层是临时的。它与单个容器实例的生命周期关联紧密。当容器停止并移除时(这经常发生,例如更新应用程序或仅仅清理资源时),这个可写层及其包含的所有数据都会被永久删除。想象一下,下载了一个大型数据集或完成了数小时的模型训练,结果却在容器移除时所有成果都消失了。这显然不适用于大多数机器学习任务。我们需要独立于容器生命周期持久化存储数据的方式。我们需要以下机制:数据持久化: 确保数据集、日志、模型检查点和最终模型在容器重启或移除后仍然存在。数据共享: 让宿主机的数据在容器内部可用(例如开发阶段的源代码或本地数据集)。数据解耦: 将应用程序逻辑(在容器镜像中)与它操作的数据分离。Docker 提供了两种主要机制来实现这些目标,它们是容器化机器学习应用中数据管理的主要方式:绑定挂载: 这些机制将宿主机文件系统中的文件或目录直接映射到容器中。在容器中进行的更改会反映到宿主机上,反之亦然。卷: 这些是由 Docker 自身管理的存储区域。它们存储在宿主机文件系统中的特定部分,由 Docker 管理,但其确切位置通常无需直接交互。卷是持久化容器生成数据的推荐方式。下图展示了容器的临时层与这些持久化存储选项之间的关系。digraph G { rankdir=LR; node [shape=box, style=filled, fontname="Helvetica"]; subgraph cluster_host { label="宿主机文件系统"; style=filled; color="#e9ecef"; host_dir [label="宿主机目录\n(/path/to/data)", fillcolor="#a5d8ff"]; docker_managed [label="Docker管理区域\n(例如:/var/lib/docker/volumes)", fillcolor="#96f2d7", shape=folder]; } subgraph cluster_container { label="容器"; style=filled; color="#dee2e6"; container_fs [label="容器可写层\n(临时 - 移除后丢失)", fillcolor="#ffc9c9"]; container_mount_bind [label="挂载点\n(/data_bind)", fillcolor="#a5d8ff"]; container_mount_volume [label="挂载点\n(/data_volume)", fillcolor="#96f2d7"]; } container_fs -> container_mount_bind [style=invis]; // ensure layout container_fs -> container_mount_volume [style=invis]; // ensure layout edge [fontname="Helvetica", fontsize=10]; host_dir -> container_mount_bind [label="绑定挂载\n(直接连接)"]; docker_managed -> container_mount_volume [label="卷\n(Docker管理)"]; {rank=same; host_dir; docker_managed;} {rank=same; container_fs; container_mount_bind; container_mount_volume;} }容器可写层中的数据在容器移除时会丢失。绑定挂载直接链接到宿主机文件系统,而卷提供Docker管理的持久化存储。理解容器内部临时存储与外部挂载持久化存储之间的这种区别,是有效管理容器化机器学习项目中的数据集、模型及其他文件的第一步。在后续章节中,我们将详细研究绑定挂载和卷,讨论它们在不同机器学习场景中的用例、优点和缺点。