返回介绍

六、使用挂载

发布于 2025-11-02 16:55:28 字数 24482 浏览 0 评论 0 收藏

Swarm 中的服务任务容器可以访问从其 Docker 映像继承的文件系统。数据通过其 Docker 映像集成到 Docker 容器中。有时,Docker 容器可能需要在持久文件系统上存储或访问数据。虽然容器有一个文件系统,但是一旦容器退出,它就会被删除。为了在容器重启时存储数据,数据必须保存在容器之外的某个地方。

问题

仅存储在容器中的数据可能会导致以下问题:

  • 数据不是持久的。当 Docker 容器停止时,数据将被删除。
  • 数据不能与其他 Docker 容器或主机文件系统共享。

解决方案

基于单一责任原则(SRP) 的模块化设计建议将数据从 Docker 容器中分离出来。Docker Swarm 模式提供了共享数据的挂载,并使数据在容器启动和关闭时保持持久。Docker Swarm 模式为服务提供了两种类型的挂载:

  • 卷装载
  • 绑定安装

默认值是卷装载。使用 docker service create 命令的 --mount 选项创建服务的挂载。

卷装载

卷装载是主机上装载到服务任务容器中的命名卷。即使在停止和删除容器后,主机上的命名卷仍然存在。可以在创建使用该卷的服务之前创建命名卷,或者可以在服务部署时创建该卷。在部署时创建的命名卷是在启动服务任务容器之前创建的。如果在服务部署时创建,并且未指定卷名,则命名卷会自动生成一个名称。图 6-1 显示了一个卷挂载的例子,其中一个在创建服务之前就存在的命名卷 mysql-scripts 被挂载到目录路径 /etc/mysql/scripts 下的服务任务容器中。

A454123_1_En_6_Fig1_HTML.gif

图 6-1。

Volume mount

服务中的每个容器都可以访问运行该容器的主机上的相同命名卷,但是该主机命名卷可以存储相同或不同的数据。

使用卷装载时,内容不会跨群集复制。例如,如果您将某些内容放入正在使用的 mysql-scripts 目录,这些新文件将只能被运行在同一节点上的其他任务访问。在其他节点上运行的副本将无法访问这些文件。

绑定安装

绑定装载是要在其上计划服务任务的主机上的文件系统路径。主机文件系统路径被装载到服务任务容器的指定目录路径中。主机文件系统路径必须存在于群中的每个主机上,在创建服务之前可以在其上调度任务。如果使用节点约束将某些节点排除在服务部署之外,则绑定装载主机文件系统不必存在于这些节点上。使用绑定挂载时,请记住使用绑定挂载的服务本身是不可移植的。如果要在生产中部署服务,主机目录路径必须存在于生产集群中的每个主机上。

主机文件系统路径不必与任务容器中的目标目录路径相同。例如,在图 6-2 中,主机路径 /db/mysql/data 作为绑定挂载被挂载到目录路径 /etc/mysql/data 的服务容器中。默认情况下,绑定装载是读写的,但是在服务部署时可以设置为只读。服务中的每个容器都可以访问运行容器的主机上的相同目录路径,但是主机目录路径可以存储不同或相同的数据。

A454123_1_En_6_Fig2_HTML.gif

图 6-2。

Bind mount

群模式装载在主机上提供可共享的命名卷和文件系统路径,这些路径在服务任务启动和关闭期间保持不变。Docker 映像的文件系统仍然位于文件系统层次结构的根位置,并且只能在根文件系统内的目录路径上进行挂载。

本章涵盖以下主题:

  • 设置环境
  • 安装类型
  • 创建命名卷
  • 使用卷装载来获取有关卷的详细信息
  • 删除卷
  • 创建和使用绑定装载

设置环境

为基于 AWS 的群创建一个 Docker,由一个管理节点和两个工作节点组成,如第 3 章所述。AWS Swarm 的 Docker 将用于一种类型的挂载,即卷挂载。对于绑定挂载,在 CoreOS 实例上创建一个由一个管理器和两个工作者节点组成的三节点集群。在第二章 中讨论了在 CoreOS 实例上创建蜂群。使用基于 CoreOS 的 Swarm 是因为 Docker for AWS Swarm 不支持开箱即用的绑定挂载。从 EC2 控制台获取 AWS Swarm Docker 的 manager 实例的公共 IP 地址,如图 6-3 所示。

