一、上期回顾

每天半小时,轻松学Docker第五篇:Docker 容器管理


二、什么是卷?

Docker采用了在宿主机与容器之间,或容器与容器之间进行文件/目录的映射来解决这些问题。为此,Docker引入了“卷”(volume)机制和“绑定挂载”(bind mounts)。卷由Docker管理,非Docker进程不应该修改卷文件系统中的内容,卷是在Docker中保留数据的最佳方式。Docker提供了对卷的创建、列表、详情、删除命令。 

绑定挂载优点是具有较好的性能,缺点是它们依赖于具有特定目录结构的宿主机文件系统。如果读者正在开发新的Docker应用程序,请考虑使用命名的卷。


三、卷的创建

Docker Volume Create 命令详解

命令格式:

docker volume create [OPTIONS] [VOLUME]

功能:
创建一个新的数据卷。数据卷用于持久化存储和容器间共享数据。


参数说明
参数 缩写 说明
--driver -d 指定卷驱动名称。默认值为 local(使用宿主机的本地文件系统)。
• 官方卷驱动文档:https://docs.docker.com/storage/volumes/
--label 为卷设置元数据(标签),用于对卷进行分类或标记。
--name 指定卷的名称
• 重要:当使用了 --name 参数时,可以省略命令末尾的 [VOLUME] 参数,两者的作用完全相同。
--opt -o 指定卷驱动的选项参数。这些选项因驱动而异(例如,对于 local 驱动,可以设置设备类型、文件系统等)。

[VOLUME] 参数说明
  • [VOLUME] 参数代表要创建的卷名称

  • 如果既没有使用 --name 选项,也没有在命令末尾指定 [VOLUME],Docker 会创建一个匿名卷,并为其生成一个随机的、唯一的名称

  • 卷名称必须在所有 Docker 卷中是唯一的。

root@debase:~# docker volume create my-vol1
my-vol1
root@debase:~# docker volume create --name my-vol2
my-vol2

四、卷列表查看

Docker Volume LS 命令详解

命令格式:

docker volume ls [OPTIONS]

功能:
列出当前 Docker 环境中的所有数据卷。


命令示例与输出解析

执行命令:

docker volume ls

典型输出:

root@debase:~# docker volume ls
DRIVER    VOLUME NAME
local     2ca4997ef5fd25d79528143b678f442ad3f5d672aeaccb99a77c4a42f156cceb
local     8b93eed1ae5756093efb497eb1776d71cf8b688be860749a97ec335c741f61c4
local     9b28768f72fee829dfd9d79c7f3fd0e397575ddeaf4bda78da692a73e011b566
local     5567a9a396cbd723fc1b61b65c3f4b8ebe6b88b3d82a310a0608414da43b6967
local     ea1e74d7322e2452f88bbc696496bd222796c5e677413d7bc4b83dd149641f29
local     ec5104b8730b5b0cf7268d7c15099af5a5e338874a0f7b90b367f71403f644d1
local     f25d818354514eacad8a9c0f2c2cf1c955b269d4c1aa54594f6640a42582392d
local     fc5116202752352927aab83e93bc750a19f50e856667005238ef927dd1bd82bf
local     my-vol1
local     my-vol2

输出字段说明:

字段 说明
DRIVER 创建该卷时使用的卷驱动
VOLUME NAME 卷的唯一名称

输出内容分析:

  1. 匿名卷:

    • 前两个卷的名称是一长串随机哈希值(如 2ba6c99d9d1c...)。

    • 这些是匿名卷,由 Docker 在未指定名称时自动生成。

    • 它们的卷驱动也是 local

  2. 具名卷:

    • 最后两个卷 my-vol1 和 my-vol2 是用户通过 docker volume create [卷名] 命令创建的具名卷

    • 从输出中可以清楚地看到,这些具名卷使用的卷驱动同样是默认的 local 驱动。


常用可选参数
参数 说明
--filter 或 -f 使用过滤器来列出符合条件的卷。例如:-f name=my-vol
--format 使用 Go 模板格式化输出内容。例如:--format "{{.Name}} ({{.Driver}})"
--quiet 或 -q 仅显示卷的名称,不显示表头和其他信息。

