8.4 Swarm存储卷应用

实验概述
本实验将带你探究 Swarm 中默认存储卷的局限性,并学习如何使用 NFS(网络文件系统)作为共享存储,实现数据的真正持久化,确保服务在不同节点间迁移时数据的安全与一致。

任务目标: 部署一个 MySQL 服务到 Swarm 集群中,使用默认的本地存储卷(Volume),然后通过模拟节点故障,观察数据会发生什么情况。

首先,我们来创建一个 MySQL 服务。

bash

docker service create \
--name db_[学号后两位] \
--replicas 1 \
-p [3300+学号后两位]:3306 \
-e MYSQL_ROOT_PASSWORD=root \
--mount source=mysql_data_[学号后两位],target=/var/lib/mysql \
mysql:5.7
命令解析
  • --name: 为服务指定一个唯一的名称。
  • -p: 将主机的端口映射到容器的端口,方便我们从外部访问 MySQL。
  • -e: 设置环境变量,这里用于设置 MySQL 的 root 用户密码。
  • --mount: 这是关键!它将一个存储卷挂载到容器的指定路径。
    • source: 指定存储卷的名称。
    • target: 指定容器内的数据存储路径 (/var/lib/mysql 是 MySQL 默认的数据目录)。
自动创建存储卷
如果 source 参数中指定的存储卷 mysql_data_[学号后两位] 不存在,Docker Swarm 会在服务所在的节点上自动创建一个 本地存储卷。

部署后,使用 docker service ls 或 docker service ps 命令查看服务状态,确保它已成功运行。

现在,服务已经运行起来了。让我们连接到数据库,并写入一些测试数据。

  1. 使用 Navicat 或其他数据库客户端连接到 MySQL 服务。
  2. 创建一个新的数据库,例如 students (字符集 utf8mb4)。
  3. 在 students 数据库中创建一个表,例如 cloud23,包含 no 和 name 两个字段。
  4. 在表中插入你自己的信息作为测试数据。

执行以下命令,查看我们的 MySQL 服务当前运行在哪个节点上。记下这个节点的主机名。

bash

docker service ps db_[学号后两位]

接下来,我们来模拟当前节点发生故障,Swarm 将服务迁移到另一个健康节点的情况。我们可以通过添加约束(constraint)来强制服务在另一个节点上运行。

bash

# 将下面的“节点主机名”替换成一个与当前运行节点不同的目标节点主机名
docker service update db_[学号后两位] --constraint-add "node.hostname==节点主机名"

执行后,再次查看服务状态,你会发现服务已经被重新调度到了新的节点上。

现在,回到 Navicat,刷新一下数据库连接。你会发现,我们刚刚创建的 students 数据库、cloud23 表以及里面的数据,全都消失了!

数据丢失!

为什么会这样?

因为 Docker 默认创建的是 本地存储卷。这意味着数据被存储在服务第一次运行时所在的那个节点的本地磁盘上。当服务被迁移到新节点时,它在新节点上找不到原来的数据文件,于是就初始化了一个全新的、空的数据目录。而我们宝贵的数据,则被遗留在了原来的那个节点上。

任务目标: 既然本地存储卷不可靠,我们需要一个所有节点都能访问的共享存储。在实际工作中,NFS(网络文件系统)是一个简单且高效的选择。让我们用它来解决数据丢失的问题。

首先,确保所有 Swarm 节点都安装了 NFS 客户端工具。

教师节点
NFS 服务端已在教师机(192.168.192.205)上配置好,大家只需要作为客户端挂载即可。

在所有节点上执行以下命令:

bash

yum install -y nfs-utils

与任务一不同,这次我们要创建一个特殊类型的存储卷,它连接到 NFS 服务器。

在所有节点上都执行这个命令,以确保每个节点都知道这个 NFS 存储卷的存在:

bash

docker volume create \
--opt type=nfs \
--opt o=addr=192.168.192.205,rw,nolock \
--opt device=:/data/[学号后两位] \
mysql_data_nfs_[学号后两位]
命令解析
  • --opt type=nfs: 指定存储卷的类型为 nfs。
  • --opt o=...: 这里的 o 代表 NFS 的挂载选项 (mount options)。
    • addr=192.168.192.205: NFS 服务器的 IP 地址。
    • rw: 以可读写模式挂载。
    • nolock: 禁用文件锁,这在某些情况下可以提高性能和兼容性。
  • --opt device=...: 指定要挂载的 NFS 服务器上的共享目录。格式为 :/path/to/share。
  • mysql_data_nfs_[学号后两位]: 为这个 NFS 存储卷命名。

现在,让我们用新的 NFS 存储卷来重新部署 MySQL 服务。

  1. 首先,删除任务一中创建的旧服务:docker service rm db_[学号后两位]

  2. 使用与任务一类似的命令重新创建服务,但这次 --mount 的 source 要指向我们新创建的 NFS 存储卷:

    bash

    docker service create \
    --name db_[学号后两位] \
    --replicas 1 \
    -p [3300+学号后两位]:3306 \
    -e MYSQL_ROOT_PASSWORD=root \
    --mount source=mysql_data_nfs_[学号后两位],target=/var/lib/mysql \
    mysql:5.7
  3. 重复任务一中的步骤 2,向数据库中写入相同的数据。

  4. 重复任务一中的步骤 4,将服务迁移到另一个节点。

  5. 再次回到 Navicat 中查看,这次你会发现,即使服务迁移到了新节点,数据依然完好无损!

数据不再丢失!

成功了!

因为这次我们使用了 NFS 共享存储。无论 MySQL 服务被调度到哪个节点,它挂载的都是同一个位于网络上的共享目录。数据不再与任何单个节点绑定,从而实现了真正的数据持久化和高可用性。