Docker基础教程 - 7 容器数据卷

更好的阅读体验:点这里www.doubibiji.com

7 容器数据卷

什么是容器卷,为什么需要容器卷?

我们在运行容器的时候,产生的数据都是保存在容器内部的。如果使用Docker来运行mysql容器,数据都保存在容器内部,此时删除容器,数据就全部没了!没了!了!比删库跑路还容易,简直离谱他妈给离谱开门------离谱到家了。

所以需要容器卷,将主机的目录挂载到容器内部(宿主机目录相当于一个外部移动硬盘一样),将容器的目录与宿主机的目录进行映射,将数据保存到宿主机上,这样,即使容器被删除,挂载到容器卷中的数据仍然会被保留在宿主机上。使用容器卷既可以实现容器数据的持久化,也可以在容器间共享数据。

目录挂载后,两个目录进行了映射,在宿主机对应目录进行操作,都会反应到容器内的对应目录中;同样,在容器内对挂载的目录进行操作,也会同步到宿主机上,两个文件夹之间的内容始终保持一致。将容器停止,然后修改宿主机的目录,重启容器,还是会将宿主机的内容同步到容器内部。

Docker 提供了三种常见的挂载方式,分别是:绑定挂载(Bind Mounts)、卷挂载(Volume Mounts)和临时文件系统(tmpfs)挂载。下面分别介绍这三种挂载方式的使用。

7.1 绑定挂载

下面使用 Ubuntu 镜像来运行一个容器,使用绑定挂载,将宿主机的目录挂载到容器中。

命令:

shell 复制代码
# 容器卷使用-v参数
docker run -it --privileged=true -v 宿主机目录:容器内目录 镜像名称

# 例如,运行ubuntu并进行容器卷的挂载:
docker run -it --privileged=true \
-v /home/doubi/my-ubuntu/host_data:/root/docker_data \
--name my-ubuntu ubuntu

shell 命令太长,使用 \ 进行换行。

解释一下:

  • --privileged=true :建议都添加 --privileged=true 参数来开启权限,否则可能出现 ls: cannot open directory .: Permission denied 的错误。使用该命令,容器内的root拥有真正的root权限,否则容器内的root在外部只是一个普通用户权限,所以导致容器内的root权限不够。

  • -v /home/doubi/my-ubuntu/host_data:/root/docker_data :表示将宿主机上的 /home/doubi/my-ubuntu/host_data 目录挂载到容器内的 /root/docker_data 目录,使两个目录进行映射。

运行上面的命令后,如果宿主机没有 /home/doubi/my-ubuntu/host_data 目录,则会自动创建,如果容器内部没有 /root/docker_data 目录,也会自动创建,挂载的路径必须是绝对路径,如果容器内/root/docker_data 目录有内容,内容将被覆盖删除。

-v 参数也是可以使用多个的,进行多个目录挂载的,例如:

shell 复制代码
docker run -it --privileged=true \
-v /home/doubi/my-ubuntu/host_data:/root/docker_data \
-v /home/doubi/my-ubuntu/config:/root/config \
--name my-ubuntu ubuntu

大多数情况下,我们都使用了绑定挂载的方式。

7.2 卷挂载

卷挂载方式,Docker管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录中。

卷挂载有两种方式:具名挂载匿名挂载

1 具名挂载

下面运行 ubuntu 并使用卷挂载:

shell 复制代码
docker run -it --privileged=true \
-v ubuntu_data:/root/docker_data \
--name my-ubuntu ubuntu

ubuntu_data 就是容器卷的名称,使用卷挂载,docker 会查看 ubuntu_data 容器卷是否存在,如果不存在就会创建 ubuntu_data 容器卷 。docker 会将容器中的目录映射到 ubuntu_data 容器卷。

使用命令 docker volume ls 可以查看 docker 中存在的卷:

可以使用 docker inspect 命令查看容器卷的位置:

容器中对应的目录中的数据会被存储在 /var/lib/docker/volumes/容器卷名/_data 目录中。

我们也可以使用命令创建容器卷,然后在运行容器的时候,使用已存在的卷:

shell 复制代码
# 创建容器卷
docker volume create 卷名称

# 举个栗子,创建ubuntu_data2容器卷
docker volume create ubuntu_data2

我们可以使用多个容器使用同样的容器卷,实现容器间数据的共享:

shell 复制代码
# 创建容器1
docker run -it --privileged=true \
-v ubuntu_data:/root/docker_data \
--name my-ubuntu1 ubuntu

# 创建容器2,使用同样的数据卷
docker run -it --privileged=true \
-v ubuntu_data:/root/docker_data \
--name my-ubuntu2 ubuntu

2 匿名挂载

在上面使用命令进行容器卷挂载的时候,是指定了容器卷的名称。还有一种是匿名挂载,也就是只指定容器内部的目录,不指定宿主机的目录。

举个栗子:

shell 复制代码
docker run -it --privileged=true -v /root/docker_data --name my-ubuntu ubuntu

docker inspect 命令查看匿名挂载的容器的信息:

可以看到,使用匿名挂载,容器卷是被挂载到宿主机的 /var/lib/docker/volumes/xxxx/_data 目录下。

匿名挂载一般很少使用。

7.3 临时文件系统挂载

这种挂载方式,数据只存储在宿主机的内存中,不会写入到宿主机的文件系统中,当容器停止时,挂载的数据会被删除。

例如,使用如下命令可以实现临时文件系统挂载:

shell 复制代码
docker run --tmpfs /container/path image_name

不过一般不会使用这种方式,就当我没说,忽略。

7.4 查看挂载