A454123_1_En_6_Fig3_HTML.jpg

图 6-3。

EC2 instances for Docker for AWS Swarm nodes

SSH 登录到管理器实例。

[root@localhost ∼]# ssh -i "docker.pem" docker@52.91.115.180
Welcome to Docker!

列出群体中的节点。列出了一个管理节点和两个工作节点。

∼ $ docker node ls
ID                          HOSTNAME                      STATUS AVAILABILITY MANAGER STATUS
8ynq7exfo5v74ymoe7hrsghxh   ip-172-31-33-230.ec2.internal Ready  Active             
o0h7o09a61ico7n1t8ooe281g * ip-172-31-16-11.ec2.internal  Ready  Active       Leader
yzlv7c3qwcwozhxz439dbknj4   ip-172-31-25-163.ec2.internal Ready  Active              

创建命名卷

在服务中用作卷类型装载的命名卷可以在创建服务之前创建,也可以在部署时创建。使用以下命令语法创建新的命名卷。

docker volume create [OPTIONS] [VOLUME]

支持表 6-1 中讨论的选项。

表 6-1。

Options for the docker volume create Command for a Named Volume

| [计]选项 | 描述 | 类型 | 缺省值 | | --- | --- | --- | --- | | `--driver, -d` | 指定卷驱动程序名称 | `string` | `local` | | `--label` | 设置卷的元数据 | `value` | `[]` | | `--name` | 指定卷名 | `string` | | | `--opt, -o` | 设置驱动程序特定选项 | `value` | `map[]` |

使用 docker volume create 命令创建一个名为 hello 的命名卷。

∼ $ docker volume create --name  hello
hello

随后,使用 docker volume ls 命令列出卷。除了可能存在的其他命名卷之外,还列出了 hello 卷。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello

您可以使用以下命令找到有关该卷的详细信息。

docker volume inspect hello

除了卷名和驱动程序之外,还会列出卷的挂载点。

∼ $ docker volume inspect hello
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/hello/_data",
        "Name": "hello",
        "Options": {},
        "Scope": "local"
    }
]

本地驱动程序卷的范围是 local 。另一个支持的范围是 global 。在单个 Docker 主机上创建一个 local 卷,在集群中的每个 Docker 主机上创建一个 global 卷。

使用卷装载

使用带有 --mount 选项的 docker service create 命令中的 hello 音量。表 6-2 中讨论的选项可用于绑定挂载和卷挂载。

表 6-2。

Options for Volume and Bind Mounts

| [计]选项 | 需要 | 描述 | 默认 | | `type` | 不 | 指定装载的类型。可以指定三个值之一:`volume-Mounts`是容器中的命名卷。`bind-Bind-mounts`是将一个目录或文件从主机放入一个容器中。`tmpfs-Mounts`是一只`tmpfs`变成的容器。 | `volume` | | `src`或`source` | 仅适用于`type=bind`。`type=volume`的否 | 源目录或卷。该选项对于不同类型的挂载有不同的含义。`type=volume: src`指定卷的名称。如果指定的卷不存在,则创建该卷。如果省略了`src`,则使用自动生成的名称创建命名卷,该名称在主机上是唯一的,但在群集范围内可能不是唯一的。当使用卷的容器被删除时,自动生成的命名卷也被删除。`docker service update`命令关闭任务容器并启动新的任务容器,扩展服务也是如此。`volume source`不能是绝对路径。`type=bind: src`指定要绑定挂载的目录或文件的绝对路径。目录路径必须是绝对路径,而不是相对路径。类型为`bind`的挂载需要`src`选项,如果没有指定,就会产生错误。不支持`type=tmpfs:`。 | | | `dst`或`destination`或`target` | 是 | 指定容器内的挂载路径。如果容器的文件系统中不存在该路径,Docker 引擎会在挂载绑定或卷挂载之前创建挂载路径。卷目标必须是相对路径。 | | | `readonly`或`ro` | 不 | 一个布尔值(真/假) 或(1/0) 来指示 Docker 引擎应该装入卷并绑定读写还是只读。如果未指定选项,引擎将装载绑定或卷读写。如果将该选项指定为 true 值、1 值或无值,则引擎会以只读方式装载卷或绑定。如果将该选项指定为值 false 或 0,则引擎会装载卷或绑定读写。 | |

