Docker | 数据持久化与跨容器共享

Docker | 数据持久化与跨容器共享

_

一、容器存储概述

1.容器和层

容器和镜像最大的区别在于顶层中的可写层,所有在容器中的数据写入和修改都会直接存储到这个可写层中。通俗的说,当容器被删除时,可写层中的数据就会丢失。虽然每个容器都有不同的可写层,但是容器底层的镜像都是可以同时共享的。

2. 主流的存储驱动

在容器的设计和使用时,在容器可写层中写入的数据是非常少的。在实际的生产环境中,大部分数据是必须要具备持久化保存的能力,所以在容器中引入了多种存储驱动来解决可写层数据的易失性。

发行版系统

Docker主流支持的存储驱动

Ubuntu 20.04/22.04 LTS

overlay2(Docker 20.10+/Containerd 默认)、zfs、btrfs、vfs

Debian 12

overlay2(Docker 20.10 + 默认)、vfs、btrfs

CentOS 7/8 Stream

overlay2(CentOS 8 + 默认)、zfs、devicemapper、vfs

RHEL 8/9/10

overlay2(RHEL 8 + 官方推荐)、devicemapper、zfs

3. Copy-on-Write

CoW(Copy-on-Write,写时复制),数据只读共享,只有在写入时才复制。多个使用者先共享同一份原始数据(数据只读),当有人需要修改数据时,先把原始数据拷贝一份给使用者,让其修改拷贝后的副本,原始数据保持不变,这样不会影响其它使用者。

操作

具体执行

创建文件

新文件只能被添加在容器层中

删除文件

依据容器分层结构由上往下依次查找。找到后,在容器层中记录该删除操作。UnionFS会在容器层创建一个“whiteout”文件,将被删除的文件掩盖起来。

修改文件

依据容器分层机构由上往下依次查找。找到后,将镜像层中的数据复制到容器层进行修改,修改后的数据保存在容器层中。

读取文件

依据容器分层结构由上往下依次查找

4. Storage Driver

Storage Driver管理镜像层和容器层,Storage Driver处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户提供多层数据合并后的统一视图。所有Storage Driver都使用可堆叠图像层和写时复制(CoW)策略。

Storage Driver类型

Storage Driver

说明

overlay2

所有当前的Linux发行版都支持且首选的存储驱动程序

AUFS

仅在Ubuntu和Debian上支持

Device Mapper

CentOS和RedHat推荐的存储驱动程序,当前版本的CentOS和RedHat都支持overlay2

Btrfs

仅在SLES支持

ZFS

仅支持Ubuntu14.04或更高版本

VFS

用于测试目的,不建议使用在生成环境中

[Step1] 查看当前系统中的Storage Driver。

[root@redhat ~]# docker info

二、主机与容器间数据共享

1. 存储方式

docker主机与容器间中持久化数据一般采用两种存储方式

  • volume:将Host上的数据copy到容器的volume中(使用docker cp命令在容器与Host之间复制数据)

  • bind mount:将Host上的目录或文件mount到容器中

2. volume

volume由Docker管理,将特定目录挂载给容器使用。Docker会在指定路径下为每个volume生成一个目录作为mount源。如果没有手动指定路径,默认会挂载在“/var/lib/docker/volumes”。

[Step1]: 基于kylinsp3镜像创建一个容器volume01,并为其分配一个volume卷。

[root@redhat ~]# docker run -d --name volume01 -v /mnt kylinsp3:latest /sbin/init

[Step2] 查看Docker为volume01容器所分配的卷位置。

[root@redhat ~]# docker inspect volume01 | grep Source

[Step3] 往volume卷中写入内容。

[root@redhat ~]# echo "Hello World!" > /var/lib/docker/volumes/cee74954431bf64e0aac09765fbb61fe0c9536d8eff4e69e35940103ffbaced9/_data/hello.txt

[Step4] 连接容器volume01,能够查看到hello.txt文件内容,同时新建文件。

[root@redhat ~]# docker exec -it volume01 /bin/bash
[root@ffefeb27f776 /]# cat /mnt/hello.txt
[root@ffefeb27f776 /]# echo "2026-1-5" > /mnt/time.txt

[Step4] 验证:能够在volume目录下查看刚刚创建的文件及其内容。

[root@redhat ~]# ll /var/lib/docker/volumes/cee74954431bf64e0aac09765fbb61fe0c9536d8eff4e69e35940103ffbaced9/_data/
[root@redhat ~]# cat /var/lib/docker/volumes/cee74954431bf64e0aac09765fbb61fe0c9536d8eff4e69e35940103ffbaced9/_data/time.txt

[Step5]: 删除掉该容器后,可以看到数据仍然存在,可持久化存储。

[root@redhat ~]# docker rm -f volume01
[root@redhat ~]# ll /var/lib/docker/volumes/cee74954431bf64e0aac09765fbb61fe0c9536d8eff4e69e35940103ffbaced9/_data/

3. bind mount

bind mount是将宿主机上已有的目录或文件mount到容器中。

[Step1] 创建一个新的目录“/volume”,在目录中新建一个txt文件。

