存储

介绍

默认情况下,容器内创建的所有文件都存储在可写的容器层上,该层位于只读、不可变的图像层之上。

写入容器层的数据在容器销毁后不会保留。这意味着,如果其他进程需要这些数据,则很难将其从容器中取出。

每个容器的可写层都是唯一的。无法将数据从可写层提取到主机或其他容器。

存储挂载选项

挂载类型 说明 使用场景 特点
Volume Mounts Docker管理的持久化数据卷,存储在/var/lib/docker/volumes/目录下 数据库存储、应用数据持久化 独立于容器生命周期、可在容器间共享、支持数据备份和迁移
Bind Mounts 将宿主机目录或文件直接挂载到容器内 开发环境代码热更新、配置文件挂载 方便直接操作文件、依赖宿主机文件系统、适合开发调试
Tmpfs Mounts 将数据临时存储在宿主机内存中 敏感数据存储、临时文件存储 高性能、数据易失性、增加内存占用
Named Pipes 在容器间建立命名管道进行通信 容器间进程通信、数据流传输 低延迟、进程间通信、适合流式数据传输

Volume mounts

管理操作

Usage: docker volume create [OPTIONS] [VOLUME]

# 创建一个简单的数据卷
[root@docker-server ~]# docker volume create my_data

# 创建带标签的数据卷
[root@docker-server ~]# docker volume create --label env=prod --label app=web my_app_data

# 创建指定驱动的数据卷
[root@docker-server ~]# docker volume create --driver local --opt type=nfs --opt o=addr=192.168.1.1,rw --opt device=:/path/to/dir nfs_data

# 创建带容量限制的数据卷(需要支持的存储驱动)
# docker volume create --opt size=10G mysql_data

Usage: docker volume ls [OPTIONS]

# 列出所有数据卷
[root@docker-server ~]# docker volume ls

# 按名称过滤数据卷
[root@docker-server ~]# docker volume ls --filter name=my_data

# 按标签过滤数据卷
[root@docker-server ~]# docker volume ls --filter label=env=prod

# 以自定义格式输出(仅显示名称)
[root@docker-server ~]# docker volume ls --format "{{.Name}}"

# 列出未被任何容器使用的数据卷
[root@docker-server ~]# docker volume ls --filter dangling=true

Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]

# 查看单个数据卷详情
[root@docker-server ~]# docker volume inspect my_data

# 查看多个数据卷详情
[root@docker-server ~]# docker volume inspect my_data my_app_data

# 以特定格式查看数据卷挂载点
[root@docker-server ~]# docker volume inspect --format '{{ .Mountpoint }}' my_data

# 以特定格式查看数据卷驱动
[root@docker-server ~]# docker volume inspect --format '{{ .Driver }}' my_data

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

# 删除单个数据卷
[root@docker-server ~]# docker volume rm my_data

# 删除多个数据卷
[root@docker-server ~]# docker volume rm nfs_data my_app_data

# 强制删除数据卷(即使正在使用)
# [root@docker-server ~]# docker volume rm -f my_data

Usage: docker volume prune [OPTIONS]

# 删除所有未使用的数据卷
[root@docker-server ~]# docker volume prune

# 删除未使用的数据卷并跳过确认提示
[root@docker-server ~]# docker volume prune --force

# 按标签过滤并删除未使用的数据卷
[root@docker-server ~]# docker volume prune --filter label=env=dev

使用卷启动容器

如果使用不存在的卷启动容器,Docker 会为创建该卷。