一些装载选项仅支持卷装载,并在表 6-3 中讨论。

表 6-3。

Options for Volume Mounts

| [计]选项 | 需要 | 描述 | 缺省值 | | --- | --- | --- | --- | | `volume-driver` | 不 | 指定用于卷的卷驱动程序插件的名称。如果在`src`中没有指定命名卷,则`volume-driver`用于创建一个命名卷。 | `local` | | `volume-` `label` | 不 | 指定要应用于卷的一个或多个逗号分隔的元数据标签。例子:`volume-label=label-1=hello-world,label-2=hello`。 | | | `volume-nocopy` | 不 | 适用于在文件和目录已经存在的装载路径的容器中装载的空卷。指定是否将挂载路径(`dst`) 下容器的文件系统文件和目录复制到卷中。主机能够访问从容器复制到指定卷的文件和目录。true 或 1 值禁止将文件从容器的文件系统复制到主机卷。false 或 0 值表示允许复制。 | 真或 1 | | `volume-` `opt` | 不 | 指定在创建命名卷(如果不存在) 时提供给`volume-driver`的选项。`volume-opt`选项被指定为逗号分隔的键/值对列表。例如:`volume-opt-1=option-1=value1,option-2=value2`。要装载卷类型装载的每个主机上都必须有一个命名卷。在 Swarm manager 上创建命名卷并不会在 worker 节点上创建命名卷。`volume-driver`和`volume-opt`选项用于在工作节点上创建命名卷。 | |

表 6-4 中讨论的选项仅支持 tmpfs 类型的安装。

表 6-4。

Options for the tmpfs Mount

| [计]选项 | 需要 | 描述 | 缺省值 | | --- | --- | --- | --- | | `tmpfs-size` | 不 | 以字节为单位的`tmpfs`挂载的大小 | Linux 的无限价值 | | `tmpfs-` `mode` | 不 | 以八进制指定`tmpfs`的文件模式 | `1777`在 Linux 中 |

接下来,我们将在用 Docker 映像 tutum/hello-world 创建的服务中使用命名卷 hello 。在下面的 docker service create 命令中, --mount 选项将 src 指定为 hello ,并包含一些卷的 volume-label 标签。

∼ $ docker service create \
   --name hello-world \
   --mount src=hello,dst=/hello,volume-label="msg=hello",volume-label="msg2=world" \
   --publish 8080:80 \
   --replicas 2 \
   tutum/hello-world

创建服务并输出服务 ID。

∼ $ docker service create \
>   --name hello-world \
>   --mount src=hello,dst=/hello,volume-label="msg=hello",volume-label="msg2=world" \
>   --publish 8080:80 \
>   --replicas 2 \
>   tutum/hello-world
8ily37o72wyxkyw2jt60kdqoz

创建了两个服务副本。

∼ $ docker service ls
ID            NAME          MODE        REPLICAS  IMAGE                      PORTS
8ily37o72wyx  hello-world   replicated  2/2       tutum/hello-world:latest   *:8080->80/tcp
∼ $ docker service ps hello-world
ID            NAME                IMAGE                        NODE             DESIRED STATE       CURRENT STATE            ERROR              PORTS
uw6coztxwqhf  hello-world.1       tutum/hello-world:latest     ip-172-31-25-163.ec2.internalRunning             Running 20 seconds ago
cfkwefwadkki  hello-world.2       tutum/hello-world:latest     ip-172-31-16-11.ec2.internalRunning             Running 21 seconds ago                       

命名的卷安装在服务的每个任务容器中。

服务定义列出了装载,包括装载标签。

