如何在 Docker 容器之间共享数据

介绍

Docker 是一个流行的集装箱化工具,用于提供软件应用程序的文件系统,其中包含他们运行所需的一切。

通常情况下,Docker 容器是短暂的,运行的时间是需要在容器中发出的命令完成的时间。然而,有时,应用程序需要共享数据访问或在容器被删除后持续数据。 数据库、用户生成的网站内容和日志文件只是一些不切实际或不可能在Docker 图像中包含的数据的例子,但哪些应用程序需要访问。

Docker 卷可以用创建容器的相同命令创建和附加,也可以独立创建任何容器并稍后附加。

前提条件

要遵循这篇文章,你需要一个 Ubuntu 20.04 服务器,具有以下内容:

<$>[注] **注:**虽然前提条件在Ubuntu 20.04上为安装Docker提供指示,但本文中关于Docker数据量的docker命令应该在其他操作系统上工作,只要Docker已安装,并将sudo用户添加到docker组中。

步骤 1 – 创建一个独立的卷

在Docker 1.9 版本中引入的Docker 创建卷命令允许您创建卷,而不将其与任何特定容器相关联。

1[environment local]
2docker volume create --name DataVolume1

显示命名,表示命令成功:

1[secondary_label Output]
2[environment local]
3DataVolume1

为了利用卷,我们将从Ubuntu图像中创建一个新的容器,使用--rm旗帜自动删除它,当我们离开时。我们还将使用-v来安装新的卷。-v需要卷的名称,一个,然后绝对路径到容器内部应该出现的卷。

1[environment local]
2docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu

在容器中,让我们把一些数据写入体积:

1[environment second]
2echo "Example1" > /datavolume1/Example1.txt

由于我们使用了--rm旗帜,我们的容器将在我们离开时自动删除,但我们的体积仍然可以访问。

1[environment second]
2exit

我们可以通过docker volume inspect来验证体积是否存在于我们的系统中:

1[environment local]
2docker volume inspect DataVolume1
 1[secondary_label Output]
 2[environment local]
 3[
 4    {
 5        "CreatedAt": "2018-07-11T16:57:54Z",
 6        "Driver": "local",
 7        "Labels": {},
 8        "Mountpoint": "/var/lib/docker/volumes/DataVolume1/_data",
 9        "Name": "DataVolume1",
10        "Options": {},
11        "Scope": "local"
12    }
13]

<$>[注] **注:**我们甚至可以在列出为山点的路径上查看主机上的数据,但是我们应该避免修改它,因为如果应用程序或容器不知道变化,则可能会导致数据损坏。

接下来,让我们开始一个新的容器并添加DataVolume1:

1[environment local]
2docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu

查看内容:

1[environment third]
2cat /datavolume1/Example1.txt
1[secondary_label Output]
2[environment third]
3Example1

走出容器:

1[environment third]
2exit

在本示例中,我们创建了一个卷,将其附在一个容器上,并验证其持久性。

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

在下一个示例中,我们将与容器同时创建一个体积,删除容器,然后将体积附加到新的容器中。

我们将使用docker run命令创建一个新的容器,使用Ubuntu的基本图像。-t将给我们一个终端,而-i将允许我们与它进行交互。

v旗帜将允许我们创建一个新的卷,我们将称之为DataVolume2。我们将使用一个子来将这个名称与容器中应该安装的卷的路径分开。

1[environment local]
2docker 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 容器和主机之间共享数据 <$>

在容器中,我们将写一些数据到卷:

1[environment second]
2echo "Example2" > /datavolume2/Example2.txt
3cat /datavolume2/Example2.txt
1[secondary_label Output]
2[environment second]
3Example2

让我们走出容器:

1[environment second]
2exit

当我们重新启动容器时,音量将自动安装:

1[environment local]
2docker start -ai Container2

让我们来验证,这个量是否真的增加了,我们的数据仍然存在:

1[environment second]
2cat /datavolume2/Example2.txt
1[secondary_label Output]
2[environment second]
3Example2

最后,我们走出去,清理一下:

1[environment second]
2exit

Docker 不允许我们删除一卷,如果它被容器引用. 让我们看看当我们尝试时会发生什么:

1[environment local]
2docker volume rm DataVolume2

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

1[secondary_label Output]
2[environment local]
3Error response from daemon: unable to remove volume: remove DataVolume2: volume is in use - [d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63]

我们可以使用此ID来删除容器:

1[environment local]
2docker rm d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
1[secondary_label Output]
2[environment local]
3d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63

删除容器不会影响体积,我们可以看到它仍然存在于系统上,通过列出docker volume ls的体积:

1[environment local]
2docker volume ls
1[secondary_label Output]
2[environment local]
3DRIVER VOLUME NAME
4local DataVolume2

我们可以使用docker volume rm来删除它:

1[environment local]
2docker volume rm DataVolume2

在本示例中,我们在创建容器的同时创建了一个空数据量. 在下一个示例中,我们将探讨当我们创建一个包含数据的容器目录的卷时会发生什么。

步骤 3 — 创建来自数据的现有目录的卷

一般来说,使用docker 创建卷独立创建卷和在创建容器时创建卷等同于一个例外,如果我们在创建容器同时创建卷 and 我们提供包含数据的目录路径,该数据将被复制到卷中。

例如,我们将创建一个容器,并在 /var 中添加数据量,该目录包含基图像中的数据:

1[environment local]
2docker run -ti --rm -v DataVolume3:/var ubuntu

从基础图像的/var目录的所有内容都被复制到卷中,我们可以将该卷装在一个新的容器中。

退出当前的容器:

1[environment second]
2exit

这次,而不是依靠基本图像的默认bash命令,我们将发出自己的ls命令,该命令将显示卷的内容而不输入壳:

1[environment local]
2docker run --rm -v DataVolume3:/datavolume3 ubuntu ls datavolume3

该目录 datavolume3现在有基础图像 /var 目录的内容的副本:

 1[secondary_label Output]
 2[environment local]
 3backups
 4cache
 5lib
 6local
 7lock
 8log
 9mail
10opt
11run
12spool
13tmp

我们不太可能希望以这种方式安装 /var/,但如果我们已经创建了自己的图像,并且想要一个简单的方法来保存数据,那么这可能是有帮助的。

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

到目前为止,我们已经将一个卷附加到一个集装箱一次. 通常,我们会希望多个集装箱附加到相同的数据量. 这是相对简单的,但有一个关键的警告:在这个时候,Docker 不会处理文件锁定。

创建 Container4 和 DataVolume4

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

1[environment local]
2docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu

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

1[environment second]
2echo "This file is shared between containers" > /datavolume4/Example4.txt

然后,我们将离开容器:

1[environment second]
2exit

这将使我们回到主机命令提示,在那里我们将创建一个新的容器,将数据量从Container4安装。

从集装箱4创建集装箱5和集装卷

我们将创建Container5,并从Container4中安装卷:

1[environment local]
2docker run -ti --name=Container5 --volumes-from Container4 ubuntu

让我们来看看数据的持续性:

1[environment third]
2cat /datavolume4/Example4.txt
1[secondary_label Output]
2[environment third]
3This file is shared between containers

现在让我们添加一些从Container5的文本:

1[environment third]
2echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt

最后,我们将离开容器:

1[environment third]
2exit

接下来,我们会检查我们的数据是否仍然存在于Container4

查看在集装箱5中做的更改

让我们通过重新启动Container4来检查Container5写入数据量的更改:

1[environment local]
2docker start -ai Container4

查看更改:

1[environment second]
2cat /datavolume4/Example4.txt
1[secondary_label Output]
2[environment second]
3This file is shared between containers
4Both containers can write to DataVolume4

现在我们已经验证了这两个容器能够从数据量中读写,我们将退出容器:

1[environment second]
2exit

再次,Docker 无法处理任何文件锁定,因此应用程序 must 会考虑文件锁定本身. 可以将Docker 卷设置为仅读式,以确保数据破坏不会偶然发生,当容器需要仅读式访问时,通过添加 :ro

启动集装箱 6 并安装 Volume Read-Only

一旦一个卷已经安装在一个容器中,而不是像我们用典型的Linux文件系统一样卸载它,我们可以相反地创建一个新的容器,以我们想要的方式安装,如果需要,删除以前的容器。

1[environment local]
2docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu

我们将通过尝试删除我们的示例文件来检查仅读状态:

1[environment fourth]
2rm /datavolume4/Example4.txt
1[secondary_label Output]
2[environment fourth]
3rm: cannot remove '/datavolume4/Example4.txt': Read-only file system

最后,我们将离开容器,清理我们的测试容器和卷:

1[environment fourth]
2exit

现在我们已经完成了,让我们清理我们的容器和体积:

1[environment local]
2docker rm Container4 Container5 Container6
3docker volume rm DataVolume4

在本示例中,我们展示了如何使用数据量在两个容器之间共享数据,以及如何将数据量设置为只读。

结论

在本教程中,我们创建了一个数据量,允许数据通过删除一个容器继续存在。我们在容器之间共享数据量,并警告说应用程序需要设计以处理文件锁定以防止数据破坏。

Published At
Categories with 技术
comments powered by Disqus