使用示例:

  1. 仅显示卷名:

    docker volume ls -q
    
    root@debase:~# docker volume ls -q
    2ca4997ef5fd25d79528143b678f442ad3f5d672aeaccb99a77c4a42f156cceb
    8b93eed1ae5756093efb497eb1776d71cf8b688be860749a97ec335c741f61c4
    9b28768f72fee829dfd9d79c7f3fd0e397575ddeaf4bda78da692a73e011b566
    5567a9a396cbd723fc1b61b65c3f4b8ebe6b88b3d82a310a0608414da43b6967
    ea1e74d7322e2452f88bbc696496bd222796c5e677413d7bc4b83dd149641f29
    ec5104b8730b5b0cf7268d7c15099af5a5e338874a0f7b90b367f71403f644d1
    f25d818354514eacad8a9c0f2c2cf1c955b269d4c1aa54594f6640a42582392d
    fc5116202752352927aab83e93bc750a19f50e856667005238ef927dd1bd82bf
    my-vol1
    my-vol2
  2. 过滤出名称中包含 "my" 的卷:

    docker volume ls -f name=my
    
    root@debase:~# docker volume ls -f name=my
    DRIVER    VOLUME NAME
    local     my-vol1
    local     my-vol2
  3. 自定义格式输出:

    docker volume ls --format "Volume: {{.Name}}\tDriver: {{.Driver}}"
    
    root@debase:~# docker volume ls --format "Volume: {{.Name}}\tDriver: {{.Driver}}"
    Volume: 2ca4997ef5fd25d79528143b678f442ad3f5d672aeaccb99a77c4a42f156cceb        Driver: local
    Volume: 8b93eed1ae5756093efb497eb1776d71cf8b688be860749a97ec335c741f61c4        Driver: local
    Volume: 9b28768f72fee829dfd9d79c7f3fd0e397575ddeaf4bda78da692a73e011b566        Driver: local
    Volume: 5567a9a396cbd723fc1b61b65c3f4b8ebe6b88b3d82a310a0608414da43b6967        Driver: local
    Volume: ea1e74d7322e2452f88bbc696496bd222796c5e677413d7bc4b83dd149641f29        Driver: local
    Volume: ec5104b8730b5b0cf7268d7c15099af5a5e338874a0f7b90b367f71403f644d1        Driver: local
    Volume: f25d818354514eacad8a9c0f2c2cf1c955b269d4c1aa54594f6640a42582392d        Driver: local
    Volume: fc5116202752352927aab83e93bc750a19f50e856667005238ef927dd1bd82bf        Driver: local
    Volume: my-vol1 Driver: local
    Volume: my-vol2 Driver: local

五、卷默认存储位置

Docker 卷的存储位置与权限

默认存储路径

Docker 创建的卷默认存储在宿主机的以下目录中:

/var/lib/docker/volumes/

目录权限与访问
  • Docker 管理:该目录及其内容由 Docker 守护进程直接管理。

  • 非 Docker 进程不应修改:为了确保数据的一致性和可靠性,任何非 Docker 进程(如常规的用户应用程序或脚本)都不应直接修改该文件系统中的内容。

  • 访问权限:因此,该目录对普通用户没有查看权限

访问示例:
必须使用 sudo 权限才能列出该目录的内容。

sudo ls /var/lib/docker/volumes/

典型输出:

root@debase:~# ls /var/lib/docker/volumes/
2ca4997ef5fd25d79528143b678f442ad3f5d672aeaccb99a77c4a42f156cceb  ec5104b8730b5b0cf7268d7c15099af5a5e338874a0f7b90b367f71403f644d1
5567a9a396cbd723fc1b61b65c3f4b8ebe6b88b3d82a310a0608414da43b6967  f25d818354514eacad8a9c0f2c2cf1c955b269d4c1aa54594f6640a42582392d
8b93eed1ae5756093efb497eb1776d71cf8b688be860749a97ec335c741f61c4  fc5116202752352927aab83e93bc750a19f50e856667005238ef927dd1bd82bf
9b28768f72fee829dfd9d79c7f3fd0e397575ddeaf4bda78da692a73e011b566  metadata.db
backingFsBlockDev                                                 my-vol1
ea1e74d7322e2452f88bbc696496bd222796c5e677413d7bc4b83dd149641f29  my-vol2

目录结构解析
目录项 类型 说明
my-vol1my-vol2 目录 这些目录的名称与通过 docker volume create 命令创建的具名卷的名称完全一致。每个卷的数据通常存储在其对应的目录下的 _data 子目录中。
2ba6c99d9d1c...5dd4508797e0... 目录 这些目录的名称与通过 docker volume ls 看到的匿名卷的随机哈希名称完全一致
metadata.db 文件 Docker 用于管理卷的元数据库文件。它记录了卷的元信息(如名称、驱动、标签等),不应手动修改此文件
(其他文件) 文件 可能还包含由 Docker 或卷驱动维护的其他内部文件和块文件。