∼ $ docker service inspect hello-world
[
     ...
        "Spec": {
                "ContainerSpec": {
                    "Image": "tutum/hello-world:latest@sha256:0d57def8055178aafb4c7669cbc25ec17f0acdab97cc587f30150802da8f8d85",
                    "Mounts": [
                        {
                            "Type": "volume",
                            "Source": "hello",
                            "Target": "/hello",
                            "VolumeOptions": {
                                "Labels": {
                                    "msg": "hello",
                                    "msg2": "world"
                                },
...
]

在前面的示例中,在卷装入中使用卷之前,创建了一个命名卷。又如,在部署时创建一个命名卷。在下面的 docker service create 命令中, --mount 选项被设置为 type=volume ,源被设置为 nginx-root 。创建服务之前,命名卷 nginx-root 不存在。

∼ $ docker service create \
>   --name nginx-service \
>   --replicas 3 \
>   --mount type=volume,source="nginx-root",destination="/var/lib/nginx",volume-
label="type=nginx root dir" \
>   nginx:alpine
rtz1ldok405mr03uhdk1htlnk

运行该命令时,会创建一个服务。服务描述包括 mounts 中的卷挂载。

∼ $ docker service inspect nginx-service
[
...
        "Spec": {
            "Name": "nginx-service",
...
                    "Mounts": [
                        {
                            "Type": "volume",
                            "Source": "nginx-root",
                            "Target": "/var/lib/nginx",
                            "VolumeOptions": {
                                "Labels": {
                                    "type": "nginx root dir"
                                },
...
]

命名卷 nginx-root 不是在创建服务之前创建的,因此是在为服务任务启动容器之前创建的。命名卷 nginx-root 仅在计划任务的节点上创建。三个节点中的每一个都计划了一个服务任务。

∼ $ docker service ps nginx-service
ID                  NAME                IMAGE               NODE                         DESIRED STATE       CURRENT STATE            ERROR               PORTS
pfqinizqmgur        nginx-service.1     nginx:alpine        ip-172-31-33-230.ec2.internalRunning             Running 19 seconds ago                       
mn8h3p40chgs        nginx-service.2     nginx:alpine        ip-172-31-25-163.ec2.internalRunning             Running 19 seconds ago                       
k8n5zzlnn46s        nginx-service.3     nginx:alpine        ip-172-31-16-11.ec2.internalRunning             Running 18 seconds ago                       

当在管理器节点上调度任务时,在管理器节点上创建一个名为 nginx-root 的命名卷,如 docker volume ls 命令的输出中所列。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

服务任务和任务容器在两个工作节点的每一个上启动。在每个工作节点上创建一个 nginx-root 命名卷。列出工作节点上的卷会列出 nginx-root 卷。

[root@localhost ∼]# ssh -i "docker.pem" docker@34.229.86.64
Welcome to Docker!
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

[root@localhost ∼]# ssh -i "docker.pem" docker@52.91.200.241
Welcome to Docker!
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

在前面的示例中,在 src 中指定了一个命名卷。在下面的服务定义中,可以省略指定的卷。

∼ $ docker service create \
>   --name nginx-service-2 \
>   --replicas 3 \
>   --mount type=volume,destination=/var/lib/nginx   \
>   nginx:alpine
q8ordkmkwqrwiwhmaemvcypc3

服务是用一个副本创建的,并在每个群节点上进行调度。

∼ $ docker service ps nginx-service-2
ID                  NAME                IMAGE               NODE                           DESIRED STATE       CURRENT STATE            ERROR               PORTS
kz8d8k6bxp7u        nginx-service-2.1   nginx:alpine        ip-172-31-25-163.ec2.internalRunning             Running 27 seconds ago                       
wd65qsmqixpg        nginx-service-2.2   nginx:alpine        ip-172-31-16-11.ec2.internalRunning             Running 27 seconds ago                       
mbnmzldtaaed        nginx-service-2.3   nginx:alpine        ip-172-31-33-230.ec2.internalRunning             Running 26 seconds ago                       

服务定义没有列出命名卷。

∼ $ docker service inspect nginx-service-2
[
        "Spec": {
            "Name": "nginx-service-2",
                "ContainerSpec": {
                    "Mounts": [
                        {
                            "Type": "volume",
                            "Target": "/var/lib/nginx"
                        }
                    ],
...
]

如果没有明确指定卷名,则会创建具有自动生成名称的命名卷。在运行服务任务的每个节点上,都会创建一个具有自动生成名称的自动生成的命名卷。manager 节点上列出的一个命名卷是自动生成的命名卷,具有自动生成的名称。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               305f1fa3673e811b3b320fad0e2dd5786567bcec49b3e66480eab2309101e233
local               hello
local               nginx-root

作为在服务中使用命名卷作为挂载的另一个例子,为 MySQL 数据库服务创建一个名为 mysql-scripts 的命名卷。

∼ $ docker volume create --name mysql-scripts
mysql-scripts

命名的卷已创建并列出。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               305f1fa3673e811b3b320fad0e2dd5786567bcec49b3e66480eab2309101e233
local               hello
local               mysql-scripts
local               nginx-root

卷描述将范围列为 local ,并列出挂载点。

∼ $ docker volume inspect mysql-scripts
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mysql-scripts/_data",
        "Name": "mysql-scripts",
        "Options": {},
        "Scope": "local"
    }
]

接下来,创建一个在卷装载中使用命名卷的服务。

∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --mount type=volume,src="mysql-scripts",dst="/etc/mysql/scripts",
      el="msg=mysql",volume-label="msg2=scripts" \
> --publish 3306:3306\
>   --replicas 2 \
>   --name mysql \
>  mysql
cghaz4zoxurpyqil5iknqf4c1

服务被创建并列出。

∼ $ docker service ls
ID             NAME         MODE        REPLICAS  IMAGE                     PORTS
8ily37o72wyx   hello-world  replicated  2/2       tutum/hello-world:latest  *:8080->80/tcp
cghaz4zoxurp   ysql         replicated  1/2       mysql:latest              *:3306->3306/tcp

列出服务任务表明任务被安排在管理器节点和一个工作者节点上。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                     DESIRED STATE       CURRENT STATE                    ERROR               PORTS
y59yhzwch2fj        mysql.1             mysql:latest        ip-172-31-33-230.ec2.internalRunning             Preparing 12 seconds ago                             
zg7wrludkr84        mysql.2             mysql:latest        ip-172-31-16-11.ec2.internalRunning             Running less than a second ago                       

命名卷的目标目录在 Docker 容器中创建。管理节点上的 Docker 容器可以用 docker ps 列出,容器上的 bash shell 可以用 docker exec -it <containerid> bash 命令启动。

∼ $ docker ps
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS              PORTS                         NAMES
a855826cdc75        mysql:latest                                "docker-entrypoint..."   22 seconds ago      Up 21 seconds       3306/tcp                      mysql.2.zg7wrludkr84zf8vhdkf8wnlh
∼ $ docker exec -it a855826cdc75 bash
root@a855826cd75:/#

将目录更改为容器中的 /etc/mysql/scripts 。最初,目录是空的。

root@a855826cdc75:/# cd /etc/mysql/scripts
root@a855826cdc75:/etc/mysql/scripts# ls -l
total 0
root@a855826cdc75:/etc/mysql/scripts# exit
exit

在工作者节点之一上创建服务的任务容器,并且可以在工作者节点上列出该任务容器。

∼ $ docker ps
CONTAINER ID        IMAGE                            COMMAND        CREATED             STATUS          PORTS                NAMES
eb8d59cc2dff        mysql:latest                     "docker-entrypoint..."     8 minutes ago       Up 8 minutes    3306/tcp             mysql.1.xjmx7qviihyq2so7n0oxi1muq

在 worker 节点上为 Docker 容器启动一个 bash shell。在 Docker 容器中创建了挂载指定卷的 /etc/mysql/scripts 目录。

∼ $ docker exec -it eb8d59cc2dff bash
root@eb8d59cc2dff:/# cd /etc/mysql/scripts
root@eb8d59cc2dff:/etc/mysql/scripts# exit
exit

如果使用自动生成的命名卷的服务被扩展为在先前未运行任务的节点上运行任务,则命名卷也会在这些节点上自动生成。作为在服务中使用自动生成的命名卷作为挂载时发现扩展服务的效果的示例,创建一个带有卷挂载的 MySQL 数据库服务。在创建服务之前,卷 mysql-scripts 不存在;移除 mysql-scripts 卷(如果存在)。

∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --replicas 1 \
>   --mount type=volume,src="mysql-scripts",dst="/etc/mysql/scripts"\
>   --name mysql \
>  mysql
088ddf5pt4yb3yvr5s7elyhpn

服务任务被安排在一个节点上。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                   DESIRED STATE       CURRENT STATE              ERROR               PORTS
xlix91njbaq0        mysql.1             mysql:latest        ip-172-31-13-122.ec2.internalRunning             Preparing 12 seconds ago               

列出节点;安排服务任务的节点是管理器节点。

∼ $ docker node ls
ID                           HOSTNAME                      STATUS  AVAILABILITY  MANAGER STATUS
o5hyue3hzuds8vtyughswbosl    ip-172-31-11-41.ec2.internal   Ready  Active              
p6uuzp8pmoahlcwexr3wdulxv    ip-172-31-23-247.ec2.internal  Ready  Active              
qnk35m0141lx8jljp87ggnsnq *  ip-172-31-13-122.ec2.internal  Ready  Active        Leader

在调度任务的 manager 节点上创建一个命名卷 mysql-scripts 和一个具有自动生成名称的辅助命名卷。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               a2bc631f1b1da354d30aaea37935c65f9d99c5f084d92341c6506f1e2aab1d55
local               mysql-scripts

工作节点没有列出 mysql-scripts 命名卷,因为工作节点上没有调度任务。

∼ $ docker volume ls
DRIVER              VOLUME NAME

将服务扩展到三个副本。在三个节点中的每一个节点上都安排了一个复制副本。

∼ $ docker service scale mysql=3
mysql scaled to 3

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                  DESIRED STATE       CURRENT STATE                    ERROR               PORTS
xlix91njbaq0        mysql.1             mysql:latest        ip-172-31-13-122.ec2.internal Running             Running about a minute ago                           
ifk7xuvfp9p2        mysql.2             mysql:latest        ip-172-31-23-247.ec2.internal Running             Running less than a second ago                       
3c53fxgcjqyt        mysql.3             mysql:latest        ip-172-31-11-41.ec2.internal Running             Running less than a second ago                       

由于计划了一个副本,因此在工作节点上创建了一个命名卷 mysql-scripts 和一个具有自动生成名称的辅助命名卷。

[root@localhost ∼]# ssh -i "docker.pem" docker@54.165.69.9
Welcome to Docker!

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               431a792646d0b04b5ace49a32e6c0631ec5e92f3dda57008b1987e4fe2a1b561
local               mysql-scripts
[root@localhost ∼]# ssh -i "docker.pem" docker@34.232.95.243
Welcome to Docker!

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               afb2401a9a916a365304b8aa0cc96b1be0c161462d375745c9829f2b6f180873
local               mysql-scripts

自动生成的命名卷是永久性的,不会在服务复制副本关闭时被删除。具有自动生成名称的命名卷不是永久卷。例如,将服务扩展回一个副本。两个复制副本关闭,包括管理器节点上的复制副本。

∼ $ docker service scale mysql=1
mysql scaled to 1
∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                      DESIRED STATE       CURRENT STATE           ERROR               PORTS
3c53fxgcjqyt        mysql.3             mysql:latest        ip-172-31-11-41.ec2.internal Running             Running 2 minutes ago                   

但是管理器节点上的命名卷 mysql-scripts 不会被删除,即使没有使用该卷的 Docker 容器正在运行。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               mysql-scripts

类似地,关闭服务副本的工作节点上的命名卷也不会被删除,即使没有使用该命名卷的 Docker 容器正在运行。当没有容器在使用时,具有自动生成名称的命名卷会被删除,但 mysql-scripts 命名卷不会被删除。

移除卷 mysql-scripts 仍未移除。

∼ $ docker service rm mysql
mysql
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               mysql-scripts

删除卷

可以使用以下命令删除命名卷。

docker volume rm  <VOL>

例如,删除命名卷 mysql-scripts

∼ $ docker volume rm mysql-scripts
mysql-scripts

如果您尝试删除的卷在 Docker 容器中使用,则会生成一个错误,并且该卷不会被删除。如果正在容器中使用,即使是具有自动生成名称的命名卷也不能删除。

创建和使用绑定装载

在本节中,我们将创建一个 bind 类型的装载。如果需要从 Docker 容器中访问主机上已经存在的目录中的数据,则适合使用绑定装载。当创建具有绑定类型装载的服务时,必须使用 --mount 选项指定 type=bind 。主机源目录和卷目标必须都是绝对路径。创建服务之前,主机源目录必须存在。服务的每个 Docker 容器中的目标目录是自动创建的。在管理器节点上创建一个目录,然后向该目录添加一个名为 createtable.sql 的文件。

core@ip-10-0-0-143 ∼ $ sudo mkdir -p /etc/mysql/scripts
core@ip-10-0-0-143 ∼ $ cd /etc/mysql/scripts
core@ip-10-0-0-143 /etc/mysql/scripts $ sudo vi createtable.sql

在示例 SQL 文件中保存一个 SQL 脚本,如图 6-4 所示。

A454123_1_En_6_Fig4_HTML.jpg

图 6-4。

Adding a SQL script to the host directory

类似地,创建一个目录并向 worker 节点添加一个 SQL 脚本。

使用使用主机目录的绑定装载创建服务。目标目录被指定为 /scripts

core@ip-10-0-0-143 ∼ $ docker service create \
>    --env MYSQL_ROOT_PASSWORD='mysql' \
>    --replicas 3 \
>    --mount type=bind,src="/etc/mysql/scripts",dst="/scripts" \
>    --name mysql \
>       mysql

0kvk2hk2qigqyeem8x1r8qkvk

从调度任务的节点启动服务容器的 bash shell。列出目标目录 /scripts

core@ip-10-0-0-143 ∼ $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED           STATUS              PORTS               NAMES
e71275e6c65c        mysql:latest        "docker-entrypoint.sh"   5 seconds ago       Up 4 seconds        3306/tcp            mysql.1.btqfrx7uffym2xvc441pubaza

core@ip-10-0-0-143 ∼ $ docker exec -it e71275e6c65c bash
root@e71275e6c65c:/# ls -l                                   
drwxr-xr-x.  2 root root 4096 Jul 24 20:44 scripts

将目录( cd ) 更改为目标挂载路径 /scripts 。在绑定挂载的目标挂载路径中列出了 createtable.sql 脚本。

root@e71275e6c65c:/# cd /scripts
root@e71275e6c65c:/scripts# ls -l
-rw-r--r--. 1 root root 1478 Jul 24 20:44 createtable.sql

每个服务任务 Docker 容器在主机上都有自己的文件副本。因为默认情况下,挂载是 read-write ,所以挂载路径中的文件可能会被修改或删除。例如,从容器中删除 createtable.sql 脚本。

core@ip-10-0-0-137 ∼ $ docker exec -it 995b9455aff2 bash
root@995b9455aff2:/# cd /scripts                                               
root@995b9455aff2:/scripts# ls -l
total 8
-rw-r--r--. 1 root root 1478 Jul 24 20:45 createtable.sql
root@995b9455aff2:/scripts# rm createtable.sql
root@995b9455aff2:/scripts# ls -l
total 0
root@995b9455aff2:/scripts#

如前所述,通过在 --mount arg 中包含一个额外的选项,可以将挂载设置为只读。为了演示 a readonly 挂载,首先删除已经运行的 mysql 服务。创建一个服务并使用与之前相同的命令挂载一个 readonly 绑定,除了包含一个额外的 readonly 选项。

core@ip-10-0-0-143 ∼ $ docker service create \
>    --env MYSQL_ROOT_PASSWORD='mysql' \
>    --replicas 3 \
>    --mount type=bind,src="/etc/mysql/scripts",dst="/scripts",readonly \
>    --name mysql \
>       mysql
c27se8vfygk2z57rtswentrix

安装了类型为 readonlymount 活页夹。

访问调度任务的节点上的容器,并列出主机目录中的示例脚本。

core@ip-10-0-0-143 ∼ $ docker exec -it 3bf9cf777d25 bash
root@3bf9cf777d25:/# cd /scripts                                               
root@3bf9cf777d25:/scripts# ls -l
-rw-r--r--. 1 root root 1478 Jul 24 20:44 createtable.sql

删除或尝试删除示例脚本。会产生一个错误。

root@3bf9cf777d25:/scripts# rm createtable.sql
rm: cannot remove 'createtable.sql': Read-only file system

摘要

本章介绍了蜂群模式下的坐骑。支持两种类型的装载 - 绑定装载和卷装载。绑定装载将预先存在的目录或文件从主机装载到服务的每个容器中。卷挂载将命名卷挂载到服务中的每个容器中,该命名卷在创建服务之前可能存在,也可能不存在。下一章讨论配置资源。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。