Docker的存储资源

Docker为容器提供了两类存储资源:

1.由storage Driver管理的镜像层和容器层

在docker服务器中查看docker信息

[root@localhost ~]# docker info
# 找到以下这条信息,overlay就是在graph中来管理镜像和容器的
# 镜像分层中也说到过,容器的COW特性,对容器的增删改查不会涉及到镜像层中的内容
# 这些功能就是由Storage Driver完成的,也是docker默认使用的driver
 Storage Driver: overlay2

2.Data Volume

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。

本文主要来说Data Volume

Data Volume 有以下特点:

  • Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。
  • 容器可以读写 volume 中的数据。
  • volume 数据可以被永久的保存,即使使用它的容器已经销毁或者关闭。

那现在知道了docker有两种存储数据的资源,同样都是存储数据资源,有什么样的区别呢

这就需要考虑到几个这样的场景

  • Database 软件 vs Database 数据
  • Web 应用 vs 应用产生的日志
  • 数据分析软件 vs input/output 数据
  • Apache Server vs 静态 HTML 文件

以上四点中,前者都属于静态(冷)数据,应用或者软件都是不怎么变化的,可以作为镜像来使用,也就是存放在镜像层中,由storage Driver来管理

而后者,属于动态(热)数据,数据库中的数据,日志,html页面,都是需要变化的动态数,就可以来使用volume卷来管理,是需要持久化的数据,应该与镜像分开来放

Volume容量

如何设置 voluem 的容量?

因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。

这时候也就可以想到,之前在为容器限制使用物理机资源你的时候,对硬盘的限制,只能是读写速率的限制,不能进行容量大小的限制。

在具体的使用上,docker 提供了两种类型的 volume:bind mount 和 manage volume。

volume类型

bind mount一般用于物理机向容器中挂载,而manage volume用于容器中的数据挂载到本地的物理机中

bind mount

bind mount 是将 host 上已存在的目录或文件 mount 到容器。

挂载目录

如:在物理机写个文件mount到docker容器中

[root@localhost ~]# mkdir htdocs
[root@localhost ~]# vi htdocs/index.html
This is FeiYi add html.

启动容器时将目录挂载到容器的指定目录

通过使用-v/--volume参数来指定

–volume指定的目录必须是绝对路径

docker run -d -p 80:80 --volume 物理机路径:容器内路径 image-name

[root@localhost ~]# docker run -d -p 80:80 --name web --volume /root/htdocs/:/usr/local/apache2/htdocs httpd
6f6726e8372bb8fd618c6fb3f7a6212f17601b118eed342d64667a37cf1dfdfd

因为已经对本地进行了端口映射,使用访问本地ip即可知道index.html是不是自己写的内容

[root@localhost ~]# curl 192.168.1.11
This is FeiYi add html.

修改本地文件,同步到容器

[root@localhost ~]# echo "good good study" > htdocs/index.html 
[root@localhost ~]# curl 192.168.1.11
good good study

修改容器文件,同步到本地

[root@localhost ~]# docker exec -it web /bin/sh
# cd /usr/local/apache2/htdocs
# echo "day day up" > index.html
# exit
[root@localhost ~]# cat htdocs/index.html 
day day up 
[root@localhost ~]# curl 192.168.1.11
day day up 

将该容器删掉之后也不会影响物理机的原始文件

[root@localhost ~]# docker rm -f web 
web
[root@localhost ~]# cat htdocs/index.html 
day day up 

挂载目录/文件的权限

在bind mount的挂载类型中,存在两个权限rwro,也即是读写和只读,默认情况下的bind mount是rw权限,如果要指定为ro,可以进行以下操作

docker run -d -p 80:80 --volume 物理机路径:容器内路径:ro/rw image-name

启动容器时指定mount到的文件权限为ro

[root@localhost ~]# docker run -d -p 80:80 --volume htdocs:/usr/local/apache2/htdocs:ro --name web1 httpd
1e203710495879e23cf2ae84d2926d5480bfbb5537d91cbf6f76e650fea7ac40

进入容器写入数据测试,输出信息,不能去修改,Read-only,只读

[root@localhost ~]# docker exec -it web1 /bin/sh
# cd /usr/local/apache2/htdocs
# echo "nimei" > index.html
/bin/sh: 3: cannot create index.html: Read-only file system

挂载文件

[root@localhost ~]# docker run -d -p 80:80 --volume /root/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html --name web httpd
284ad653a4f440789e88ec39ca4cf447f67c7a816fd3496c906130e83a2db9af
[root@localhost ~]# curl 192.168.1.11:80
<html><body><h1>It works!</h1></body></html>
[root@localhost ~]# curl 192.168.1.11/new_index.html
day day up 

使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录 bind mount 给容器。