关键观察:

/var/lib/docker/volumes/ 目录下的子文件夹名称,与通过 docker volume ls 命令列出的 VOLUME NAME 是完全一致的。每一个卷(无论是具名卷还是匿名卷)都在此目录下有一个对应的文件夹。


六、卷删除

Docker 卷删除命令详解

Docker 提供了两个命令来删除卷,用于不同的场景。


1. docker volume rm - 删除指定卷

命令格式:

bash

docker volume rm [OPTIONS] VOLUME [VOLUME...]

参数说明:

参数 说明
VOLUME [VOLUME...] 指定一个或多个要删除的卷名称
-f--force 强制移除一个或多个卷。
实践示例:移除 my-vol2 卷
# 删除指定的 my-vol2 卷
rz@demo:~$ docker volume rm my-vol2
my-vol2

# 查看删除后的卷列表,确认 my-vol2 已不存在
rz@demo:~$ docker volume ls
DRIVER    VOLUME NAME
local     2ba6c99d9d1c7225f052c55c4d9c62eb0e895ff81cb0b36928fd8e92022aed35
local     5dd4508797e0950e46e171e15ba79998130dfb78bdd0325fb2f0e09b298ee986
...
local     my-vol1

2. docker volume prune - 清理未使用的卷

命令格式:

docker volume prune [OPTIONS]

参数说明:

参数 说明
-f--force 不进行确认提示,直接移除所有未使用的卷。

功能说明:
移除所有未被任何容器使用的本地卷

实践示例:移除系统内未使用的卷
# 执行清理命令,系统会提示确认
rz@demo:~$ docker volume prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y

# 显示被删除的卷列表
Deleted Volumes:
8060d803c478443df41b16d2ef0064efea5ba9882cb2e72269867e9d34eb8283
...
2ba6c99d9d1c7225f052c55c4d9c62eb0e895ff81cb0b36928fd8e92022aed35
...
5dd4508797e0950e46e171e15ba79998130dfb78bdd0325fb2f0e09b298ee986
...

# 显示回收的磁盘空间
Total reclaimed space: 2.022GB

# 查看清理后的卷列表
rz@demo:~$ docker volume ls
DRIVER    VOLUME NAME
local     my-vol1

关键区别总结
命令 删除对象 特点
docker volume rm 指定的一个或多个卷 精确删除,需要明确知道要删除的卷名
docker volume prune 所有未被使用的本地卷 批量清理,主要用于释放磁盘空间

重要观察:

单独创建的具名卷 my-vol1 如果没有被任何容器使用,在执行 docker volume prune 时不会被自动删除。这是因为 prune 命令主要针对的是匿名卷和未被引用的卷,而手动创建的具名卷即使未被使用,通常也需要显式删除。


七、绑定挂载

Docker 绑定挂载详解与实践

同使用卷一样,可以在创建启动容器时,通过 --mount 或 --volume 参数使用绑定挂载。


参数语法详解

1. -v 或 --volume 参数

语法格式:

-v <第一字段>:<第二字段>:<第三字段>
字段 说明 注意
第一字段 宿主机上文件或目录的绝对路径 与卷挂载的第一字段(卷名)有重要区别
第二字段 容器内挂载的文件或目录路径 可以为文件
第三字段 逗号分隔的选项列表(可选) 如 ro(只读)、zZ

关于 z 和 Z 选项:用于配置 SELinux 标签,参考 Docker 官网文档

2. --mount 参数

语法格式:

--mount <key1>=<value1>,<key2>=<value2>,...
键 (key) 说明 示例值
type 挂载类型:bindvolumetmpfs bind
source 或 src 主系统上文件或目录的绝对路径 $HOME/data_bind
destination 或 dst 或 target 容器内的目标路径 /var/lib/mysql
readonly 可选,容器以只读方式使用 -

注意--mount 参数不支持用于修改 SELinux 标签的 z 或 Z 选项


重要行为区别

场景 -v 参数行为 --mount 参数行为
挂载不存在的路径 自动创建相应的目录(对于文件也会创建目录) 抛出异常错误,操作失败

实践案例