使用 docker inspect 容器ID 命可以查看容器挂载的详细信息,里面就包含了容器的挂载信息。

7.5 理解挂载 - 重要

重新来说一下挂载,其实上面说的将宿主机和容器的目录进行映射是不准确的说法。

例如我们在运行容器的时候,使用了绑定挂载 ,指定了 -v /home/doubi/my-ubuntu/data:/root/docker_data

这表示将宿主机的 /home/doubi/my-ubuntu/host_data 目录挂载到容器内部的 /root/docker_data 目录,也就是容器内部的 /root/docker_data 目录变成了指向了宿主机的 /home/doubi/my-ubuntu/host_data 目录的一个链接,或快捷方式。在容器内部将数据保存到 /root/docker_data 目录,数据实际保存到的是宿主机的 /home/doubi/my-ubuntu/host_data 目录。

所以在执行挂载的时候,如果容器内的 /root/docker_data 目录是非空的,那么目录中的文件将会丢失,因为 /root/docker_data 目录变成了一个链接,指向了宿主机的目录的 /home/doubi/my-ubuntu/host_data 目录,显示的自然是宿主机 /home/doubi/my-ubuntu/host_data 目录的内容,如果 /home/doubi/my-ubuntu/host_data 目录是空的,那么容器内的 /root/docker_data 目录也将变成空的。

而卷挂载不一样:如果volume是空的而容器中的目录有内容,那么docker会将容器目录中的内容拷贝到volume中,但是如果volume中已经有内容,则会将容器中的目录覆盖。

7.6 容器卷读写规则

上面在进行容器卷挂载的时候,我们没有指定容器卷的读写规则,那么使用的就是默认规则,也就是说容器内部对挂载的目录具有可读可写权限。

还可以使用容器卷读写规则,限制容器内对挂载目录的读写权限。

命令:

shell 复制代码
docker run -it --privileged=true -v 宿主机目录:容器内目录 镜像名称

没有指定读写规则,默认是 rw 的读写规则,那么其实是这样的:

shell 复制代码
docker run -it --privileged=true -v 宿主机目录:容器内目录:rw 镜像名称

如果想限制容器内对挂载目录的操作权限,例如在容器内只能对挂载目录进行只读,那么,可以修改命令为:

shell 复制代码
# 容器内对挂载目录只能读
docker run -it --privileged=true -v 宿主机目录:容器内目录:ro 镜像名称

# 举例:
docker run -it --privileged=true -v /home/doubi/my-ubuntu/host_data:/root/docker_data:ro --name my-ubuntu ubuntu

ro 表示 readonly ,只读。目录下的内容只能通过宿主机来修改,容器内部是无法操作的,只能读!

一般情况下都是使用默认规则,可读可写。

7.7 容器卷的继承和共享

如果要在多个容器之间共享数据,那么可以使用相同的挂载目录。

举个栗子:

shell 复制代码
# 运行my-ubuntu1容器
docker run -it --privileged=true -v /home/doubi/my-ubuntu/host_data:/root/docker_data --name my-ubuntu1 ubuntu
# 运行my-ubuntu2容器
docker run -it --privileged=true -v /home/doubi/my-ubuntu/host_data:/root/docker_data --name my-ubuntu2 ubuntu

上面运行了两个 ubuntu 容器,使用的是宿主机相同的挂载目录,这样在宿主机修改目录下的内容,会同时同步到两个容器中;同样,在一个容器内修改目录下的内容,也可以同步到宿主机和其他的容器中。

上面是一种方式,我们还可以使用 --volumes-from 参数,让一个容器继承另一个容器的卷规则。

举个栗子:

shell 复制代码
# 运行my-ubuntu1容器
docker run -it --privileged=true \
-v /home/doubi/my-ubuntu/host_data:/root/docker_data \
--name my-ubuntu1 ubuntu

# 运行my-ubuntu2容器,继承my-ubuntu1容器的卷规则
docker run -it --privileged=true \
--volumes-from my-ubuntu1 \
--name my-ubuntu2 ubuntu

上面的 my-ubuntu2 容器,使用 --volumes-from 参数继承 my-ubuntu1容器的卷规则,那么他们的挂载将是相同的。

这样在宿主机修改目录下的内容,会同时同步到两个容器中;在一个容器内修改目录下的内容,也可以同步到宿主机和其他的容器中。

这种继承的方式在使用多个容器时更为方便。

相关推荐
huangyuchi.15 分钟前
【Linux】LInux下第一个程序:进度条
linux·运维·服务器·笔记·进度条·c/c++
moongoblin33 分钟前
行业赋能篇-2-能源行业安全运维升级
运维·安全·协作
极简网络科技1 小时前
Docker、Wsl 打包迁移环境
运维·docker·容器
黑客老李1 小时前
JavaSec | SpringAOP 链学习分析
java·运维·服务器·开发语言·学习·apache·memcached
杨浦老苏1 小时前
轻量级Docker管理工具Docker Switchboard
运维·docker·群晖
江湖有缘1 小时前
【Docker管理工具】部署Docker可视化管理面板Dpanel
运维·docker·容器
一加一等于二1 小时前
docker部署postgresql17,并且安装插件
docker·postgresql
RussellFans2 小时前
Linux 文本三剑客(grep, awk, sed)
linux·运维·服务器
猴哥聊项目管理2 小时前
什么是DevOps智能平台的核心功能?
运维·项目管理·制造·devops·软件·项目管理软件·软件分享
Chuncheng's blog2 小时前
CentOS 7如何编译安装升级gcc至7.5版本?
linux·运维·c++·centos