docker存储
docker存储
Docker 数据持久化
默认容器的数据是保存在容器的可读写层,当容器被删除时其上的数据将会丢失,所以需要实现数据持久化。
实现数据持久化当前有以下二种方式:
graph LR
A[数据持久化] --> B[挂载目录 Bind Mounts]
A --> C[数据卷 Volumes]
挂载目录(Bind Mounts)
-
存储位置:宿主机任意路径
-
特点:
-
⚡ 宿主机进程可直接访问
-
⚡ 开发环境常用(代码同步)
-
docker run -v /宿主机路径:/容器路径 ...
[root@192 ~]# docker run -itd -p 3306:3306 --name zabbix-mysql -e MYSQL_ROOT_PASSWORD="root123" -v /data/mysql/db:/var/lib/mysql mysql:8.0.42
d9769b864058f4b6dee4c9151328a1b2acd5067cbe8a5dad107f8d44ac0eb6c3
[root@192 ~]# ll /data/mysql/db
数据卷(Volumes)
-
存储位置:
/var/lib/docker/volumes/ -
特点:
- 🔒 仅Docker管理
- 🚀 生产环境推荐方案
docker run -v 卷名:/容器路径
数据卷分为两种:
-
命名卷
- 手动指定卷名称的数据卷,如
db_vol
- 手动指定卷名称的数据卷,如
-
匿名卷
- 自动生成,以哈希ID为名的数据卷
-
显式创建命名卷挂载
# 显式创建命名卷挂载:提前使用docker volume create创建数据卷
[root@192 ~]# docker volume create mysqldata
mysqldata
[root@192 ~]# docker volume ls
DRIVER VOLUME NAME
local mysqldata
[root@192 ~]# docker run -itd -p 3307:3306 --name zabbix-mysql2 -e MYSQL_ROOT_PASSWORD="root123" -v mysqldata:/var/lib/mysql mysql:8.0.42
bc16a434957fca051b9f128a7d0200ee7b30a16d8fe133f4e52ed8def47e5574
[root@192 ~]#
- 隐式创建命名卷挂载
# 隐式创建命名卷挂载:如果指定的命名卷没有提前创建,Docker 会自动创建该命名卷。
[root@192 ~]# docker run -itd -p 3308:3306 --name zabbix-mysql3 -e MYSQL_ROOT_PASSWORD="root123" -v mysqldata2:/var/lib/mysql mysql:8.0.42
3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7
[root@192 ~]# docker volume ls
DRIVER VOLUME NAME
local mysqldata
local mysqldata2
[root@192 ~]#
- 隐式创建匿名卷挂载
# 隐式创建匿名卷挂载
docker run -v /容器路径 ... # 挂载时省略卷名,会自动创建一个随机卷名的匿名卷
- docker中使用volume指令声明一个数据卷,创建容器时会自动创建一个匿名卷
# dockerfile 中使用volume指令,运行容器时会自动创建匿名卷挂载
# VOLUME /var/lib/mysql
[root@192 lib]# docker run -itd -p 3309:3306 --name zabbix-mysql4 -e MYSQL_ROOT_PASSWORD="root123" mysql:8.0.42
ada184b2a650ee7a84137042f7d20679739a9d0870395af7b12230f42b6c9593
[root@192 lib]# docker volume ls
DRIVER VOLUME NAME
local 86d617a310d311e8c025be3ac66bc534e3014bec1f02bc72d8a9d03bd198aa95
local mysqldata
local mysqldata2
[root@192 lib]#
docker的存储结构
默认情况下,docker的数据目录为:/var/lib/docker/,有以下几个目录:
/var/lib/docker/
├── containers/ # 容器元数据(配置、日志等)
├── overlay2/ # 容器文件系统层(主要存储位置)
├── volumes/ # 数据卷存储目录
└── image/ # 镜像存储相关
Docker 容器的存储位置主要由以下三部分组成
-
容器文件系统层 (
overlay2)-
存储容器可写层数据
-
使用联合文件系统(OverlayFS)实现分层存储
-
-
容器元数据 (
containers)- 每个容器对应一个子目录(以容器ID命名)
- 包含:
config.v2.json(容器配置)hostname(主机名)hosts(DNS 配置)-json.log(日志文件)
-
数据卷存储 (
volumes)- 命名卷存储路径:
/var/lib/docker/volumes/<卷名>/_data - 匿名卷存储路径:
/var/lib/docker/volumes/<随机ID>/_data
- 命名卷存储路径:
查看docker信息和数据卷信息
查看docker信息
[root@192 lib]# docker inspect 3ebd5fce3b9c
[
{
"Id": "3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7",
"Created": "2025-07-01T17:19:02.999253044Z",
"Path": "docker-entrypoint.sh",
"Args": [
"mysqld"
],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2025-07-01T17:19:03.34501356Z",
"FinishedAt": "2025-07-01T17:24:09.878469249Z"
},
"Image": "sha256:96c80606b7abcc8baf0123f5a6ef737750f9ba3a2f297e7b664e03d62a1e38af",
"ResolvConfPath": "/var/lib/docker/containers/3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7/hostname",
"HostsPath": "/var/lib/docker/containers/3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7/hosts",
"LogPath": "/var/lib/docker/containers/3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7/3ebd5fce3b9c22ad9f31efcae794bf90ab6cdfbba7c31a519a3ee725e10d92c7-json.log",
"Name": "/zabbix-mysql3",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"mysqldata2:/var/lib/mysql"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "bridge",
"PortBindings": {
"3306/tcp": [
{
"HostIp": "",
"HostPort": "3308"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
31,
149
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": [],
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware",
"/sys/devices/virtual/powercap"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24-init/diff:/var/lib/docker/overlay2/926b9c35d13c98b4901a61f357721d42231ef1802e5d466096ec3631bb26c139/diff:/var/lib/docker/overlay2/24addcba817cab68e1be8c08ef5bd1f40d501c1f89f5360151043616fdce1961/diff:/var/lib/docker/overlay2/8f7f5ea1a158084359e7e6c602f4af58b393c268c1cad03ea7e62db7a14ea573/diff:/var/lib/docker/overlay2/b15992edf509b8c0eb71bb6cccd5ccd1b64f730d3cc579a308d5613966b7b2af/diff:/var/lib/docker/overlay2/c6901b4b6d821ad2dbc6f15aa5b4bb1f2626b92f0e5264b7b22a02a7f748184e/diff:/var/lib/docker/overlay2/aef77f32f4c55793984c154ef50e58afc2a20417dd5d2112223471d780ff3711/diff:/var/lib/docker/overlay2/0212fc766482ffa29f2b4c5a65b534bc31e2040e6fb046e0493016a7a2f3b7a1/diff:/var/lib/docker/overlay2/76fbc1976d1524549f1183b5293889a90e631a33dd6806931b1fff13f709a834/diff:/var/lib/docker/overlay2/376520793b8083ca0651bb9c3c38716bdd2cec0d8f8362cb4fc60b89799b8547/diff:/var/lib/docker/overlay2/ae96bcdab8c40415e686e7a8db628dd6ba03e74fe7bad32b1900ce56299c4b62/diff:/var/lib/docker/overlay2/a00e8930a240c3466404ec90e74f60c2a2d8ee2555c16b8aee5a56c88e71fe91/diff",
"MergedDir": "/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24/merged",
"UpperDir": "/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24/diff",
"WorkDir": "/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "volume",
"Name": "mysqldata2",
"Source": "/var/lib/docker/volumes/mysqldata2/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "3ebd5fce3b9c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"MYSQL_ROOT_PASSWORD=root123",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.17",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.42-1.el9",
"MYSQL_SHELL_VERSION=8.0.42-1.el9"
],
"Cmd": [
"mysqld"
],
"Image": "mysql:8.0.42",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "/",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "1f5b160caa08d48e1abf6364cc9c4db174715d8b909ec142e43e6eecf096b4ce",
"SandboxKey": "/var/run/docker/netns/1f5b160caa08",
"Ports": {},
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "",
"NetworkID": "35655e50668cbbe23116df262251ac3a639379b6a343197ce2b0777fb6214191",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": null
}
}
}
}
]
过滤
[root@192 lib]# docker inspect 3ebd5fce3b9c | grep MergedDir
"MergedDir": "/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24/merged",
[root@192 lib]#
[root@192 lib]# docker inspect 3ebd5fce3b9c --format '{{.GraphDriver.Data.MergedDir}}'
/var/lib/docker/overlay2/51cbc844fd3d3ff05f7d634e0e41801d603a167452666cef936a25e8b5d57d24/merged
[root@192 lib]#
[root@192 overlay2]# docker inspect 3ebd5fce3b9c | grep Mounts -A 20
"Mounts": [
{
"Type": "volume",
"Name": "mysqldata2",
"Source": "/var/lib/docker/volumes/mysqldata2/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "3ebd5fce3b9c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
[root@192 overlay2]#
查看数据卷信息
docker volume ls查看有哪些数据卷docker volume inspect 数据卷名查看具体数据卷信息docker volume prune清理未使用的存储卷
[root@192 ~]# docker volume inspect mysqldata
[
{
"CreatedAt": "2025-07-02T01:17:40+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mysqldata/_data",
"Name": "mysqldata",
"Options": null,
"Scope": "local"
}
]
[root@192 lib]# docker volume inspect 86d617a310d311e8c025be3ac66bc534e3014bec1f02bc72d8a9d03bd198aa95
[
{
"CreatedAt": "2025-07-02T11:46:38+08:00",
"Driver": "local",
"Labels": {
"com.docker.volume.anonymous": ""
},
"Mountpoint": "/var/lib/docker/volumes/86d617a310d311e8c025be3ac66bc534e3014bec1f02bc72d8a9d03bd198aa95/_data",
"Name": "86d617a310d311e8c025be3ac66bc534e3014bec1f02bc72d8a9d03bd198aa95",
"Options": null,
"Scope": "local"
}
]
[root@192 lib]#
查看所有docker存储占用
# 显示所有镜像、容器、数据卷的磁盘使用情况
docker system df -v
其他
将镜像中的文件拷贝出来
[root@192 config]# ll
总用量 4
-rw-r--r-- 1 root root 80 7月 2 11:57 my.cnf
[root@192 config]# docker create --name temp-mysql mysql:8.0.42 # 创建一个临时容器(不启动)
2c4421046932fba2af6c10876a369580bb2965a0789ab395629a8a1ae7d927c5
[root@192 config]# docker cp temp-mysql:/etc/my.cnf /data/mysql/config/my2.cnf # 从容器中复制 my.cnf 到主机
Successfully copied 3.07kB to /data/mysql/config/my2.cnf
[root@192 config]# ll
总用量 8
-rw-r--r-- 1 root root 1317 6月 26 08:08 my2.cnf
-rw-r--r-- 1 root root 80 7月 2 11:57 my.cnf
[root@192 config]# cat my2.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
# Remove leading # to revert to previous value for default_authentication_plugin,
# this will increase compatibility with older clients. For background, see:
# https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin
# default-authentication-plugin=mysql_native_password
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/
[root@192 config]# docker rm temp-mysql # 删除临时容器
temp-mysql
[root@192 config]#
修改配置文件之后,再挂载配置文件创建容器
[root@192 config]# vim my.cnf
[root@192 config]# docker run -itd -p 3309:3306 --name zabbix-mysql5 -e MYSQL_ROOT_PASSWORD="root123" -v /data/mysql/config/my.cnf:/etc/my.cnf mysql:8.0.42
3fa095acacbaa6eb5c44da566324df31ace45c17de3a0b4e86cac241fce6b897
[root@192 config]# docker exec -it zabbix-mysql5 bash # 进入容器,验证是否生效
bash-5.1# cat /etc/my.cnf
[mysqld]
bind-address = 0.0.0.0
max_connections = 200
innodb_file_per_table = 1
bash-5.1# exit
exit
[root@192 config]#
[root@192 config]# docker exec -it zabbix-mysql5 cat /etc/my.cnf # 不进入容器,验证是否生效
[mysqld]
bind-address = 0.0.0.0
max_connections = 200
innodb_file_per_table = 1
[root@192 config]#
数据覆盖规则
graph TB
A[挂载类型] --> B{卷/目录状态}
B -->|新创建| C[容器数据 -> 挂载点]
B -->|已存在| D[挂载点数据 -> 容器]
| 场景 | 容器启动时行为 | 示例说明 |
|---|---|---|
| 挂载新命名卷 | 容器目录内容复制到卷 | 初始化数据库目录 |
| 挂载已有命名卷 | 卷内容覆盖容器目录 | 恢复数据库备份 |
| 挂载空主机目录 | 容器目录内容复制到主机目录 | 开发时同步代码 |
| 挂载非空主机目录 | 主机目录内容覆盖容器目录 | 生产环境配置覆盖 |
| Dockerfile声明VOLUME | 自动创建匿名卷并覆盖容器目录 | 防止重要数据被误删 |
数据生命周期管理
| 数据类型 | 存储位置 | 容器删除后是否保留 |
|---|---|---|
| 容器可写层 | overlay2 | ❌ 立即删除 |
| 命名卷 | volumes | ✅ 保留 |
| 绑定挂载 | 用户指定路径 | ✅ 保留 |
| 匿名卷 | volumes | ❌ 保留,需手动清理 |
如何选择存储方案
避免使用容器层存储重要数据
graph TD
Start[存储需求] --> NeedPersist{需要持久化?}
NeedPersist -- 否 --> UseContainerLayer[使用容器层存储]
NeedPersist -- 是 --> NeedHostAccess{宿主机需直接访问?}
NeedHostAccess -- 是 --> UseBindMount[使用绑定挂载]
NeedHostAccess -- 否 --> NeedBackup{需要定期备份?}
NeedBackup -- 是 --> UseNamedVolume[使用命名卷]
NeedBackup -- 否 --> UseAnonymousVolume[使用匿名卷]
| 场景 | 推荐方案 | 注意事项 |
|---|---|---|
| 配置文件 | 绑定挂载 | 使用只读模式(ro)防止容器修改 |
| 临时缓存 | 匿名卷 | 配合--rm参数自动清理 |
| 跨容器共享 | 命名卷 | 注意并发写入问题 |
| 数据库存储 | 命名卷 + 定期备份 | 确保卷驱动程序适合IO类型 |

浙公网安备 33010602011771号