[root@redhat ~]# mkdir /volume
[root@redhat ~]# echo "Hello World!" > /volume/hello.txt

[Step2] 基于kylinsp3镜像创建一个容器bind01,将/volume目录挂载到容器中。随后登录容器,能够读取目录中内容。

[root@redhat ~]# docker run -d --name bind01 -v /volume:/mnt kylinsp3:latest /sbin/init
[root@redhat ~]# docker exec -it bind01 /bin/bash
[root@ee15a5653b22 /]# ll /mnt/
[root@ee15a5653b22 /]# cat /mnt/hello.txt

[Step3] 删除掉该容器后,可以看到数据仍然存在,可持久化存储。

[root@redhat ~]# docker rm -f bind01
[root@redhat ~]# ll /volume/

4. docker cp

[Step1] 基于kylinsp3镜像创建一个容器docker_cp。

[root@redhat ~]# docker run -d --name docker_cp kylinsp3:latest /sbin/init

[Step2] 在本地新建一个文件,复制到容器docker_cp。

[root@redhat ~]# echo "docker_cp" > docker_cp.txt
[root@redhat ~]# docker cp docker_cp.txt docker_cp:/mnt

[Step3] docker cp也支持将容器文件复制到宿主机,将docker_cp中的hostname文件复制宿主机当前目录。

[root@redhat ~]# docker cp docker_cp:/etc/hostname .
[root@redhat ~]# cat hostname

三、容器与容器间数据共享

1. 挂载同一目录实现数据共享

多个容器通过“-v”参数挂载到同一个物理位置实现数据共享。

[Step1] 创建一个新的目录“/volume_contianer”,在目录中新建一个txt文件。

[root@redhat ~]# mkdir /volume_contianer
[root@redhat ~]# echo "docker file" > /volume_contianer/docker.txt

[Step2] 基于kylinsp3镜像创建一个容器ky01,将/volume_contianer目录挂载到容器中。登录容器,能够读取目录中内容,随后创建一个新文件ky01.txt。

[root@redhat ~]# docker run -d --name ky01 -v /volume_contianer:/mnt kylinsp3:latest /sbin/init
[root@redhat ~]# docker exec -it ky01 /bin/bash
[root@de1949837e00 /]# echo "ky01 file" > /mnt/ky01.txt

[Step3] 基于kylinsp3镜像创建一个容器ky02,将/volume_contianer目录挂载到容器中。登录容器,能够读取目录中内容。

[root@redhat ~]# docker run -d --name ky02 -v /volume_contianer:/mnt kylinsp3:latest /sbin/init
[root@redhat ~]# docker exec -it ky02 /bin/bash
[root@ab9bc99fe611 /]# ls /mnt/
[root@ab9bc99fe611 /]# cat /mnt/docker.txt
[root@ab9bc99fe611 /]# cat /mnt/ky01.txt

2. 容器卷实现数据共享

容器卷:将一个容器作为数据卷,然后其它容器引用这个容器中的数据。

[Step1] 创建一个新的目录“/docker_volume”,在目录中新建一个txt文件并写入内容。

[root@redhat ~]# mkdir /docker_volume
[root@redhat ~]# echo "Hello World!" > /volume01/hello.txt

[Step2] 基于kylinsp3镜像创建一个容器卷docker_volume,将“/docker_volume”挂载到容器的/mnt目录。

[root@redhat ~]# docker run -d --name docker_volume -v /docker_volume:/mnt kylinsp3:latest /sbin/init

[Step3] 基于kylinsp3镜像创建两个容器分别为kylin01和kylin02,将“/docker_volume”挂载到容器的/mnt目录。

[root@redhat ~]# docker run -d --name kylin01 --volumes-from docker_volume kylinsp3:latest /sbin/init
[root@redhat ~]# docker run -d --name kylin02 --volumes-from docker_volume kylinsp3:latest /sbin/init

[Step4] 分别查看docker_volume、kylin01和kylin03三个容器的挂载信息,可以看到三个容器的卷挂载信息都是一致的

[root@redhat ~]# docker inspect docker_volume | grep Source
[root@redhat ~]# docker inspect kylin01 | grep Source
[root@redhat ~]# docker inspect kylin02 | grep Source

[Step5] 验证:登录容器kylin01,能够读取文件内容。

[root@redhat ~]# docker exec -it kylin01 /bin/bash

[Step6] 验证:登录容器kylin01,新建文件kylin01并写入内容。

[root@17e8100decaf /]# echo "kylin01" > /mnt/kylin01.txt

[Step7] 验证:登录容器kylin02,能够读取文件内容和新建文件。

[root@redhat ~]# docker exec -it kylin02 /bin/bash
[root@ac737fc2cf39 /]# cat /mnt/hello.txt
[root@ac737fc2cf39 /]# cat /mnt/kylin01.txt
[root@ac737fc2cf39 /]# echo "kylin02" > /mnt/kylin02.txt

Docker | 容器网络管理 2026-03-21
Docker | 容器资源管控 2026-03-21

评论区