【实践07】使用 --mount 参数进行绑定挂载

1) 创建目录和容器

# 创建宿主机目录(必须手动创建)
rz@demo:~$ mkdir ~/data_bind
rz@demo:~$ ls
data_bind  debian-src  docker-ce  scripts

# 创建容器并使用绑定挂载
rz@demo:~$ docker run -d --name mysql-studk6 \
  --mount type=bind,source=$HOME/data_bind,target=/var/lib/mysql \
  -p 3318:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:8.0.40-debian
9bc201ed0715968cf664c982c95bbca6fd196a88bdf8d7720e54c58af60c75e8

rz@demo:~$ docker ps
CONTAINER ID   IMAGE                 STATUS          PORTS       NAMES
9bc201ed0715   mysql:8.0.40-debian   Up 11 seconds   ...3318...  mysql-studk6

验证挂载:

rz@demo:~$ ls ~/data_bind/
auto.cnf         client-key.pem      '#innodb_temp'        server-key.pem
binlog.000001    '#ib_16384_0.dblwr'   mysql                sys
binlog.000002    '#ib_16384_1.dblwr'   mysql.ibd            undo_001
binlog.index     ib_buffer_pool       performance_schema    undo_002
ca-key.pem       ibdata1              private_key.pem
ca.pem           ibtmp1               public_key.pem
client-cert.pem  '#innodb_redo'       server-cert.pem

注意:使用 --mount 参数,必须手动先创建宿主机目录,并且给出绝对路径。

2) 创建数据库并验证持久化

# 连接 MySQL 服务创建数据库
rz@demo:~$ mysql -h 127.0.0.1 -P3318 -uroot -p123456

MySQL [(none)]> create database studk_test;
Query OK, 1 row affected (0.005 sec)

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| studk_test         |
| sys                |
+--------------------+
5 rows in set (0.003 sec)

MySQL [(none)]> exit;

# 停止并删除容器
rz@demo:~$ docker stop mysql-studk6
mysql-studk6
rz@demo:~$ docker rm mysql-studk6
mysql-studk6

# 验证数据持久化
rz@demo:~$ ls ~/data_bind/
auto.cnf         client-key.pem       mysql                studk_test
binlog.000001    '#ib_16384_0.dblwr'   mysql.ibd            sys
...

删除容器后,所创建的 studk_test 数据库在宿主机目录中持久化存储下来了。


【实践08】以只读方式绑定挂载

1) 准备宿主机目录和文件

rz@demo:~$ mkdir ~/data_bind2
rz@demo:~$ echo "Hello, World!" > ~/data_bind2/test.txt
rz@demo:~$ cat ~/data_bind2/test.txt
Hello, World!

2) 创建容器并以只读方式绑定挂载

rz@demo:~$ docker run -d --rm --name mysql-studk7 \
  -v $HOME/data_bind2:/root:ro \
  -p 3320:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:8.0.40-debian
919d8d1f0f66f8c99a4041b14ca3b16db680e94407182de72d00382651d15e55

rz@demo:~$ docker ps
CONTAINER ID   IMAGE                 STATUS         PORTS       NAMES
919d8d1f0f66   mysql:8.0.40-debian   Up 2 seconds   ...3320...  mysql-studk7

3) 验证只读绑定

# 进入容器
rz@demo:~$ docker exec -it mysql-studk7 /bin/bash

# 查看挂载的文件
root@919d8d1f0f66:/# cd /root/
root@919d8d1f0f66:~# ls
test.txt

# 尝试删除文件(应该失败)
root@919d8d1f0f66:~# rm test.txt
rm: cannot remove 'test.txt': Read-only file system

root@919d8d1f0f66:~# exit
exit

# 清理容器
rz@demo:~$ docker stop mysql-studk7
mysql-studk7
rz@demo:~$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

 在容器内以 root 权限删除 test.txt,系统提示"只读文件系统",验证只读绑定成功。


关键总结

  1. 绑定挂载 vs 卷挂载:绑定挂载使用宿主机路径,卷挂载使用卷名称

  2. 路径要求--mount 必须手动创建宿主机目录,-v 会自动创建

  3. 只读保护:使用 ro 选项或 readonly 键可以防止容器修改宿主机文件

  4. 数据持久化:绑定挂载的数据直接保存在宿主机文件系统中,生命周期独立于容器


八、总结与预告

1、下节课程预告

每天半小时,轻松学Docker第七篇:对象查询与资源配额

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