六、使用挂载
Swarm 中的服务任务容器可以访问从其 Docker 映像继承的文件系统。数据通过其 Docker 映像集成到 Docker 容器中。有时,Docker 容器可能需要在持久文件系统上存储或访问数据。虽然容器有一个文件系统,但是一旦容器退出,它就会被删除。为了在容器重启时存储数据,数据必须保存在容器之外的某个地方。
问题
仅存储在容器中的数据可能会导致以下问题:
- 数据不是持久的。当 Docker 容器停止时,数据将被删除。
- 数据不能与其他 Docker 容器或主机文件系统共享。
解决方案
基于单一责任原则(SRP) 的模块化设计建议将数据从 Docker 容器中分离出来。Docker Swarm 模式提供了共享数据的挂载,并使数据在容器启动和关闭时保持持久。Docker Swarm 模式为服务提供了两种类型的挂载:
- 卷装载
- 绑定安装
默认值是卷装载。使用 docker service create 命令的 --mount 选项创建服务的挂载。
卷装载
卷装载是主机上装载到服务任务容器中的命名卷。即使在停止和删除容器后,主机上的命名卷仍然存在。可以在创建使用该卷的服务之前创建命名卷,或者可以在服务部署时创建该卷。在部署时创建的命名卷是在启动服务任务容器之前创建的。如果在服务部署时创建,并且未指定卷名,则命名卷会自动生成一个名称。图 6-1 显示了一个卷挂载的例子,其中一个在创建服务之前就存在的命名卷 mysql-scripts 被挂载到目录路径 /etc/mysql/scripts 下的服务任务容器中。

图 6-1。
Volume mount
服务中的每个容器都可以访问运行该容器的主机上的相同命名卷,但是该主机命名卷可以存储相同或不同的数据。
使用卷装载时,内容不会跨群集复制。例如,如果您将某些内容放入正在使用的 mysql-scripts 目录,这些新文件将只能被运行在同一节点上的其他任务访问。在其他节点上运行的副本将无法访问这些文件。
绑定安装
绑定装载是要在其上计划服务任务的主机上的文件系统路径。主机文件系统路径被装载到服务任务容器的指定目录路径中。主机文件系统路径必须存在于群中的每个主机上,在创建服务之前可以在其上调度任务。如果使用节点约束将某些节点排除在服务部署之外,则绑定装载主机文件系统不必存在于这些节点上。使用绑定挂载时,请记住使用绑定挂载的服务本身是不可移植的。如果要在生产中部署服务,主机目录路径必须存在于生产集群中的每个主机上。
主机文件系统路径不必与任务容器中的目标目录路径相同。例如,在图 6-2 中,主机路径 /db/mysql/data 作为绑定挂载被挂载到目录路径 /etc/mysql/data 的服务容器中。默认情况下,绑定装载是读写的,但是在服务部署时可以设置为只读。服务中的每个容器都可以访问运行容器的主机上的相同目录路径,但是主机目录路径可以存储不同或相同的数据。

图 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 所示。

图 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 所示。

图 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
安装了类型为 readonly 的 mount 活页夹。
访问调度任务的节点上的容器,并列出主机目录中的示例脚本。
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
摘要
本章介绍了蜂群模式下的坐骑。支持两种类型的装载 - 绑定装载和卷装载。绑定装载将预先存在的目录或文件从主机装载到服务的每个容器中。卷挂载将命名卷挂载到服务中的每个容器中,该命名卷在创建服务之前可能存在,也可能不存在。下一章讨论配置资源。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论