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

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

7 容器数据卷

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

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


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

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


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

7.1 绑定挂载

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

命令:

# 容器卷使用-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 参数也是可以使用多个的,进行多个目录挂载的,例如:

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 并使用卷挂载:

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 目录中。


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

# 创建容器卷
docker volume create 卷名称

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

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

# 创建容器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 匿名挂载

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

举个栗子:

docker run -it --privileged=true -v /root/docker_data --name my-ubuntu ubuntu

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

匿名挂载一般很少使用。

7.3 临时文件系统挂载

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

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

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 容器卷读写规则

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

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

命令:

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

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

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

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

# 容器内对挂载目录只能读
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 容器卷的继承和共享

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

举个栗子:

# 运行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 参数,让一个容器继承另一个容器的卷规则。

举个栗子:

# 运行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容器的卷规则,那么他们的挂载将是相同的。

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

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

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山石岐渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值