Docker 容器最容易与无状态应用程序一起使用,因为它们的文件系统本质上是短暂的。当容器停止、崩溃或被替换时,对容器环境所做的更改将丢失。
您可以通过将卷附加到容器来Dockerize 有状态应用程序,例如数据库和文件服务器。卷提供独立于单个容器的持久存储。您可以在发生故障后将卷重新附加到不同的容器,或者使用它们同时在多个容器之间共享数据。
在本文中,您将了解什么是卷以及它们支持的用例。我们还将介绍一些将卷与 Docker 和 Docker Compose 结合使用的实际示例。
什么是 Docker 卷?
卷是一种在容器外存储数据的机制。所有卷都由 Docker 管理并存储在主机上的专用目录中,通常/var/lib/docker/volumes
用于 Linux 系统。
卷挂载到容器中的文件系统路径。当容器写入卷挂载点下方的路径时,更改将应用于卷而不是容器的可写映像层。如果容器停止,写入的数据仍然可用——因为卷单独存储在您的主机上,它可以重新安装到另一个容器或使用手动工具直接访问。
卷适用于 Linux 和 Windows 容器。有几种不同的驱动程序可用于在不同的服务中存储卷数据。Docker 主机上的本地存储是默认设置,但 NFS 卷、CIFS/Samba 共享和设备级块存储适配器可作为备选方案。第三方插件也可以添加额外的存储选项。
绑定装载与 Docker 卷
绑定挂载是让容器访问主机上的文件和文件夹的另一种方式。他们直接将主机目录挂载到您的容器中。对目录所做的任何更改都将反映在挂载的两侧,无论修改源自主机还是容器内。
绑定挂载最适合用于短期临时存储。它们在开发工作流程中很方便。例如:绑定将您的工作目录挂载到容器中会自动同步您的源代码文件,使您可以立即测试更改而无需重建 Docker 映像。
当您为可操作的容器提供永久存储时,卷是更好的解决方案。因为它们由 Docker 管理,所以您无需在主机上手动维护目录。数据被意外修改的可能性较小,并且不依赖于特定的文件夹结构。卷驱动程序还提供更高的性能和将更改直接写入远程位置的可能性。
何时使用 Docker 卷?
卷旨在支持有状态 Docker 容器的部署。当容器需要持久存储以永久保存新文件和修改后的文件时,您将需要使用卷。
典型的卷用例包括以下内容:
- 数据库存储– 您应该将卷挂载到数据库(如 MySQL、Postgres 和 Mongo)使用的存储目录。这将确保您的数据在容器停止后仍然存在。
- 应用程序数据——应用程序生成的数据,例如文件上传、文档和个人资料照片,应该存储在一个卷中。
- 基本缓存——考虑使用一个卷来保存任何缓存的内容,这将花费大量时间来重建。
- 方便的数据备份– Docker 的集中式卷存储可以通过将/var/lib/docker/volumes镜像到另一个位置来轻松备份容器数据。社区工具和Docker Desktop 扩展可以自动化该过程,提供比手动复制单个绑定挂载目录更简单的体验。
- 在容器之间共享数据——Docker 卷可以同时挂载到多个容器。容器可以实时访问其邻居所做的更改。
- 写入远程文件系统——当您希望容器写入远程文件系统和网络共享时,您需要使用卷。这可以简化与 LAN 资源交互的应用程序的工作流程。
您不需要将卷挂载到没有可写文件系统路径或仅存储一次性内容的容器。作为一般规则,当您的容器写入数据时创建一个卷,如果它丢失会导致中断。
示例:使用 Docker 卷
让我们看看卷是如何工作的。您可以通过在调用时设置标志来启动带有卷的容器。-v``docker run
以下命令启动一个新的 Ubuntu 22.04 容器并将您的终端连接到它 ( ),准备好在以下步骤中运行演示命令。名为的卷安装到容器内部。现在运行命令:-it``demo_volume``/data
$ docker run -it -v demo_volume:/data ubuntu:22.04
列出容器目录的内容:/data
$ ls /data
路径存在,说明卷已经挂载成功,但是还没有创建文件。
添加一个包含任意内容的测试文件:
$ echo "foobar" > /data/foo
$ cat /data/foo
foobar
接下来,通过按 Ctrl+C 或运行从您的容器中分离:exit
$ exit
exit
容器将立即停止,因为其中没有其他进程在运行。
现在,启动一个附加相同卷的新容器:
$ docker run -it -v demo_volume:/app alpine:latest
该卷已经存在,因此 Docker 将重用它而不是创建一个新卷。这一次,卷被挂载到容器内的不同路径,但是当您列出路径的内容时,您将看到第一个容器创建的文件:demo_volume
$ cat /app/foo
foobar
Docker 在第一个容器停止后保留卷的内容,允许它与您的替换容器一起重用。
手动创建和链接卷
上面的这个例子演示了 Docker 如何在您第一次引用新名称时自动创建卷。您可以使用以下命令提前手动创建卷:docker volume create
$ docker volume create app_data
app_data
然后可以像以前一样将该卷安装到您的容器中:
$ docker run -it -v app_data:/app alpine:latest
填充卷内容
您可以将卷挂载到已包含数据的容器路径。发生这种情况时,Docker 会将现有容器数据复制到新卷中。这可以防止意外的数据丢失。使用该卷的其他容器也将看到从相邻挂载点填充的内容。
将卷安装为只读
默认情况下,卷以读写模式挂载。要以只读模式安装卷,请将或作为命令标志中的第三个字段:ro``readonly``docker run``-v
$ docker run -it -v app_data:/app:ro alpine:latest
容器将能够从挂载点读取卷的内容,但无法进行修改。当一个卷在多个容器之间共享时,这是理想的,只有其中一些容器需要执行写入。
具有只读挂载的容器中的写入操作将失败并出现错误:
$ echo "foo" > /app/bar
/bin/sh: can't create /app/bar: Read-only file system
💡您可能还喜欢:
容器启动时重用卷
有时您可能想要启动一个新容器,其卷与主机上的现有容器相同。您可以使用自动包含另一个容器的卷,而不是重复所需的标志列表:-v``--volumes-from
# Create the first container
$ docker run -d --name db -v app_data:/data database-image:latest
# Create the second container
$ docker run -d --name backup --volumes-from db backup-image:latest
Docker 将挂载所有已附加到现有容器的卷。相同的目标路径将用于将卷装载到新容器中。
当您备份现有容器的卷时,此功能很有用。您可以轻松地将目标容器的卷装载到运行专用备份映像的新容器中。
在 Dockerfile 中使用卷
Docker 允许镜像使用Dockerfile 指令定义卷挂载点。当容器从镜像启动时,Docker 会自动为 Dockerfile 中列出的挂载点创建新卷。VOLUME
以下 Dockerfile 将始终将一个卷挂载到容器内部,即使您在没有标志的情况下调用也是如此:/app_data``docker run``-v
FROM ubuntu:22.04
VOLUME /app_data
您仍然可以手动将新的或现有的卷安装到指令引用的路径。该标志会覆盖 Dockerfile 的内容:VOLUME``-v
$ docker run -v custom_volume:/app_data app-image:latest
该指令可确保在用户启动新容器时始终保留关键路径。但是,应该谨慎对待它,因为用户不一定会期望这种行为。使用删除了为调试或测试目的创建纯粹的临时容器的选择。VOLUME``VOLUME
与 Docker 卷交互
Docker CLI 包括一组用于与主机上的卷进行交互的命令。
列出所有卷:docker volume ls
$ docker volume ls
DRIVER VOLUME NAME
local app_data
local demo_volume
您将看到每个卷的名称及其支持的存储驱动程序。要访问有关特定卷的更多详细信息,请改用:docker volume inspect
$ docker volume inspect demo_volume
[
{
"CreatedAt": "2023-03-16T14:05:55Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/demo_volume/_data",
"Name": "demo_volume",
"Options": null,
"Scope": "local"
}
]
删除卷:docker volume rm
$ docker volume rm demo_volume
demo_volume
除非添加(force) 标志,否则无法删除当前安装到容器的卷:-f
$ docker volume rm app_data -f
最后,您可以使用 清理所有未使用的卷。该命令删除未安装到至少一个容器的卷。在修剪开始之前,您将看到确认提示。完成后,已释放磁盘空间总量将显示在您的终端中。docker volume prune
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Total reclaimed space: 6B
将卷与 Docker Compose 结合使用
卷也可以在Docker Compose中定义和使用。在您的文件中,添加一个顶级字段,列出要创建的卷,然后将您的卷装入该部分中的容器中:docker-compose.yml``volumes``services
services:
app:
image: app-image:latest
volumes:
- app_data:/data
volumes:
app_data:
当您运行时,Compose 会自动创建并装载您的卷。要使用现有卷,请将其添加到docker-compose.yml文件的部分并将标志设置为:docker compose up``volumes``external``true
volumes:
demo_volume:
external: true
关键点
Docker卷为您的容器提供持久存储。Docker 将卷中的数据分别管理到容器中。卷可以同时附加到多个容器,在它们安装到的容器停止后仍然可以访问,并且可以使用 Docker CLI 集中管理。
每当您的容器化应用程序需要永久存储文件系统更改时,就安装一个卷。存储在卷中的数据受到保护,不受容器故障和重启的影响,但对容器中任何其他路径的更改都将丢失。
寻找有关 Docker 及其功能的更多信息?查看我们的初学者教程,或浏览Spacelift 博客上的其他文章。
将软件打包为容器使其更具可移植性,从而消除环境之间的差异。您可以在笔记本电脑、生产环境和 CI/CD 基础设施中使用该容器。看看 Spacelift如何 使用 Docker 容器 在隔离环境中运行 CI 作业。