Usage:  
docker run --mount type=volume[,src=<volume-name>],dst=<mount-path>[,<key>=<value>...]
docker run -v [<volume-name>:]<mount-path>[:opts]
参数 说明 使用示例 最佳实践
source, src 卷的名称,用于指定要挂载的数据卷 src=myvolume 使用有意义的名称便于识别和管理
target, dst 容器内的挂载路径,指定数据卷挂载到容器内的位置 dst=/data/app 遵循容器内标准目录结构
type 卷的类型,可选值:volume、bind、tmpfs,默认为volume type=volume 根据数据持久化需求选择合适类型
readonly, ro 只读挂载标志,设置后容器内无法修改挂载内容 ro=true 对配置文件等静态内容建议只读挂载
volume-subpath 卷的子路径,只挂载数据卷中的指定子目录 volume-subpath=/config 用于精确控制挂载范围,提高安全性
volume-opt 卷的额外选项,用于指定卷的特定行为 volume-opt=size=10G 根据实际需求配置,避免过度使用
volume-nocopy 创建卷时不从容器复制数据 volume-nocopy=true 用于避免不必要的数据复制,提高性能
[root@docker-server ~]# docker run -d --name devtest01 --mount source=myvol01,target=/app busybox:latest
[root@docker-server ~]# docker run -d --name devtest02 -v myvol02:/app busybox:latest

实践案例

需求:运行MySQL容器并支持久化存储,进行一次数据备份,数据恢复测试验证。

# 步骤1: 创建MySQL数据卷
[root@docker-server ~]# docker volume create mysql_data

# 步骤2: 启动MySQL容器并挂载数据卷
[root@docker-server ~]# docker run -d \
    --name mysql_db \
    -e MYSQL_ROOT_PASSWORD=mysecret \
    -e MYSQL_DATABASE=testdb \
    -e MYSQL_USER=testuser \
    -e MYSQL_PASSWORD=testpass \
    -p 3306:3306 \
    --mount type=volume,src=mysql_data,dst=/var/lib/mysql \
    mysql:8.0

# 步骤3: 验证MySQL容器运行状态
[root@docker-server ~]# docker ps -a | grep mysql_db

# 步骤4: 连接到MySQL并创建测试数据
[root@docker-server ~]# docker exec -it mysql_db mysql -uroot -pmysecret -e "
    USE testdb;
    CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100));
    INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com'), ('李四', 'lisi@example.com');
    SELECT * FROM users;
"

# 步骤5: 使用docker命令备份数据库
# 创建备份目录
[root@docker-server ~]# mkdir -p ~/mysql_backups

# 使用mysqldump进行备份
[root@docker-server ~]# docker exec mysql_db mysqldump -uroot -pmysecret testdb > ~/mysql_backups/testdb_backup.sql

# 步骤6: 模拟数据丢失
[root@docker-server ~]# docker exec -it mysql_db mysql -uroot -pmysecret -e "
    USE testdb;
    DROP TABLE users;
    SHOW TABLES;
"

# 步骤7: 从备份恢复数据
[root@docker-server ~]# docker exec -i mysql_db mysql -uroot -pmysecret testdb < ~/mysql_backups/testdb_backup.sql

# 步骤8: 验证数据恢复
[root@docker-server ~]# docker exec -it mysql_db mysql -uroot -pmysecret -e "
    USE testdb;
    SELECT * FROM users;
"

# 步骤9: 测试容器删除后数据持久性
[root@docker-server ~]# docker stop mysql_db
[root@docker-server ~]# docker rm mysql_db

# 使用相同的数据卷重新创建容器
[root@docker-server ~]# docker run -d \
    --name mysql_db_new \
    -e MYSQL_ROOT_PASSWORD=mysecret \
    -e MYSQL_DATABASE=testdb \
    -e MYSQL_USER=testuser \
    -e MYSQL_PASSWORD=testpass \
    -p 3306:3306 \
    --mount type=volume,src=mysql_data,dst=/var/lib/mysql \
    mysql:8.0

# 等待MySQL启动完成
[root@docker-server ~]# sleep 20

# 验证数据是否仍然存在
[root@docker-server ~]# docker exec -it mysql_db_new mysql -uroot -pmysecret -e "
    USE testdb;
    SELECT * FROM users;
"
# 步骤10: 清理资源(可选)
[root@docker-server ~]# docker stop mysql_db_new
[root@docker-server ~]# docker rm mysql_db_new
[root@docker-server ~]# docker volume rm mysql_data
[root@docker-server ~]# rm -rf ~/mysql_backups