挂载的目录有很多应用场景,比如我们可以将源代码目录 mount 到容器中,在 host 中修改代码就能看到应用的实时效果。再比如将 mysql 容器的数据放在 bind mount 里,这样 host 可以方便地备份和迁移数据。

bind mount 的使用直观高效,易于理解,但它也有不足的地方:bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。

manage volume

managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 挂载点就行了。

将前面用过的容器删除即可,因为我们要继续使用80端口,方便验证查看

挂载后自动生成volume id

还是以httpd镜像为例,命令中只指定了一个挂载点

[root@localhost ~]# docker run -d -p 80:80 --name web --volume /usr/local/apache2/htdocs httpd
c55e7a02c309204df25dd6372d6d13b2c13fe7c652809c33776f257071c4d5b0

意思是将容器中的该目录挂载到本地中用来管理volume的目录中/var/lib/docker/volume

查看容器的信息来看挂载源和挂载点,方便更好的理解

[root@localhost ~]# docker inspect web
# 找到以下关键信息
        "Mounts": [
            {
                "Type": "volume",
                "Name": "c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0",
                "Source": "/var/lib/docker/volumes/c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0/_data",
                # 挂载源路径,挂载后的数据就放在这个路径,而这个id编号就是volume卷的id号
                "Destination": "/usr/local/apache2/htdocs",
                # 挂载点路径
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

以下操作可以看到manage volume管理的所有volume卷

[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
local               c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0

进入物理机的挂载源中查看,存放的是容器中的挂载点文件

[root@localhost ~]# cd /var/lib/docker/volumes/c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0/_data
[root@localhost _data]# ls
index.html
[root@localhost _data]# cat index.html 
<html><body><h1>It works!</h1></body></html>

与bind mount 一样,这个文件的修改也能够直接更新到容器中

[root@localhost _data]# echo "feiyi" > index.html 
[root@localhost _data]# curl 192.168.1.11
feiyi

查看卷状态

[root@localhost  _data]# docker volume inspect c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0 
[
    {
        "CreatedAt": "2020-03-31T19:06:43+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0/_data",
        "Name": "c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0",
        "Options": null,
        "Scope": "local"
    }
]

同样删除容器后,该volume卷也不会消失

[root@localhost _data]# docker rm -f web 
web
[root@localhost _data]# ls
index.html

删除卷

[root@localhost _data]# docker volume rm c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0 
c8234d831f3ca959f377abe71489dd8c39feec564eaca58f987c7bb31cdc37c0

docker volume prune 删除没有用的卷,此命令慎用,它会自己判断你的卷容器是否无用。

命名volume卷

如果使用以上方法,挂载的目录多了之后,使用volume id根本不知道id是哪个容器的,最好是可以给他自定义一个volume name。

如:

[root@localhost ~]# docker run -d -p 80:80 --name web --volume httpd_test:/usr/local/apache2/htdocs httpd
3d2b3742b3bb79700daaac638b710273754390393875f757ccfdeb6dbce2cac1
[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
local               httpd_test

查看容器的信息来看挂载源和挂载点

[root@localhost ~]# docker inspect web
# 查看以下关键信息
        "Mounts": [
            {
                "Type": "volume",
                "Name": "httpd_test",
                "Source": "/var/lib/docker/volumes/httpd_test/_data",
                # 挂载源已经不是一长串的id了,为httpd_test
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],

去挂载源目录查看数据

[root@localhost ~]# cd /var/lib/docker/volumes/httpd_test/_data
[root@localhost _data]# cat index.html 
<html><body><h1>It works!</h1></body></html>

volume卷重复挂载

上面的volume卷httpd_test已经和web进行挂载,一个卷可以被进行多次挂载

[root@localhost ~]# docker run -itd --name bbox1 --volume httpd_test:/volume busybox
6d1232fee172b64bfb63f1edcfa6360b3c5223e63a861ea8e0c6c4afb8671254
[root@localhost ~]# docker exec -it bbox1 /bin/sh
/ # cat /volume/index.html 
<html><body><h1>It works!</h1></body></html>

虽然看起来这种方式像是,bind mount,只不过冒号前面是volume 名就可以将volume卷中的内容挂载到容器中的指定目录,如果目录不存在则会自动创建

这个时候在更改挂载文件中的内容会同步到两个容器中去

[root@localhost ~]# echo "go go go " > /var/lib/docker/volumes/httpd_test/_data/index.html 
[root@localhost ~]# curl 192.168.1.11
go go go 
[root@localhost ~]# docker exec -it bbox1 /bin/sh
/ # cat /volume/index.html 
go go go 

这种方式更适合于web集群

对于这两种volume卷类型来说,即使已经相互挂载的容器,被使用docker stop停止之后,对物理机的挂载文件进行修改,对停止后的容器也是生效的。

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0