0x01 前言

我使用Rancher2作为容器的编排工具已经有大半年的时间,直到今天还是使用单机NFS服务作为存储为容器提供数据持久化服务。找到新工作后一直在忙于学习工作上的新事物,所以直到今天才开始研究适用于容器的高可用数据持久化服务。

但在测试的过程中发现Rancher2所使用的hyperkube内置Gluster的驱动太旧,需要使用5.x版本的Gluster才能正常工作,而这花了我3天时间才找到问题的原因。

0x02 准备

基础架构及流程如下:

这流程图看起来是有那么一点点复杂,简单描述如下:

  1. Client通过Rancher Web GUI创建Pod的时候创建一个新的PVC或者直接创建一个PVC
  2. 创建PVC的时候选择指定的Storage Class
  3. Storage Class使用配置好的信息通过Restful API调用Heketi API创建Volume
  4. Heketi调用Gluster Cluster创建Volume
  5. Pod拿到Volume信息后挂载使用

严格来说这流程不太对,但主要是这么回事。如果不用Heketi的情况下,是需要使用gluster client手动创建Volume,但不符合自动化的需求。这里会使用Heketi,它能提供API接口给Rancher内的Storage驱动使用,同时又能管理Gluster node,这是一个成熟的解决方案,一举多得。

Gluster在默认情况下是3副本模式,可用性较高。另外也不需要过于担心Heketi故障的问题,它只提供API接口,故障后只会导致无法创建新的Volume而已。而挂载的时候会使用Gluster某一个node作为挂载点,另外还有一个option附有所有node的IP,当正在使用的node故障后会自动切换。

首选需要准备一套Rancher2环境,可以参考以下文章进行部署:

然后准备4台虚拟机,分别为1台Heketi,3台Gluster node,这3个node至少要有一个未经格式化的磁盘,比如我的虚拟机:

其实Heketi也可以通过一些常见的技术实现高可用,比如keepalived,而Heketi自身是有个数据库的,这个数据库可以放在Gluster的一个Volume内。但本文篇幅有限,不涉及这部分内容。

0x03 安装Gluster

正如前面所说的,我们需要安装5.x版本以适配Rancher2内置的驱动,所以需要在Gluster所有node内执行以下命令:

yum install centos-release-gluster5 -y \
 && yum install glusterfs-server -y \
 && systemctl enable glusterd \
 && systemctl restart glusterd \
 && systemctl status glusterd

可以检查这服务所监听的端口:

至此,GlusterFS安装的工作全部完成,非常简单。

0x04 安装Heketi

在Heketi服务器上执行以下命令即可完成安装Heketi的工作:

yum install centos-release-gluster5 -y \
  && yum install heketi heketi-client -y

完成安装后先不要启动Heketi,需要先进行配置工作:

vim /etc/heketi/heketi.json

按需修改如下注释中的内容:

{
  "_port_comment": "Heketi Server Port Number",

# 端口
  "port": "8080",

  "_use_auth": "Enable JWT authorization. Please enable for deployment",

# 是否启用用户验证
  "use_auth": false,

  "_jwt": "Private keys for access",
  "jwt": {
    "_admin": "Admin has access to all APIs",
    "admin": {

# 管理员级别用户的key
      "key": "My Secret"
    },
    "_user": "User only has access to /volumes endpoint",
    "user": {

# 用户级别的key
      "key": "My Secret"
    }
  },

  "_glusterfs_comment": "GlusterFS Configuration",
  "glusterfs": {
    "_executor_comment": [
      "Execute plugin. Possible choices: mock, ssh",
      "mock: This setting is used for testing and development.",
      "      It will not send commands to any node.",
      "ssh:  This setting will notify Heketi to ssh to the nodes.",
      "      It will need the values in sshexec to be configured.",
      "kubernetes: Communicate with GlusterFS containers over",
      "            Kubernetes exec api."
    ],

# 配置GlusterFS所用的方式
    "executor": "ssh",

    "_sshexec_comment": "SSH username and private key file information",
    "sshexec": {

# SSH免密登陆的key所在的路径
      "keyfile": "/etc/heketi/heketi.key",

# SSH用户
      "user": "root",

# SSH端口
      "port": "22",

# fstab文件所在的路径
      "fstab": "/etc/fstab"
    },

    "_kubeexec_comment": "Kubernetes configuration",
    "kubeexec": {
      "host" :"https://kubernetes.host:8443",
      "cert" : "/path/to/crt.file",
      "insecure": false,
      "user": "kubernetes username",
      "password": "password for kubernetes user",
      "namespace": "OpenShift project or Kubernetes namespace",
      "fstab": "Optional: Specify fstab file on node.  Default is /etc/fstab"
    },

    "_db_comment": "Database file name",

# Heketi数据库路径
    "db": "/var/lib/heketi/heketi.db",

    "_loglevel_comment": [
      "Set log level. Choices are:",
      "  none, critical, error, warning, info, debug",
      "Default is warning"
    ],

# 日志级别
    "loglevel" : "debug"
  }
}

