Docker数据管理:数据卷挂载和绑定挂载方法
引言
Docker主要有三种数据的管理方式:数据卷(Volumes)、绑定挂载(Bind Mounts)以及tmpfs(内存文件系统)挂载。数据卷是 Docker 管理的数据生命周期,通常用于持久化数据;绑定挂载是将宿主机上的目录直接挂载到容器中,适用于需要访问宿主机文件系统的情况;tmpfs 则是在内存中创建临时文件系统,速度快但数据易丢失。本次将主要介绍数据卷挂载与绑定挂载,这两种方法是持久化数据最常用的选择。如果能够很好的理解这些方法对于高效管理Docker容器中的数据十分重要。
基础知识:
要深入了解这两种数据管理方式,我们先来了解一些基本概念
- 持久化数据:指的是在容器被删除后仍然保存的数据。
- 容器:容器是一种软件打包技术,它把应用程序及其所有依赖项(如代码、运行时库、配置文件等)打包在一起,形成一个独立、可移植的运行环境。
- 容器镜像:是一种打包了应用程序及其所有依赖的二进制数据,是可执行的软件包,用于在容器化环境中部署应用程序。
- tmpfs挂载:一种临时文件存储系统,存储在内存中,容器停止后数据会消失。
数据卷(Volumes)
数据卷的定义
数据卷是 Docker 管理的主机文件系统的一部分,是一个供Docker容器使用的特殊目录,允许在容器和主机之间持久化和共享数据。它绕过 Docker 的联合文件系统(UFS),使得对数据卷的修改会立即生效,即使容器被删除,数据也不会丢失。(默认位于/var/lib/docker/volumes目录中)。如非Docker进程不应修改/var/lib/docker/volumes目录中的内容,以确保数据的一致性和完整性。数据卷是在Docker中持久化数据最佳的方法。
创建和使用数据卷
1、创建数据卷:
docker volume create your_volume
2、使用数据卷运行容器(包含两种方式):
1、挂载命名Volume:docker run -d --name yourapp -v your_volume:/app/data[:options] yourimage
2、挂载匿名Volume:docker run -d --name yourapp -v /app/data[:options] yourimage
[:options]参数解释:options为数据卷权限控制参数,有两种模式 1、:rw(读写模式,默认)2、:ro(只读模式)下文有介绍。
**建议:**尽量避免使用第二种匿名镜像挂载方法,它们难以管理和引用,当创建它们的容器被删除后(除非特殊处理),这些 Volume 可能会变成“孤儿”,占用磁盘空间。始终命名为 Volume。
优点
- 由 Docker 管理,更易备份、恢复和迁移
- 性能高(某些情况下性能高于绑定挂载)、跨容器数据共享更加方便,可在多个容器之间共享
- 数据卷的内容可以由其他容器或 Docker 外部的程序安全地访问
- 数据与宿主机的特定路径解耦,提高了应用的可移植性
- 如果挂载某个空的Volume到容器内一个已经存在并且包含内容的目录,Docker 会自动将容器目录的内容复制到 Volume 中(仅在 Volume 为空且首次挂载时发生)。这对于初始化数据库等场景非常有用。
实用技巧(适合熟练用户)
- 使用带标签的数据卷(便于管理)
docker volume create --label project=yourproject your_volume
- 使用驱动程序创建网络存储数据卷
docker volume create --driver nfs --opt o=addr=192.168.0.3,rw your_nfs_volume
绑定挂载(Bind Mounts)
绑定挂载的定义
绑定挂载是指将宿主机上的一个已存在的文件或目录直接映射到容器内部的指定路径。这种方式简单直接,方便在宿主机和容器间共享文件,尤其在开发环境中映射源代码非常常见。
使用绑定挂载
使用绑定挂载运行容器:
docker run -d --name myapp -v /host/path:/container/path[:options] yourimage
优点
- 性能高
- 主机上的文件立即对容器可见
- 无需预先创建卷,直接使用宿主机上已有的文件或目录即可,更加便捷。
- 能够实现宿主机和容器之间的数据实时同步,非常适合需要频繁更新数据的场景,如日志文件或配置文件等。
- 允许将宿主机上的任意文件或目录挂载到容器内的任何路径,提供了非常大的灵活性。
- 在开发环境中,绑定挂载可以让代码更改实时反映在容器中,无需每次都重新构建镜像,极大提高了开发效率。
这中间有几个需要注意的点:
1、-v后面的路径必须是宿主机上的**绝对路径,**使用绝对路径可以避免与相对路径混淆
2、在Docker23.0版本之前的版本,如若宿主机的路径不存在,Docker可能会自动创建宿主机的目录,但在Docker23.0之后的版本,这通常会报错,最好的方式是手动提前创建好宿主机的路径。
3、权限控制主要通过在挂载路径后添加选项 :rw(读写,默认)或 :ro(只读),即/host/path:/container/path后面的options参数。
4、在Windows系统上,路径的格式可能需要调整:
由于Windows系统表示绝对路径的方式与Linux系统表示绝对路径的方式有所不同,Windows系统中表示路径的方式用的是反斜杠即“\”表示,而Linux系统中由“/”**表示,所以命令就变成了下面两种表示方式:
Windows系统:
docker run -d --name myapp -v C:\Users\YourName\project:/app[:options] yourimage
Linux系统/Mac系统上:
docker run -d --name myapp -v /host/path:/container/path[:options] yourimage
VOLUME 定义匿名卷
在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME /data
执行这条命令会在容器运行时创建一个匿名卷,挂载到容器的/data目录下。
ARG 构建参数配置VOLUME (适合熟练用户)
我们可以使用ARG构建参数来配置VOLUME匿名卷的路径、名称等信息:
ARG DATA_PATH=/data
VOLUME ${DATA_PATH}
**注意:**ARG构建参数是在构建镜像时进行传递的,要通过–build-arg命令来进行创建,ARG所设置的构建环境的环境变量在将来容器运行时是不会存在这些环境变量的这就为我们设置某些变量提供了很大的便利。
docker build --build-arg DATA_PATH=/host/path:/container/path[:options] -t yourimage
使用docker compose管理数据卷挂载和绑定挂载
docker compose的出现使数据卷挂载和绑定挂载的使用变得简单许多,通过在 docker-compose.yml 文件中定义和管理卷,你可以根据需要轻松创建、更新和删除卷,而无需使用 Docker 命令手动管理它们。这种简化的流程让您可以专注于开发和部署应用程序,下面是用yaml配置文件实现数据卷挂载以及绑定挂载的方法:
version: '3.8'
services:
web:
image: nginx
volumes:
- web_data:/var/www/html
- ./nginx.conf:/etc/nginx/nginx.conf:rw #rw表示可读可写挂载,默认权限
database:
image: mysql
volumes:
- db_data:/var/lib/mysql
volumes:
web_data:
db_data:
o: bind
该示例中表示:定义了一个名为web_data的命名卷、一个名称为db_data的命名卷和一个权限为可读可写的绑定挂载,并将它们挂载在web容器名为nginx的特定目录下,随后,它将名称为web_data的卷挂载在web容器的/var/www/html目录下,将名称为db_data的卷挂载到database容器名为mysql的**/var/lib/mysql**目录下。
我们可以使用以下命令来启动服务:
docker-compose up -d
高级配置(适合熟练用户)
version: '3'
services:
db:
image: postgres
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
external: true #表示是否属于外部卷,true表示是 false表示否
比如上面的示例中创建了一个名为db_data的外部卷,并将其挂载在服务器的/var/lib/postgresql/data目录下。
volumes:
myvolume:
driver: local
driver_opts:
type: nfs #表示卷驱动类型,主要类型有3种(预定义、显式、自动)
o: addr=192.168.0.3,ro #表示卷驱动IP地址
device: ":/path/to/dir" #表示驱动安装位置
数据卷挂载与绑定挂载实际应用场景
1、需要使用数据卷挂载的情况
- 对于需要在多个容器间共享的数据,使用数据卷挂载
- 使用docker compose来管理多容器应用及它的数据卷
- 对于主要由应用程序写入的数据,无需频繁与主机文件系统进行交互时
- 应用程序需要跨不同的操作系统环境部署的时候
2、需要使用绑定挂载的情况
- 在进行程序开发时需要本地调试代码方便实时修改的情况
- 需要将宿主机的文件以只读(:ro)方式挂载到容器中的情况
- 需要访问宿主机特定资源的情况,如 Docker Socket (/var/run/docker.sock),但是需要特别注意安全风险。
- 对读写性能有极高要求,希望直接在主机文件系统上操作的情况
实际使用建议
- 为数据卷添加命名标签,方便后续的分类和管理
- 在实际生产环境中推荐使用外部存储方案,将重要数据与系统存储分开
- 经常将重要数据比如数据库、日志等进行备份,并要测试恢复过程
- 始终使用命名Volumes,避免使用匿名Volumes
- 注意权限问题,尤其在使用绑定挂载时,确保容器内进程有权访问挂载点,并考虑 UID/GID 映射。
- 要经常制定备份策略,无论是绑定挂载还是 数据卷挂载,都需要可靠的备份机制。Volumes 通常更容易集成到备份流程中。
备份和恢复数据卷
- 备份数据卷
- 使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从主机挂载当前目录到容器的 /backup 目录。
docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
-
容器启动后,使用了 tar 命令来将 dbdata 卷备份为容器中 /backup/backup.tar 文件,也就是主机当前目录下的名为 backup.tar 的文件。
2、恢复数据卷
-
首先创建一个带有空数据卷的容器 dbdata2
docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
- 创建另一个容器,挂载 dbdata2 容器卷中的数据卷,并使用 untar 解压备份文件到挂载的容器卷中。
docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
- 验证是否成功恢复数据,可以再启动一个容器挂载同样的容器卷来查看
docker run --volumes-from dbdata2 busybox /bin/ls/dbdata
故障检查与排除
在我们进行数据卷和绑定挂载操作时,可能会遇到一些问题,如何进行解决呢,下面就列举一些常见的数据卷的挂载问题:
1、数据卷挂载后无法删除?
-
检查是否仍然有容器在使用该数据卷
-
使用“docker volume rm -f volume_name”命令强制删除该数据卷
2、绑定挂载好后不工作,容器内找不到数据?
-
确保宿主机路径存在并且检查是否是绝对路径,避免与其他路径混淆
-
检查绑定挂载的数据卷是否具有正确的权限
-
检查路径是否正确,(特别是在Windows系统环境中)
Windows路径正确格式:使用反斜杠“\\”,或双反斜杠“\\\\”表示 Windows读写权限问题:确保当前用户对挂载目录有足够的读写权限 3、数据未同步怎么办? -
确保挂载时在正确的路径中进行操作
-
检查挂载权限是否足够
-
对于所要挂载的数据卷确保没有其他进程能够直接修改“/var/lib/docker/volumes/”目录下的内容
总结:
数据卷是 Docker 生态系统中的一个重要组件,它使您能够存储和管理 Docker 容器生成的数据。有了 Docker 数据卷,即使在您删除或更新容器后,重要的应用程序数据也会持续存在,有助于保持应用程序的完整性和一致性。Docker Compose 提供了一种在 docker-compose.yml 文件中创建和管理卷的简化方法。这种方法简化了开发过程,确保了资源的高效利用。使用卷还能使开发变得灵活高效,Docker Compose 提供了各种与卷相关的命令,帮助你有效监督应用程序资源。利用这些命令,您可以轻松创建、检查和清理卷。无论选择哪种方法,确保数据的安全性和可访问性都应该是首要考虑的因素。
随着对Docker技术的熟悉程度的提升,我们能够使用更加便捷和高级的数据管理技术。持续不断的学习,才能使我们更加熟练的掌握Docker数据管理技术。