介绍
Docker 是一个流行的集装箱化工具,用于提供软件应用程序的文件系统,其中包含他们运行所需的一切。
通常情况下,Docker 容器是短暂的,运行的时间是需要在容器中发出的命令完成的时间。然而,有时,应用程序需要共享数据访问或在容器被删除后持续数据。 数据库、用户生成的网站内容和日志文件只是一些不切实际或不可能在Docker 图像中包含的数据的例子,但哪些应用程序需要访问。
Docker 卷可以用创建容器的相同命令创建和附加,也可以独立创建任何容器并稍后附加。
前提条件
要遵循这篇文章,你需要一个 Ubuntu 20.04 服务器,具有以下内容:
- 具有 sudo 特权的非 root 用户. 使用 Ubuntu 20.04 的初始服务器设置(https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-20-04)指南解释了如何设置此设置。
- 安装了 Docker 根据 [如何在 Ubuntu 20.04 上安装和使用 Docker] 的 步骤 1 和 步骤 2 的说明。
<$>[注]
**注:**虽然前提条件在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
在本示例中,我们展示了如何使用数据量在两个容器之间共享数据,以及如何将数据量设置为只读。
结论
在本教程中,我们创建了一个数据量,允许数据通过删除一个容器继续存在。我们在容器之间共享数据量,并警告说应用程序需要设计以处理文件锁定以防止数据破坏。