如何在Ubuntu22.04上的Docker容器之间共享数据

来自菜鸟教程
跳转至:导航、​搜索

介绍

Docker 是一种流行的容器化工具,用于为软件应用程序提供一个文件系统,该文件系统包含它们运行所需的一切。 使用 Docker 容器可确保软件无论部署在何处都以相同的方式运行,因为它的运行时环境是一致的。

通常,Docker 容器是短暂的,运行时间与容器中发出的命令完成所需的时间一样长。 然而,有时,应用程序需要在容器被删除后共享数据访问或持久化数据。 数据库、用户为网站生成的内容和日志文件只是不切实际或不可能包含在 Docker 映像中但应用程序需要访问的数据的几个示例。 Docker Volumes 提供对数据的持久访问。

Docker 卷可以在创建容器的同一命令中创建和附加,也可以独立于任何容器创建并在以后附加。 在本文中,您将了解在容器之间共享数据的四种不同方式。

先决条件

要阅读本文,您将需要一个 Ubuntu 22.04 服务器,其中包含以下内容:

注意: 尽管先决条件给出了在 Ubuntu 22.04 上安装 Docker 的说明,但只要安装了 Docker 并且sudo 用户已添加到 docker 组。


第 1 步 — 创建独立卷

在 Docker 的 1.9 版本中引入的 docker volume create 命令允许您创建卷,而无需将其与任何特定容器相关联。 您将使用此命令添加名为 DataVolume1 的卷:

docker volume create --name DataVolume1

显示名称,说明命令成功:

OutputDataVolume1

要使用该卷,您将从 Ubuntu 映像创建一个新容器,使用 --rm 标志在您退出时自动删除它。 您还将使用 -v 安装新卷。 -v 需要卷的名称、冒号,然后是卷应出现在容器内的绝对路径。 如果路径中的目录不作为映像的一部分存在,则将在命令运行时创建它们。 如果他们 do 存在,挂载的卷将隐藏现有的内容:

docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu

在容器中,将一些数据写入卷:

echo "Example1" > /datavolume1/Example1.txt

因为您使用了 --rm 标志,所以您的容器将在您退出时自动删除。 但是,您的卷仍然可以访问。

exit

您可以使用 docker volume inspect 验证系统上是否存在卷:

docker volume inspect DataVolume1
Output[
    {
        "CreatedAt": "2018-07-11T16:57:54Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/DataVolume1/_data",
        "Name": "DataVolume1",
        "Options": {},
        "Scope": "local"
    }
]

注意:你甚至可以查看主机上的数据,路径为Mountpoint。 但是,您应该避免更改它,因为如果应用程序或容器不知道更改,它可能会导致数据损坏。


接下来,启动一个新容器并附加 DataVolume1

docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu

验证内容:

cat /datavolume1/Example1.txt
OutputExample1

退出容器:

exit

在此示例中,您创建了一个卷,将其附加到一个容器,并验证了它的持久性。

第 2 步 — 创建一个在容器被移除时仍然存在的卷

在下一个示例中,您将在创建容器的同时创建一个卷,删除该容器,然后将该卷附加到一个新容器。

您将使用 docker run 命令使用基本 Ubuntu 映像创建一个新容器。 -t 将给我们一个终端,-i 将允许我们与之交互。 为清楚起见,您将使用 --name 来标识容器。

-v 标志将允许我们创建一个新卷,您将其称为 DataVolume2。 您将使用冒号将此名称与容器中应安装卷的路径分开。 最后,您将指定基本 Ubuntu 映像并依赖 Ubuntu 基本映像的 Docker 文件bash 中的默认命令,将我们放入 shell:

docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu

注意: -v 标志非常灵活。 它可以绑定或命名一个卷,只需稍微调整语法。 如果第一个参数以 /~/ 开头,则您正在创建绑定挂载。 删除它,您将命名该卷。 例如:

  • -v /path:/path/in/container挂载主机目录,/path/path/in/container
  • -v path:/path/in/container 创建一个名为 path 的卷,与主机无关。

有关从主机绑定目录的更多信息,请参阅 如何在 Docker 容器和主机之间共享数据


在容器中,您将向卷中写入一些数据:

echo "Example2" > /datavolume2/Example2.txt
cat /datavolume2/Example2.txt
OutputExample2

退出容器:

exit

重新启动容器时,卷将自动挂载:

docker start -ai Container2

验证卷确实已安装并且您的数据仍然存在:

cat /datavolume2/Example2.txt
OutputExample2

最后,退出并清理:

exit

如果容器引用了卷,Docker 不会让我们删除它。 要查看会发生什么,请尝试:

docker volume rm DataVolume2

该消息告诉我们该卷仍在使用中,并提供了容器 ID 的长版本:

OutputError response from daemon: unable to remove volume: remove DataVolume2: volume is in use - [d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63]