在此,我只修改以下内容:

  • executor:SSH
  • keyfile:/etc/heketi/heketi.key
  • user:root
  • port:22
  • fstab:/etc/fstab

紧接着生成SSH Key并分发到3台Gluster中以实现免密登陆:

# 生成SSH Key
[root@heketi-node1 ~]# ssh-keygen -t rsa -q -f /etc/heketi/heketi.key -N ""

# 修改SSH Key权限
[root@heketi-node1 ~]# chown heketi:heketi /etc/heketi/heketi.key && chmod 400 /etc/heketi/heketi.key

# 部署SSH Key到Gluster Node
[root@heketi-node1 ~]# ssh-copy-id -i /etc/heketi/heketi.key [email protected]

[root@heketi-node1 ~]# ssh-copy-id -i /etc/heketi/heketi.key [email protected]

[root@heketi-node1 ~]# ssh-copy-id -i /etc/heketi/heketi.key [email protected]

至此已完成Heketi的基本配置,现在尝试启动Heketi:

systemctl enable heketi \
  && systemctl restart heketi \
  && systemctl status heketi

接下来要准备拓扑结构的文件,比如我的:

{
  "clusters": [
    {
      "nodes": [
        {
          "devices": [
            "/dev/sdb"
          ],
          "node": {
            "hostnames": {
              "manage": [
                "10.1.3.15"
              ],
              "storage": [
                "10.1.3.15"
              ]
            },
            "zone": 1
          }
        },
        {
          "devices": [
            "/dev/sdb"
          ],
          "node": {
            "hostnames": {
              "manage": [
                "10.1.3.16"
              ],
              "storage": [
                "10.1.3.16"
              ]
            },
            "zone": 1
          }
        },
        {
          "devices": [
            "/dev/sdb"
          ],
          "node": {
            "hostnames": {
              "manage": [
                "10.1.3.17"
              ],
              "storage": [
                "10.1.3.17"
              ]
            },
            "zone": 1
          }
        }
      ]
    }
  ]
}

其中一些key的含义如下:

  • manage:管理通道的IP
  • storage:数据通道的IP
  • zone:故障域
  • devices:磁盘路径

可以创建不同故障域以提升数据的可靠性;磁盘路径可以是多个;通道必须填写IP,因为Heketi无法解析域名。完成后执行以下命令即可:

# 执行命令
[root@heketi-node1 ~]# heketi-cli topology load --json=/etc/heketi/topology.json

# 返回的结果
Creating cluster ... ID: 6a84b0b18e9af56173431e5d4ef16b89
	Allowing file volumes on cluster.
	Allowing block volumes on cluster.
	Creating node 10.1.3.15 ... ID: c264795f04903148775d62181a1a00ed
		Adding device /dev/sdb ... OK
	Creating node 10.1.3.16 ... ID: 61412a8ed3ca971bffd0ee36a80dfd59
		Adding device /dev/sdb ... OK
	Creating node 10.1.3.17 ... ID: f31f5f32a591342232b97caa6bd5cae0
		Adding device /dev/sdb ... OK

在返回的结果中有Cluster ID的部分,这在后续需要用到的。至此,Heketi的安装配置工作已全部完成。

在继续之前可以尝试使用以下命令:

# 列出Cluster
[root@heketi-node1 ~]# heketi-cli cluster list
Clusters:
Id:6a84b0b18e9af56173431e5d4ef16b89 [file][block]

# 查看Cluster信息
[root@heketi-node1 ~]# heketi-cli cluster info 6a84b0b18e9af56173431e5d4ef16b89
Cluster id: 6a84b0b18e9af56173431e5d4ef16b89
Nodes:
61412a8ed3ca971bffd0ee36a80dfd59
c264795f04903148775d62181a1a00ed
f31f5f32a591342232b97caa6bd5cae0
Volumes:

