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 容器的存储位置主要由以下三部分组成

  1. 容器文件系统层 (overlay2)

    • 存储容器可写层数据

    • 使用联合文件系统(OverlayFS)实现分层存储

  2. 容器元数据 (containers)

    • 每个容器对应一个子目录(以容器ID命名)
    • 包含:
      • config.v2.json(容器配置)
      • hostname(主机名)
      • hosts(DNS 配置)
      • -json.log(日志文件)
  3. 数据卷存储 (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类型

docker

posted @ 2025-12-25 15:00  姬雨晨  阅读(7)  评论(0)    收藏  举报