Docker存储

专栏:Docker

第七章:Docker存储

​ Docker提供了4种存储方式:默认存储、volume(数据卷)、bind mounts(绑定挂载)、tmpfsmount(仅在Linux环境中提供)。其中volume、bind mounts两种存储方式实现持久化容器数据。持久化存储系统的功能是将各种服务在运行过程中产生的数据长久地保存下来,即使容器被销毁,数据也仍然存在。

容器的存储可以分为两大类:

一种是与镜像相关的即我们在《联合文件系统OuninFS》一文提到的容器层Copy-On-Write特性。默认情况下,在容器内创建的所有文件都存储在可写容器层上,这种直接将文件存储在容器层的方式数据难以持久化和共享,由于依赖存储驱动与使用直接写入主机文件系统的数据卷相比,这种额外的抽象会降低性能 。

默认容器的数据的读写发生在容器的存储层,当容器被删除时其上的数据将会丢失。所以我们应该尽量保证容器存储层不发生写操作,为了实现数据的持久化存储我们需要选择一种方案来保存数据,当前有以下几种方式:

Volumes、Bind mounts、tmpfs mounts

img

Volumes

Volumes(数据卷)是一个可供一个或多个容器使用的位于宿主机上特殊目录,它拥有以下特性:

数据卷可以在容器间共享和重用 对数据卷的写入操作,不会对镜像有任何影响。数据卷默认会一直存在,即使容器被删除使用数据卷的目的是持久化容器中的数据,以在容器间共享或者防止数据丢失(写入容器存储层的数据会丢失)。

使用数据卷的步骤一般分为两步:

创建一个数据卷,使用 -v 或 --mount 参数将数据卷挂载容器指定目录中,这样所有该容器针对该指定目录的写操作都会保存在宿主机上的 Volume 中。

Volume管理

创建一个Volume:

[root@docker1 ~]# docker volume create my_vol
my_vol

查看Volumes:

[root@docker1 ~]# docker volume ls
DRIVER    VOLUME NAME
local     my_vol
[root@docker1 ~]# docker volume inspect my_vol
[
    {
        "CreatedAt": "2024-04-15T15:30:31+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/my_vol/_data",
        "Name": "my_vol",
        "Options": null,
        "Scope": "local"
    }
]

我么可以看到创建的 Volume my-vol 保存在目录/var/lib/docker/volumes/下,以后所有针对该 Volume 的写数据都会保存中目录/var/lib/docker/volumes/my-vol/_data下。

删除一个 Volume:

[root@docker1 ~]# docker volume rm my_vol

或者删除所有未使用的 Volumes:

[root@docker1 ~]# docker volume prune

挂载数据卷到容器目录

创建了一个 Volume 之后,我们可以在运行容器时通过指定 -v 或 --mount 参数来使用该 Volume:

[root@docker1 ~]# docker volume create nginx-vol
nginx-vol

使用--mount参数:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> --mount source=nginx-vol,destination=/usr/share/nginx/html \
> nginx:latest

source 指定 volume,destination 指定容器内的文件或文件夹。

或者使用 -v 参数:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> -v nginx-vol:/usr/share/nginx/html \
> nginx:latest

挂载成功后,容器从 /usr/share/nginx/html 目录下读取或写入数据,实际上都是从宿主机的 nginx-vol 数据卷中读取或写入数据。因此 Volumes 或 Bind mounts 也可以看作是容器和宿主机共享文件的一种方式。

-v 参数使用冒号分割 source 和 destination,冒号前半部分是 source,后半部分是 destination。

如果你挂载一个还不存在的数据卷,Docker 会自动创建它。(因此创建数据卷那一步非必需)

如果容器中的待挂载的目录不是一个空目录,那么该目录下的文件会被复制到数据卷中。(Bind mounts下,宿主机上的目录总会覆盖容器中的待挂载目录)

-v 参数和 --mount 参数总的来说功能几乎相同,唯一的区别是在运行一个 service 时只能够 --mount 参数来挂载数据卷。

使用只读数据卷

有些情况下,我们希望某个数据卷对某个容器来说是只读的,可以通过添加 readonly 选项来实现:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
> nginx:latest

或者使用-v参数:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> -v nginx-vol:/usr/share/nginx/html:ro \
> nginx:latest

Bind mounts