您可以使用上述错误消息中的 ID 来移除容器:

docker rm d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
Outputd0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63

移除容器不会影响音量。 通过使用 docker volume ls 列出卷,您可以看到它仍然存在于系统中:

docker volume ls
OutputDRIVER              VOLUME NAME
local               DataVolume2

您可以使用 docker volume rm 删除它:

docker volume rm DataVolume2

在此示例中,您在创建容器的同时创建了一个空数据卷。 在您的下一个示例中,您将探索使用已包含数据的容器目录创建卷时会发生什么。

第 3 步 — 从包含数据的现有目录创建卷

一般来说,使用docker volume create独立创建卷和创建容器的同时创建卷是等价的,只有一个例外。 如果在创建容器 的同时创建卷,则提供包含基础映像中数据的目录的路径,该数据将被复制到卷中。

例如,您将创建一个容器并在 /var 中添加数据卷,该目录包含基础映像中的数据:

docker run -ti --rm -v DataVolume3:/var ubuntu

基础镜像的 /var 目录中的所有内容都会复制到卷中,您可以将该卷挂载到新容器中。

退出当前容器:

exit

这一次,您将发出自己的 ls 命令,而不是依赖基础映像的默认 bash 命令,该命令将在不进入 shell 的情况下显示卷的内容:

docker run --rm -v DataVolume3:/datavolume3 ubuntu ls datavolume3

目录 datavolume3 现在具有基本映像的 /var 目录内容的副本:

Outputbackups
cache
lib
local
lock
log
mail
opt
run
spool
tmp

您不太可能希望以这种方式挂载 /var/,但如果您已经制作了自己的映像并想要一种简单的方法来保存数据,这可能会有所帮助。 在下一个示例中,您将演示如何在多个容器之间共享卷。

第 4 步 — 在多个 Docker 容器之间共享数据

到目前为止,您一次将一个卷附加到一个容器。 通常,您会希望将多个容器附加到同一个数据卷。 这相对容易实现,但有一个关键警告:此时,Docker 不处理文件锁定。 如果您需要多个容器写入卷,则在这些容器中运行的应用程序 必须 设计为写入共享数据存储,以防止数据损坏。

创建 Container4 和 DataVolume4

使用 docker run 创建一个名为 Container4 的新容器,并附加一个数据卷:

docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu

接下来,您将创建一个文件并添加一些文本:

echo "This file is shared between containers" > /datavolume4/Example4.txt

然后,您将退出容器:

exit

这会将我们返回到主机命令提示符,您将在其中创建一个新容器,用于从 Container4 装载数据卷。

创建 Container5 并从 Container4 挂载卷

您将创建 Container5,并从 Container4 挂载卷:

docker run -ti --name=Container5 --volumes-from Container4 ubuntu

检查数据持久性:

cat /datavolume4/Example4.txt
OutputThis file is shared between containers

现在,从 Container5 添加一些文本:

echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt

最后,您将退出容器:

exit

接下来,您将检查您的数据是否仍然存在于 Container4 中。

查看 Container5 中所做的更改

现在,通过重新启动 Container4 检查 Container5 写入数据卷的更改:

docker start -ai Container4

检查更改:

cat /datavolume4/Example4.txt
OutputThis file is shared between containers
Both containers can write to DataVolume4

现在您已经验证了两个容器都能够从数据卷中读取和写入,您将退出容器:

exit

同样,Docker 不处理任何文件锁定,因此应用程序 必须 自行考虑文件锁定。 可以通过添加 :ro 将 Docker 卷挂载为只读,以确保在容器需要只读访问时不会意外发生数据损坏。 现在,您将了解它是如何工作的。

启动 Container 6 并以只读方式挂载卷

一旦卷被安装到容器中,而不是像使用典型的 Linux 文件系统那样卸载它,您可以创建一个以您想要的方式安装的新容器,如果需要,删除以前的容器。 要将卷设为只读,请将 :ro 附加到容器名称的末尾:

docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu

您将通过尝试删除示例文件来检查只读状态:

rm /datavolume4/Example4.txt
Outputrm: cannot remove '/datavolume4/Example4.txt': Read-only file system

最后,您将退出容器并清理您的测试容器和卷:

exit

现在你已经完成了,清理你的容器和卷:

docker rm Container4 Container5 Container6
docker volume rm DataVolume4

在此示例中,您展示了如何使用数据卷在两个容器之间共享数据,以及如何将数据卷挂载为只读。

结论

在本教程中,您创建了一个数据卷,该卷允许数据通过删除容器来保留。 您在容器之间共享数据卷,但需要注意的是应用程序需要设计为处理文件锁定以防止数据损坏。 最后,您展示了如何以只读模式安装共享卷。 如果您有兴趣了解容器和主机系统之间的数据共享,请参阅如何在 Docker 容器和主机之间共享数据