Block: true

File: true

# 列出Node
[root@heketi-node1 ~]# heketi-cli node list
Id:61412a8ed3ca971bffd0ee36a80dfd59	Cluster:6a84b0b18e9af56173431e5d4ef16b89
Id:c264795f04903148775d62181a1a00ed	Cluster:6a84b0b18e9af56173431e5d4ef16b89
Id:f31f5f32a591342232b97caa6bd5cae0	Cluster:6a84b0b18e9af56173431e5d4ef16b

# 查看Node信息
[root@heketi-node1 ~]# heketi-cli node info 61412a8ed3ca971bffd0ee36a80dfd59
Node Id: 61412a8ed3ca971bffd0ee36a80dfd59
State: online
Cluster Id: 6a84b0b18e9af56173431e5d4ef16b89
Zone: 1
Management Hostname: 10.1.3.16
Storage Hostname: 10.1.3.16
Devices:
Id:8a50a043463b591b518a61c19abdc374   Name:/dev/sdb            State:online    Size (GiB):49      Used (GiB):0       Free (GiB):49      Bricks:0 

还可以查看拓扑信息:

[root@heketi-node1 ~]# heketi-cli topoligy info

0x05 Rancher2挂载

因为没有配置用户信息,所以只需要Heketi服务器的IP、端口和Cluster的ID即可,比如我的信息:

  • 服务器IP:10.1.3.21
  • 端口:8080
  • Cluster ID:6a84b0b18e9af56173431e5d4ef16b89

我们还可以通过浏览器访问Heketi的这个URI确认服务是否正常:

在默认情况下,很多驱动在Rancher2里都属于实验性功能,我们需要手动打开。因为没有全面测试过,所以在后续的Rancher2升级中可能会出现问题,这需要使用者自行衡量风险。不过开源软件不都是这样的吗?

首先来到下图中的页面激活被禁用的存储驱动:

然后来到存储类页面,添加一个存储类:

然后按下图进行配置:

  • 名称:自定义名称
  • 提供者:Gluster Volume
  • REST URL:Heketi服务器地址
  • 集群ID:Heketi集群ID
  • 回收策略:
    • 在工作负载释放后删除卷和底层设备:PVC释放后会删除PV,该PV内的数据会被删除,慎用
    • 保留卷以进行手动清理:PVC释放后会保留PV,数据保留。

完成后保存即可,随后即可手动创建一个PVC:

配置信息如下:

单击创建后稍等片刻即可看到PV信息已经自动创建:

单击上图中的PV,再打开注释部分可以看到以下信息:

再会到Heketi,执行以下命令可以查看该Volume的详细信息:

# 列出Volume
[root@heketi-node1 ~]# heketi-cli volume list
Id:d79bb11df638f5b78e3f0cd8c20a6f32    Cluster:6a84b0b18e9af56173431e5d4ef16b89    Name:vol_d79bb11df638f5b78e3f0cd8c20a6f32

# 查看指定的Volume
[root@heketi-node1 ~]# heketi-cli volume info d79bb11df638f5b78e3f0cd8c20a6f32
Name: vol_d79bb11df638f5b78e3f0cd8c20a6f32
Size: 10
Volume Id: d79bb11df638f5b78e3f0cd8c20a6f32
Cluster Id: 6a84b0b18e9af56173431e5d4ef16b89
Mount: 10.1.3.16:vol_d79bb11df638f5b78e3f0cd8c20a6f32
Mount Options: backup-volfile-servers=10.1.3.15,10.1.3.17
Block: false
Free Size: 0
Reserved Size: 0
Block Hosting Restriction: (none)
Block Volumes: []
Durability Type: replicate
Distributed+Replica: 3
Snapshot Factor: 1.00

至此,所有配置工作皆已完成。

在实际使用中可以省略手动创建PVC的步骤,在创建Pod的时候新建即可:

同样的,需要填写一些信息:

但是在这里填写信息后并不会立刻创建PVC,而是在完成该Pod所有信息的填写并且运行时才会创建:

进入容器检查挂载情况并touch一个文件:

然后来到Gluster各个Node查看文件是否成功被复制:

0x06 结语

这套东西部署起来非常简单,但用起来需要考虑诸如网络、IO、存储高可用和Rancher自动化等等问题,还得对Centos调优,工作可预见的繁杂。

至少目前有一套高可用的数据持久化解决方案,接下来要替换掉我目前使用的单机NFS。