Bind mounts模式和Volumes非常相似,不同点在于Bind mounts模式是将宿主机上的任意文件或文件夹挂载到容器,而Volumes本质上是将Docker服务管理的一块区域(默认是 /var/lib/docker/volumes 下的文件夹)挂载到容器。

Bind mounts的使用和Volumes类似,也是通过-v或--mount参数将宿主机文件挂载容器中。下面是一个例子:

使用--mount参数时,需要指定type=bind:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> --mount type=bind,source=/usr/local/web,destination=/usr/share/nginx/html \
> nginx:latest

上面的例子将宿主机上的 /usr/local/web 文件夹挂载到容器中的 /usr/share/nginx/html 文件夹。

或者使用-v参数:

[root@docker1 ~]# docker run \
> -d \
> --name=nginxtest \
> -v /usr/local/web:/usr/share/nginx/html \
> nginx:latest

挂载成功后,容器从 /usr/share/nginx/html 目录下读取或写入数据,实际上都是从宿主机的 /usr/local/web 目录中读取或写入数据。因此Volumes或Bind mounts也可以看作是容器和宿主机共享文件的一种方式。

如果你使用Bind mounts挂载宿主机目录到一个容器中的非空目录,那么此容器中的非空目录中的文件会被隐藏,容器访问这个目录时能够访问到的文件均来自于宿主机目录。这也是Bind mounts模式和Volumes模式最大的行为上的不同。

在使用绑定挂载和卷时我们要注意下面传播覆盖原则:

img

挂载一个空卷时:容器内目录的内容会传播(复制)到卷中。

绑定挂载或非空卷时:容器内目录的内容会被卷或绑定的主机目录覆盖。

tmpfs mounts

tmpfs挂载仅适用于linux主机,当我们使用tmpfs挂载创建容器时,容器可以在容器的可写层之外创建文件。将数据保留在内存中,当容器停止时,写入的数据也将被移除。主要用于临时存储不想保留在主机或容器可写层中的敏感文件。

我们可以在运行容器时通过指定--tmpfs参数或--mount参数来使用tmpfs mounts:

[root@docker1 ~]# docker run \
> -d \
> --name=tmptest \
> --mount type=tmpfs,destination=/app \
> nginx:latest

[root@docker1 ~]# docker run \
> -d \
> --name=tmptest \
> --tmpfs /app \
> nginx:latest

使用--tmpfs参数无法指定任何其他的可选项,并且不能用于Swarm Service。

使用docker container inspect tmptest命令,然后查看Mounts部分可以看到:

[root@docker1 ~]# docker inspect tmptest
"Mounts": [
            {
                "Type": "tmpfs",
                "Source": "",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

tmpfs mounts 可选选项

img

一个例子:

[root@docker1 ~]# docker run -d \
 > -it \
 > --name tmptest \
 > --mount type=tmpfs,destination=/app,tmpfs-mode=1770 \
 > nginx:latest

volume可以被多容器共享,但是type=bind直接挂载目录,目录只能被某个容器独占

img

存储数据共享

在容器之间共享数据主要有两种方法,第一种比较简单,只需要将目录或者volume挂载到多个容器中即可。这里不做赘述,我们来看一下通过中间容器实现共享的方式。

我们创建一个中间容器,包含绑定挂载目录和一个卷。

[root@docker1 ~]# docker create \
> -v /share:/volume1 \
> -v /volume2 \
> --name volume_share \  
> busybox

在我们需要共享的容器中通过选项--volumes-from拿过来用即可

[root@docker1 ~]# docker run \
> -d \
> -t \
> --volumes-from volume_share \  
> --name container1 \
> busybox

我们inspect检查一下Mounts字段,此时container1已经挂载到了一个bind目录和一个volume

"Mounts": [
            {
                "Type": "bind",
                "Source": "/share",
                "Destination": "/volume1",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "volume",
                "Name": "3041016b1455bfd343311b6942abc04ff76cb26f7b9eb2bef16ede4995682d30",
                "Source": "/var/lib/docker/volumes/3041016b1455bfd343311b6942abc04ff76cb26f7b9eb2bef16ede4995682d30/_data",
                "Destination": "/volume2",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

0 条评论

🔒

发表评论需要 登录

还没有账号?立即注册

💬
还没有评论,来抢沙发吧!

← 返回首页