Docker 数据持久化

概览

默认情况下,在 docker 容器(container)内创建的文件或产生的数据都只是保存在容器的可写层,这意味着当容器不存在时,容器内产生的数据也没有保存下来。

Docker 提供两种容器数据持久化的方法,使用这两种方法即使容器不存在时,数据也能持久化下来:

  • Bind mount:bind mount 可以是宿主机(host)文件系统的任意目录或文件,除了 docker 容器可以访问,宿主机上也可以对这些目录或文件读写操作
  • Volume:volume 数据持久化在宿主机文件系统 /var/lib/docker/volumes/ 目录下,volume 数据由 docker 进行管理,外部不要对 volume 数据进程修改。 Volume 方式是 docker 官方推荐的数据持久化方式。

另外,如果 docker 运行在 Linux 宿主机,还可以使用 tmpfs mounttmpfs mount 的数据只是保存在宿主机的内存中,并没有持久化到硬盘。

Docker 容器与宿主机数据共享的方式如下图所示:

无论使用哪种方式,对于 docker 容器来说,这些数据都被看作成一个目录或文件,数据的使用方式是一样的。

Bind mount

Bind mount 方式是 docker 早期使用的容器与宿主机数据共享的方式,可以实现将宿主机上的文件或目录挂载(mount)到 docker 容器中使用。

相对于 volume 方式,bind mount 方式存在不少的局限。例如,bind mount 在 Linux 和 Windows 操作系统下不可移植。因此 docker 官方推荐使用 volume 方式。

为了便于说明 docker 数据共享的特点,我们以 busybox 镜像为例进行操作演示。

例如,使用 docker run -v 命令来将将宿主机的 /Users/lihao/code/docker/busybox 目录挂载到容器的 /databind 目录:

docker run -it --name container1 -v /Users/lihao/code/docker/busybox:/databind busybox

这时,在宿主机上创建两个文件 file1.txtfile2.txt,再在容器内执行命令:

cd /databind
ls

可以同步看到刚创建的两个文件:

file1.txt file2.txt

对于 bind mount,有几点需要注意。

  • -v 宿主机目录路径必须以 /~/ 开头,否则 docker 会将其当成是 volume 而不是 bind mount
  • 如果宿主机上的目录不存在,docker 会自动创建该目录
  • 如果容器中的目录不存在,docker 会自动创建该目录
  • 如果容器中的目录已有内容,那么 docker 会使用宿主机上目录的内容覆盖容器目录的内容

Volume

与 bind mount 不同,volume 由 docker 创建和管理,docker 所有的 volume 都保存在宿主机文件系统的 /var/lib/docker/volumes 目录下(注意,mac 操作系统以虚拟机运行 docker,因此并不存在该目录,可以参考 stackoverflow)。

Docker 引入 volume 的原因有:

  • 删除容器时,volume 不会被删除
  • 在不同的容器之间共享 volume (存储 / 数据)
  • 容器与存储分离
  • 将 volume 存储在远程主机或云上

可以使用 docker run -v 参数为启动容器加载一个 volume,例如:

docker run -it -v /data --name container1 busybox

这样,我们就启动了一个名为 container1 的容器,由于使用了 -it 参数,我们以交互方式进行了容器内部。
这时,执行命令:

ls

可以看到容器中 /data 目录:

bin data dev etc home proc root sys tmp usr var

接着,我们在容器 /data 目录创建 file1.txt 文件:

cd data
touch file1.txt
exit

退出容器后,执行 docker ps -a 可以看到 container1 容器的退出状态。

现在,我们 inpect 一下容器,看下 docker 在启动容器时做了什么:

docker inspect container1

可以看到一大串 JSON 格式的输出,我们重点关注 Mounts 字段的输出。

"Mounts": [
            {
                "Type": "volume",
                "Name": "9ee296c604fcb8e89c726b3ce07b55efe700763058c992821a81ca1c30f11cc5",
                "Source": "/var/lib/docker/volumes/9ee296c604fcb8e89c726b3ce07b55efe700763058c992821a81ca1c30f11cc5/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

可以看到,当容器 container1 加载一个 volume (/data)时,docker 在目录 /var/lib/docker/volumes/ 创建一个新的目录,用来存储容器中产生的文件。同时,我们注意到 /dataRW 属性为 true,即可读可写。

我们重新启动 container1 容器,并进入容器:

docker restart container1
docker attach container1

在容器执行命令:

ls
cd /data
ls

可以看到 /data 目录仍在:

bin data dev etc home proc root sys tmp usr var

之前创建的 file1.txt 文件也在:

file1.txt

这说明,即使容器关闭,之前在 volume 存储的文件仍然会保留下来。

然后,我们退出容器,并将容器 container1 删除。

docker rm container1

这时,使用命令 docker volume ls 查看当前的 volume,可以看到 9ee296c604fcb8e89c726b3ce07b55efe700763058c992821a81ca1c30f11cc5 volume 仍然存在。也就是说,即使容器不存在了,volume 仍可在宿主机上保存下来。

local 9ee296c604fcb8e89c726b3ce07b55efe700763058c992821a81ca1c30f11cc5

如果需要在其他容器也使用这个 volume,可以使用以下命令加载指定的 volume:

docker run -it -v 9ee296c604fcb8e89c726b3ce07b55efe700763058c992821a81ca1c30f11cc5:/data busybox

可以使用 docker volume rm 删除指定的 volume。

挂载指定的 volume

上面的 docker run -v 命令中,我们并没有指定 volume 的名称,这样 docker 会默认给我们创建一个匿名的 volume。
我们也可以挂载指定名称的 volume:

docker run -it -v my-volume:/data --name container1 busybox

这样,我们在启动容器 container1 时,将挂载一个名为 my-volume 的 volume,并挂载到容器的 /data 目录。对于 docker 来说,如果 my-volume 不存在,那么 docker 就会自动创建该 volume,并挂载到 /data 目录。

退出容器后,执行

docker volume inspect my-volume

可以看到 my-volume 的 JSON 输出信息:

[
    {
        "CreatedAt": "2020-02-06T09:28:54Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
        "Name": "my-volume",
        "Options": null,
        "Scope": "local"
    }
]

可以看到,名为 my-volume 的 volume 在宿主机的目录为 /var/lib/docker/volumes/my-volume/_data

除了让 docker 帮我们自动创建 volume,我们也可以自行创建 volume:

docker volume create my-volume2

然后将这个手工创建的 volume 挂载到容器:

docker run -it -v my-volume2:/data --name container1 busybox

参考资料

  • https://docs.docker.com/storage/
  • https://docs.docker.com/storage/bind-mounts/
  • https://www.jianshu.com/p/8c22cdfc0ffd
  • https://www.jianshu.com/p/ef0f24fd0674
  • https://www.ostechnix.com/explaining-docker-volumes-with-examples/
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值