Bind mounts

使用绑定挂载时,主机上的文件或目录将从主机挂载到容器中。

如果将目录绑定挂载到容器上的非空目录中,则目录的现有内容被绑定挂载隐藏。

使用绑定挂载启动容器

Usage: 
docker run --mount type=bind,src=<host-path>,dst=<container-path>[,<key>=<value>...]
docker run -v <host-path>:<container-path>[:opts]
参数 说明 使用场景 最佳实践
readonly, ro 将挂载点设置为只读模式,容器内无法修改挂载的内容 配置文件、静态资源文件挂载 对于不需要容器内修改的内容,建议使用只读模式增加安全性
rprivate 使挂载点的挂载事件不会传播到其他挂载点 默认的挂载传播模式 适用于大多数场景,确保挂载隔离性
rshared 使挂载点的挂载事件双向传播 需要在多个挂载点间共享挂载事件的场景 谨慎使用,可能影响容器隔离性
rslave 使挂载点的挂载事件单向传播(从主机到容器) 需要容器感知主机挂载变化的场景 在特定场景下使用,如动态存储管理
rbind 递归绑定挂载,包含所有子目录 需要完整复制目录结构的场景 确保目录结构完整性,但注意性能开销

实践案例

需求:启动 Nginx 容器并挂载宿主机上的配置文件和主页目录,容器内无权限修改相关内容,测试验证。

# 步骤1: 创建本地工作目录
[root@docker-server ~]# mkdir -p ~/nginx_demo/{conf,html,logs}

# 步骤2: 创建自定义Nginx配置文件
[root@docker-server ~]# cat > ~/nginx_demo/conf/nginx.conf << 'EOF'
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
}
EOF

# 步骤3: 创建自定义HTML页面
[root@docker-server ~]# cat > ~/nginx_demo/html/index.html << 'EOF'
Bind Mount 测试页面
EOF

# 步骤4: 启动Nginx容器并使用bind mount挂载配置和HTML目录(只读模式)
[root@docker-server ~]# docker run -d --name nginx_bind_mount \
    -p 8080:80 \
    --mount type=bind,src=/root/nginx_demo/conf/nginx.conf,dst=/etc/nginx/nginx.conf,readonly \
    --mount type=bind,src=/root/nginx_demo/html,dst=/usr/share/nginx/html,readonly \
    --mount type=bind,src=/root/nginx_demo/logs,dst=/var/log/nginx \
    nginx:latest

# 步骤5: 验证Nginx容器是否正常运行
[root@docker-server ~]# docker ps | grep nginx_bind_mount

# 步骤6: 测试网站访问
[root@docker-server ~]# curl http://localhost:8080

# 步骤7: 验证只读挂载(这将失败,因为挂载是只读的)
[root@docker-server ~]# docker exec -it nginx_bind_mount bash -c "echo 'test' > /usr/share/nginx/html/test.txt"
bash: /usr/share/nginx/html/test.txt: Read-only file system

# 步骤8: 在宿主机上修改HTML文件
[root@docker-server ~]# cat > ~/nginx_demo/html/index.html << 'EOF'
已更新的页面
EOF

# 步骤9: 再次测试网站访问,查看更新后的页面
[root@docker-server ~]# curl http://localhost:8080

# 步骤10: 查看Nginx日志(它们被挂载到宿主机)
[root@docker-server ~]# ls -la ~/nginx_demo/logs/
[root@docker-server ~]# cat ~/nginx_demo/logs/access.log

# 步骤11: 清理资源(可选)
[root@docker-server ~]# docker stop nginx_bind_mount
[root@docker-server ~]# docker rm nginx_bind_mount
[root@docker-server ~]# rm -rf ~/nginx_demo

扩展阅读

tmpfs mounts: https://docs.docker.com/engine/storage/tmpfs/

volumes plugins: https://docs.docker.com/engine/extend/legacy_plugins/

学前沿IT,到英格科技! all right reserved,powered by Gitbook本文发布时间: 2025-11-24 10:09:15

results matching ""

    No results matching ""