<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>glusterfs | 伪架构师</title>
    <link>/tags/glusterfs/</link>
      <atom:link href="/tags/glusterfs/index.xml" rel="self" type="application/rss+xml" />
    <description>glusterfs</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Mon, 13 May 2019 23:10:28 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>glusterfs</title>
      <link>/tags/glusterfs/</link>
    </image>
    
    <item>
      <title>Kubernetes 存储性能对比</title>
      <link>/post/kubernetes-storage-performance-comparison/</link>
      <pubDate>Mon, 13 May 2019 23:10:28 +0800</pubDate>
      <guid>/post/kubernetes-storage-performance-comparison/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://medium.com/vescloud/kubernetes-storage-performance-comparison-9e993cb27271&#34; target=&#34;_blank&#34;&gt;Kubernetes Storage Performance Comparison&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://medium.com/@pupapaik&#34; target=&#34;_blank&#34;&gt;Jakub Pavlík&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如果你正在运行 Kubernetes，你可能正在使用，或者准备使用动态供给的块存储&lt;a href=&#34;https://kubernetes.io/docs/concepts/storage/#types-of-volumes&#34; target=&#34;_blank&#34;&gt;卷&lt;/a&gt;，而首当其冲的问题就是为集群选择合适的存储技术。这个事情并不能用一个简单的测试来做出简单的回答，告诉你目前市面上最好的技术是什么。存储技术的选择过程中，集群上运行的负载类型是一个重要的输入。对于裸金属集群来说，需要根据实际用例进行选择，并集成到自己的硬件之中。公有云中的托管 K8s，例如 AKS、EKS 或者 GKE，都具有开箱可用的块存储能力，然而这也不见得就是最好的选择。有很多因素需要考虑，比如说公有云的 StorageClass 的故障转移时间太长。例如在 一个针对 AWS EBS 的故障测试中，加载了卷的 Pod 用了&lt;a href=&#34;https://blog.rook.io/run-your-own-high-performance-ebs-wherever-kubernetes-runs-798a136bd808&#34; target=&#34;_blank&#34;&gt;超过五分钟&lt;/a&gt;才成功的在另一个节点上启动。Portworx 或者 OpenEBS 这样的云原生存储产品，正在尝试解决这类问题。&lt;/p&gt;

&lt;p&gt;本文的目标是使用最常见的 Kubernetes 存储方案，进行基本的性能对比。我觉得在 Azure AKS 上使用下列后端：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AKS 原生 Storageclass：Azure native premium
&lt;!-- - AKS 存储 --&gt;&lt;/li&gt;
&lt;li&gt;使用 cStor 后端的 OpenEBS&lt;/li&gt;
&lt;li&gt;Portworx&lt;/li&gt;
&lt;li&gt;Heketi 管理的 Gluster&lt;/li&gt;
&lt;li&gt;Rook 管理的 Ceph&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;现在我们来介绍每种存储后端，并交代一下安装过程，然后进入 AKS 测试环境进行测试，最后得出结果。&lt;/p&gt;

&lt;h2 id=&#34;存储&#34;&gt;存储&lt;/h2&gt;

&lt;p&gt;这一节中介绍测试中用到的存储方案，包含安装过程以及该方案的优缺点。&lt;/p&gt;

&lt;h3 id=&#34;azure-原生-storageclass&#34;&gt;Azure 原生 StorageClass&lt;/h3&gt;

&lt;p&gt;我选择这一方案的动机是以此作为所有测试的基线。这个方案&lt;strong&gt;应该&lt;/strong&gt;提供最佳性能。Azure 动态的创建托管磁盘，并把它们映射到 K8s 的虚拟机中，最终成为 Pod 的存储卷。&lt;/p&gt;

&lt;p&gt;这个方案很方便，什么多余的步骤都不需要。创建一个新的 AKS 集群之后，就自动提供了两个预定义的 StorageClass，分别是 &lt;code&gt;default&lt;/code&gt; 和 &lt;code&gt;managed-premium&lt;/code&gt;，premium 使用的是基于 SSD 的高性能低延迟磁盘。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get storageclasses
NAME                PROVISIONER                AGE
default (default)   kubernetes.io/azure-disk   8m
managed-premium     kubernetes.io/azure-disk   8m

$ kubectl get pvc
NAME              STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
dbench-pv-claim   Bound     pvc-e7bd34a4-1dbd-11e9-8726-ae508476e8ad   1000Gi     RWO            managed-premium   10s

$ kubectl get po
NAME           READY     STATUS              RESTARTS   AGE
dbench-w7nqf   0/1       ContainerCreating   0          29s
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;优点&#34;&gt;优点&lt;/h4&gt;

&lt;p&gt;AKS 开箱即用。&lt;/p&gt;

&lt;h4 id=&#34;缺点&#34;&gt;缺点&lt;/h4&gt;

&lt;p&gt;故障转移非常缓慢，有时需要十分钟以后，存储卷才能重新挂载到不同节点上的 Pod 里。&lt;/p&gt;

&lt;h3 id=&#34;openebs&#34;&gt;OpenEBS&lt;/h3&gt;

&lt;p&gt;对我来说 OpenEBS 是个全新事物，因此我很有兴趣做他的测试。他提出了一个新的 &lt;a href=&#34;https://docs.openebs.io/docs/next/conceptscas.html#advantages-of-cas&#34; target=&#34;_blank&#34;&gt;Container Attached Storage（容器挂载存储）&lt;/a&gt;概念，这是一个基于微服务的存储控制器，以及多个基于微服务的存储副本。他和 Portworx 同样，属于云原生存储分类的成员。&lt;/p&gt;

&lt;p&gt;它是一个完全开源的方案，目前提供两种后端——Jiva 和 cStor。我最开始选择的是 Jiva，后来切换到 cStor。cStor 有很多长处，例如他的控制器和副本被部署到单一的 OpenEBS 所在的命名空间之中，能够管理原始磁盘等。每个 K8s 卷都有自己的存储控制器，能在节点存储容量的许可范围内对存储进行扩展。&lt;/p&gt;

&lt;h4 id=&#34;在-aks-上运行&#34;&gt;在 AKS 上运行&lt;/h4&gt;

&lt;p&gt;在 AKS 上的安装非常容易。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;连接到所有 K8s 节点上，安装 iSCSI，这是因为他需要使用 iSCSI 协议在 K8s 节点之间进行 Pod 和控制器的连接。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;apt-get update
apt install -y open-iscsi
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;使用一个 YAML 定义在 K8s 集群上完成部署：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl apply -f https://openebs.github.io/charts/openebs-operator-0.8.0.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;下一步，OpenEBS 控制器发现了节点中的所有磁盘。但是我必须手工标识出我附加的 AWS 托管磁盘。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get disk
NAME                                      AGE
disk-184d99015253054c48c4aa3f17d137b1     5m
disk-2f6bced7ba9b2be230ca5138fd0b07f1     5m
disk-806d3e77dd2e38f188fdaf9c46020bdc     5m
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;然后把这些磁盘加入 StoragePoolClaim，这个对象会在 StorageClass 中进行引用：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: openebs-custom
  annotations:
    openebs.io/cas-type: cstor
    cas.openebs.io/config: |
      - name: StoragePoolClaim
        value: &amp;quot;cstor-disk&amp;quot;
provisioner: openebs.io/provisioner-iscsi
---
apiVersion: openebs.io/v1alpha1
kind: StoragePoolClaim
metadata:
  name: cstor-disk
spec:
  name: cstor-disk
  type: disk
  maxPools: 3
  poolSpec:
    poolType: striped
  disks:
    diskList:
    - disk-2f6bced7ba9b2be230ca5138fd0b07f1
    - disk-806d3e77dd2e38f188fdaf9c46020bdc
    - disk-184d99015253054c48c4aa3f17d137b1
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;完成这些步骤之后，就可以用 K8s 的 PVC 来动态的创建存储卷了。&lt;/p&gt;

&lt;h4 id=&#34;优点-1&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;开源&lt;/li&gt;
&lt;li&gt;Maya 在资源使用的可视化方面做得非常好。可以在 K8s 中部署多个服务，方便的为集群的各方面数据设置监控和日志。对于排错工作来说，这十分重要。&lt;/li&gt;
&lt;li&gt;CAS 概念：我非常欣赏这一概念，我相信这是未来的趋势。&lt;/li&gt;
&lt;li&gt;OpenEBS 社区：在社区中我的任何问题都能在几分钟内得到解决。Slack 上的团队非常有帮助。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-1&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;不成熟：OpenEBS 还很年轻，目前还没有发布稳定版。核心团队还在进行后端的优化，未来几个月里会对性能做出很大提升。&lt;/li&gt;
&lt;li&gt;Kubelet 和存储控制器之间的 iSCSI 连接是通过 K8s Service 进行的，这在 Tungsten Fabric 之类的 CNI 插件环境中可能会出问题。&lt;/li&gt;
&lt;li&gt;需要在 K8s 节点上安装额外的软件（iSCSI），这对于托管集群来说非常不便。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;注：OpenEBS 团队对我的案例场景进行了调整：&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/kmova/openebs/tree/fio-perf-tests/k8s/demo/dbench&#34; target=&#34;_blank&#34;&gt;https://github.com/kmova/openebs/tree/fio-perf-tests/k8s/demo/dbench&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;portworx&#34;&gt;Portworx&lt;/h3&gt;

&lt;p&gt;Portworx 是另一个面向 Kubernetes 的容器原生存储方案，它专注于高度分布式的环境。这是一个主机可寻址的存储，每个卷都直接映射到挂在的主机上。他提供了基于应用 I/O 类型的自动微调能力。&lt;a href=&#34;https://portworx.com/makes-portworx-unique/&#34; target=&#34;_blank&#34;&gt;官方网站&lt;/a&gt;提供了更多信息。不幸的是，它也是本文中唯一的非开源产品。然而它提供了 3 节点的免费试用。&lt;/p&gt;

&lt;h4 id=&#34;在-aks-上运行-1&#34;&gt;在 AKS 上运行&lt;/h4&gt;

&lt;p&gt;在 AKS 上的安装同样简单，我用了他们&lt;a href=&#34;https://docs.portworx.com/portworx-install-with-kubernetes/cloud/azure/aks/2-deploy-px/#generate-the-specs&#34; target=&#34;_blank&#34;&gt;网站&lt;/a&gt;提供的生成器。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;选择基于 Portworx 的 ETCD，指定 K8s 版本为 1.11.4。&lt;/li&gt;
&lt;li&gt;因为我用了 Azure CNI，因此必须把数据网卡设置为 &lt;code&gt;azure0&lt;/code&gt;。否则 Portworx 会使用 docker bridge 的 IP 地址，而非 VM 网卡。&lt;/li&gt;
&lt;li&gt;最后网站会生成渲染完成的 YAML 文件。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;提交后，会看到节点上运行的 Portworx Pod：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get pods -o wide -n kube-system -l name=portworx
NAME             READY     STATUS    RESTARTS   AGE       IP          NODE                       NOMINATED NODE
portworx-g9csq   1/1       Running   0          14m       10.0.1.66   aks-agentpool-20273348-2   &amp;lt;none&amp;gt;
portworx-nt2lq   1/1       Running   0          14m       10.0.1.4    aks-agentpool-20273348-0   &amp;lt;none&amp;gt;
portworx-wcjnx   1/1       Running   0          14m       10.0.1.35   aks-agentpool-20273348-1   &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;为 PVC 创建一个 StorageClass，定义高优先级，以及三个副本：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;root@aks-agentpool-20273348-0:~# kubectl get storageclass -o yaml portworx-sc
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  creationTimestamp: 2019-01-28T21:10:28Z
  name: portworx-sc
  resourceVersion: &amp;quot;55332&amp;quot;
  selfLink: /apis/storage.k8s.io/v1/storageclasses/portworx-sc
  uid: 23455e40-2341-11e9-bfcb-a23b1ec87092
parameters:
  priority_io: high
  repl: &amp;quot;3&amp;quot;
provisioner: kubernetes.io/portworx-volume
reclaimPolicy: Delete
volumeBindingMode: Immediate
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;优点-2&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;部署方便：生成器包含配置细节。&lt;/li&gt;
&lt;li&gt;不像 Ceph 和 Glusterfs 那样需要进行额外配置。&lt;/li&gt;
&lt;li&gt;云原生存储：公有云和裸金属都可以运行。&lt;/li&gt;
&lt;li&gt;存储级别感知和应用感知的 I/O 微调。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-2&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;闭源：商业解决方案&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;glusterfs-heketi&#34;&gt;GlusterFS Heketi&lt;/h3&gt;

&lt;p&gt;GlusterFS 是知名的开源存储方案，是由 Redhat 提供的开源存储方案。&lt;a href=&#34;https://github.com/gluster/gluster-kubernetes#glusterfs-native-storage-service-for-kubernetes&#34; target=&#34;_blank&#34;&gt;Heketi&lt;/a&gt; 是 GlusterFS 的 RESTful 卷管理界面。它提供了易用的方式为 GlusterFS 卷提供了动态供给的功能。如果没有 Heketi 的辅助，就只能手工创建 GlusterFS 卷并映射到 K8s PV 了。关于 GlusterFS 的更多信息，请阅读&lt;a href=&#34;https://docs.gluster.org/en/latest/Install-Guide/Overview/&#34; target=&#34;_blank&#34;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;

&lt;h4 id=&#34;在-aks-上运行-2&#34;&gt;在 AKS 上运行&lt;/h4&gt;

&lt;p&gt;根据 Heketi 的&lt;a href=&#34;https://github.com/gluster/gluster-kubernetes/blob/master/docs/setup-guide.md#deployment&#34; target=&#34;_blank&#34;&gt;快速入门&lt;/a&gt;文档进行部署。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;参照&lt;a href=&#34;https://github.com/gluster/gluster-kubernetes/blob/master/deploy/topology.json.sample&#34; target=&#34;_blank&#34;&gt;样例&lt;/a&gt;，创建一个包含磁盘和主机名的拓扑文件。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Heketi 主要的开发和测试都在基于 RHEL 的操作系统上，我在 AKS 上使用 Ubuntu 主机时，出现了内核模块路径错误的问题，我提交了一个 &lt;a href=&#34;https://github.com/gluster/gluster-kubernetes/pull/557&#34; target=&#34;_blank&#34;&gt;PR&lt;/a&gt; 来修正这个问题。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+++ b/deploy/kube-templates/glusterfs-daemonset.yaml
@@ -67,7 +67,7 @@ spec:
           mountPath: &amp;quot;/etc/ssl&amp;quot;
           readOnly: true
         - name: kernel-modules
-          mountPath: &amp;quot;/usr/lib/modules&amp;quot;
+          mountPath: &amp;quot;/lib/modules&amp;quot;
           readOnly: true
         securityContext:
           capabilities: {}
@@ -131,4 +131,4 @@ spec:
           path: &amp;quot;/etc/ssl&amp;quot;
       - name: kernel-modules
         hostPath:
-          path: &amp;quot;/usr/lib/modules&amp;quot;
+          path: &amp;quot;/lib/modules&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;我在 AKS 环境中遇到的另一个问题是一个非空磁盘，所以我用 &lt;code&gt;wipefs&lt;/code&gt; 为 glusterfs 进行清理。这个磁盘并未用过。&lt;/p&gt;

&lt;p&gt;$ wipefs -a /dev/sdc
/dev/sdc: 8 bytes were erased at offset 0x00000218 (LVM2_member): 4c 56 4d 32 20 30 30 31&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;最后运行 &lt;code&gt;gk-deploy -g -t topology.json&lt;/code&gt;，会在每个节点上运行 Heketi 控制器管理之下的 GlusterFS Pod。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get po -o wide
NAME                     READY   STATUS    RESTARTS IP        NODE                       NOMINATED NODE
glusterfs-fgc8f          1/1     Running   0       10.0.1.35  aks-agentpool-20273348-1
glusterfs-g8ht6          1/1     Running   0       10.0.1.4   aks-agentpool-20273348-0
glusterfs-wpzzp          1/1     Running   0       10.0.1.66  aks-agentpool-20273348-2
heketi-86f98754c-n8qfb   1/1     Running   0       10.0.1.69  aks-agentpool-20273348-2
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;然后我遇到了新问题。K8s 控制面无法使用 Heketi 的 &lt;code&gt;restURL&lt;/code&gt;。我测试了一下 kube dns 的记录，pod IP 和 svc IP 都没有生效。最后只能手工使用 Heketi CLI 来创建存储卷。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ export HEKETI_CLI_SERVER=http://10.0.1.69:8080
$ heketi-cli volume create --size=10 --persistent-volume --persistent-volume-endpoint=heketi-storage-endpoints | kubectl create -f -
persistentvolume/glusterfs-efb3b155 created

$ kubectl get pv
NAME                 CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
glusterfs-efb3b155   10Gi       RWX            Retain           Available
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后把现存 PV 映射为 PVC，加载给测试工具进行测试。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: glusterfs-efb3b155
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: &amp;quot;&amp;quot;
  resources:
    requests:
      storage: 10Gi
  volumeName: glusterfs-efb3b155
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get pvc
NAME                 STATUS    VOLUME               CAPACITY   ACCESS MODES   STORAGECLASS   AGE
glusterfs-efb3b155   Bound     glusterfs-efb3b155   10Gi       RWX                           36m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Heketi 的更多输出：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ gluster volume info vol_efb3b15529aa9aba889d7900f0ce9849

Volume Name: vol_efb3b15529aa9aba889d7900f0ce9849
Type: Replicate
Volume ID: 96fde36b-e389-4dbe-887b-baae32789436
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 3 = 3
Transport-type: tcp
Bricks:
Brick1: 10.0.1.66:/var/lib/heketi/mounts/vg_5413895eade683e1ca035760c1e0ffd0/brick_cd7c419bc4f4ff38bbc100c6d7b93605/brick
Brick2: 10.0.1.35:/var/lib/heketi/mounts/vg_3277c6764dbce56b5a01426088901f6d/brick_6cbd74e9bed4758110c67cfe4d4edb53/brick
Brick3: 10.0.1.4:/var/lib/heketi/mounts/vg_29d6152eeafc57a707bef56f091afe44/brick_4856d63b721d794e7a4cbb4a6f048d96/brick
Options Reconfigured:
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off

$ kubectl get svc
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
heketi                     ClusterIP   192.168.101.75   &amp;lt;none&amp;gt;        8080/TCP   5h
heketi-storage-endpoints   ClusterIP   192.168.103.66   &amp;lt;none&amp;gt;        1/TCP      5h

$ kubectl get endpoints
NAME                       ENDPOINTS                            AGE
heketi                     10.0.1.69:8080                       5h
heketi-storage-endpoints   10.0.1.35:1,10.0.1.4:1,10.0.1.66:1   5h
kubernetes                 172.31.22.152:443                    1d
root@aks-agentpool-20273348-0:~# kubectl get endpoints heketi-storage-endpoints -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  creationTimestamp: 2019-01-29T15:14:28Z
  name: heketi-storage-endpoints
  namespace: default
  resourceVersion: &amp;quot;142212&amp;quot;
  selfLink: /api/v1/namespaces/default/endpoints/heketi-storage-endpoints
  uid: 91f802eb-23d8-11e9-bfcb-a23b1ec87092
subsets:
- addresses:
  - ip: 10.0.1.35
  - ip: 10.0.1.4
  - ip: 10.0.1.66
  ports:
  - port: 1
    protocol: TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;优点-3&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;久经考验的存储方案。&lt;/li&gt;
&lt;li&gt;比 Ceph 轻量。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-3&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Heketi 在公有云上表现不佳。在私有云上表现良好，安装会方便一些。&lt;/li&gt;
&lt;li&gt;并非为结构化数据设计，例如 SQL 数据库。然而可以使用 GlusterFS 为数据库提供备份和恢复支持。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;ceph-rook&#34;&gt;Ceph Rook&lt;/h3&gt;

&lt;p&gt;我在 OpenStack 私有云上尝试过安装和运行 Ceph。它需要为特定硬件定制参数，根据数据类型设计 pg 组、SSD 分区和 CRUSH 图等。所以第一次听说在 3 节点的 K8s 集群上运行 Ceph 的时候，我不太相信它能工作。结果 Rook 的编排工具让我印象深刻，它把所有的步骤和 K8s 的编排能力结合在一起，让安装变得非常简便。&lt;/p&gt;

&lt;h4 id=&#34;在-aks-上运行-3&#34;&gt;在 AKS 上运行&lt;/h4&gt;

&lt;p&gt;Rook 的缺省安装无需任何特定步骤，如果没什么高级配置，会非常简单。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;我使用的是 &lt;a href=&#34;https://github.com/rook/rook/blob/master/Documentation/ceph-quickstart.md#ceph-storage-quickstart&#34; target=&#34;_blank&#34;&gt;Ceph 快速入门指南&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;为 AKS 配置 &lt;code&gt;FLEXVOLUME_DIR_PATH&lt;/code&gt;，这是因为它需要 &lt;code&gt;/etc/kubernetes/volumeplugins/&lt;/code&gt;，而不是 Ubuntu 中缺省的 &lt;code&gt;/usr/libexec&lt;/code&gt;，没有这个步骤，Kubelet 就&lt;a href=&#34;https://github.com/rook/rook/issues/1790#issuecomment-402574647&#34; target=&#34;_blank&#34;&gt;无法加载 PVC&lt;/a&gt; 了。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;diff --git a/cluster/examples/kubernetes/ceph/operator.yaml b/cluster/examples/kubernetes/ceph/operator.yaml
index 73cde2e..33f45c8 100755
--- a/cluster/examples/kubernetes/ceph/operator.yaml
+++ b/cluster/examples/kubernetes/ceph/operator.yaml
@@ -431,8 +431,8 @@ spec:
         # - name: AGENT_MOUNT_SECURITY_MODE
         #   value: &amp;quot;Any&amp;quot;
         # Set the path where the Rook agent can find the flex volumes
-        # - name: FLEXVOLUME_DIR_PATH
-        #  value: &amp;quot;&amp;lt;PathToFlexVolumes&amp;gt;&amp;quot;
+        - name: FLEXVOLUME_DIR_PATH
+          value: &amp;quot;/etc/kubernetes/volumeplugins&amp;quot;
         # Set the path where kernel modules can be found
         # - name: LIB_MODULES_DIR_PATH
         #  value: &amp;quot;&amp;lt;PathToLibModules&amp;gt;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;还要在 &lt;code&gt;deviceFilter&lt;/code&gt; 中指定要使用的设备，这里是 &lt;code&gt;/dev/sdc&lt;/code&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;diff --git a/cluster/examples/kubernetes/ceph/cluster.yaml b/cluster/examples/kubernetes/ceph/cluster.yaml
index 48cfeeb..0c91c48 100755
--- a/cluster/examples/kubernetes/ceph/cluster.yaml
+++ b/cluster/examples/kubernetes/ceph/cluster.yaml
@@ -227,7 +227,7 @@ spec:
   storage: # cluster level storage configuration and selection
     useAllNodes: true
     useAllDevices: false
-    deviceFilter:
+    deviceFilter: &amp;quot;^sdc&amp;quot;
     location:
     config:
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;安装之后，创建一个 Ceph block pool，以及 StorageClass，使用如下配置。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 3
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: rook-ceph-block
provisioner: ceph.rook.io/block
parameters:
  blockPool: replicapool
  clusterNamespace: rook-ceph
  fstype: xfs
reclaimPolicy: Retain
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;最后使用部署&lt;a href=&#34;https://github.com/rook/rook/blob/master/Documentation/ceph-toolbox.md&#34; target=&#34;_blank&#34;&gt;工具&lt;/a&gt;进行检查。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plain&#34;&gt;ceph status
cluster:
id:     bee70a10-dce1-4725-9285-b9ec5d0c3a5e
health: HEALTH_OK

services:
mon: 3 daemons, quorum c,b,a
mgr: a(active)
osd: 3 osds: 3 up, 3 in

data:
pools:   0 pools, 0 pgs
objects: 0  objects, 0 B
usage:   3.0 GiB used, 3.0 TiB / 3.0 TiB avail
pgs:

[root@aks-agentpool-27654233-0 /]#
[root@aks-agentpool-27654233-0 /]#
[root@aks-agentpool-27654233-0 /]# ceph osd status
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
| id |           host           |  used | avail | wr ops | wr data | rd ops | rd data |   state   |
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
| 0  | aks-agentpool-27654233-0 | 1025M | 1021G |    0   |     0   |    0   |     0   | exists,up |
| 1  | aks-agentpool-27654233-1 | 1025M | 1021G |    0   |     0   |    0   |     0   | exists,up |
| 2  | aks-agentpool-27654233-2 | 1025M | 1021G |    0   |     0   |    0   |     0   | exists,up |
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;优点-4&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;在大型生产环境上的健壮存储系统。&lt;/li&gt;
&lt;li&gt;Rook 很好的简化了生命周期管理。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-4&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;复杂：更加重量级，也不太适合在公有云上运行。在私有云上的运行可能更加合适。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;aks-测试环境&#34;&gt;AKS 测试环境&lt;/h2&gt;

&lt;p&gt;我用 3 个虚拟机创建了基本的 Azure AKS 集群。为了连接到 Premium SSD 上，我只能使用 type E 以上级别的虚拟机。因此我选择了 &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes-memory#esv3-series&#34; target=&#34;_blank&#34;&gt;Standard_E2s_v3&lt;/a&gt;，其上配备了 2 vCPU 以及 16GB 的内存。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/aks-vm-e2.png&#34; alt=&#34;vm&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在 AKS 集群所在的资源足中，可以看到所有的虚拟机、网络接口等资源。在这里创建 3 个 1TB 的 Premium SSD 存储，并手工挂载到每个虚拟机上。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/resource-group.png&#34; alt=&#34;resource group&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这样在每个实例上，我都有 1TB 的空磁盘。Azure 的页面上，根据我们选择的虚拟机和磁盘尺寸来看，性能应该有 5000 IOPS 以及 200MB/s 的吞吐量。最后一节会显示我们的真实结果。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/azure-disk-performance.png&#34; alt=&#34;azure new disk&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;性能结果&#34;&gt;性能结果&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：每种存储的结果并不能作为独立的评估结果，但是其比较情况是可以参考的。有很多种对比测试的方法，这是最简单的一种。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;为了运行测试，我决定使用现成的测试工具 &lt;a href=&#34;https://github.com/logdna/dbench&#34; target=&#34;_blank&#34;&gt;Dbench&lt;/a&gt;，它是一个 k8s 的 YAML 文件，会使用 &lt;a href=&#34;https://github.com/axboe/fio&#34; target=&#34;_blank&#34;&gt;FIO&lt;/a&gt; 运行 8 个测试用例。可以在 Dockerfile 中&lt;a href=&#34;https://github.com/logdna/dbench/blob/master/docker-entrypoint.sh&#34; target=&#34;_blank&#34;&gt;指定不同测试&lt;/a&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;随机读写带宽。&lt;/li&gt;
&lt;li&gt;随机读写 IOPS。&lt;/li&gt;
&lt;li&gt;读写延迟。&lt;/li&gt;
&lt;li&gt;顺序读写。&lt;/li&gt;
&lt;li&gt;混合读写 IOPS。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所有测试的结果可以在 &lt;a href=&#34;https://gist.github.com/pupapaik/76c5b7f124dbb69080840f01bf71f924&#34; target=&#34;_blank&#34;&gt;Github&lt;/a&gt; 上找到。&lt;/p&gt;

&lt;h3 id=&#34;随机读写带宽&#34;&gt;随机读写带宽&lt;/h3&gt;

&lt;p&gt;随机读写测试表明，GlusterFS、Ceph 以及 Portworx 的读取性能比 AWS 本地盘的 &lt;code&gt;hostPath&lt;/code&gt; 快了几倍。读缓存是罪魁祸首。GlusterFS 和 Portworx 的写入更快，其效率直逼本地磁盘。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/random-rw-bw.png&#34; alt=&#34;table1&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/figure1.png&#34; alt=&#34;figure1&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;随机读写-iops&#34;&gt;随机读写 IOPS&lt;/h3&gt;

&lt;p&gt;随机 IOPS 测试中，Portworx 和 Ceph 表现最好。Portworx 在写入方面获得了接近 Azure 原生 PVC 的 IOPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/table2.png&#34; alt=&#34;table2&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/figure2.png&#34; alt=&#34;figure2&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;读写延迟&#34;&gt;读写延迟&lt;/h3&gt;

&lt;p&gt;延迟测试的结果比较有趣，Azure 原生 PVC 比多数其它存储都差。Portworx 和 Ceph 表现最好。写入方面，GlusterFS 要优于 Ceph。OpenEBS 的延迟相对来说非常的高。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/table3.png&#34; alt=&#34;tables&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/figure3.png&#34; alt=&#34;figure&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;顺序读写&#34;&gt;顺序读写&lt;/h3&gt;

&lt;p&gt;顺序读写的结果和前面的随机测试差不多，然而 Cpeh 在读取方面比 GlusterFS 快了一倍多。写入结果基本一致，只有 OpenEBS 表现奇差。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/table4.png&#34; alt=&#34;table4&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/figure4.png&#34; alt=&#34;figure4&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;混合读写-iops&#34;&gt;混合读写 IOPS&lt;/h3&gt;

&lt;p&gt;最后一个测试用例检查的是混合读写情况下的 IOPS，Portworx 和 Ceph 都给出了优于 Azure 原生 PVC 的结果。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/table5.png&#34; alt=&#34;table5&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/figure5.png&#34; alt=&#34;figure5&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;

&lt;p&gt;本文展示了一个简单的存储对比，使用未经性能优化的多种存储提供的存储卷进行测试和比较。建议关注本文所述方法，不建议直接采用结果进行判断。&lt;/p&gt;

&lt;p&gt;忽略 Azure 的原生 PVC 或 &lt;code&gt;hostPath&lt;/code&gt;，我们可以得出如下测试结果：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portworx 是 AKS 上最快的容器存储。&lt;/li&gt;
&lt;li&gt;Ceph 是私有云集群上最快的开源存储后端。对公有云来说，其操作太过复杂，这些多余的复杂性并没有能提供更好的测试表现。&lt;/li&gt;
&lt;li&gt;OpenEBS 的概念很棒，但是其后端需要更多优化。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;调整性能数据的测试规模应该会很有意思。另外值得关注的对比就是 CPU 和内存的消耗。我会持续关注，并分享更多。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GlusterFS &#43; Heketi 入门（非容器）</title>
      <link>/post/glusterfs-and-heketi-on-physical-server/</link>
      <pubDate>Wed, 19 Apr 2017 19:05:50 +0800</pubDate>
      <guid>/post/glusterfs-and-heketi-on-physical-server/</guid>
      <description>

&lt;p&gt;GlusterFS 是个开源的分布式文件系统，而 Heketi 在其上提供了 REST 形式的 API，二者协同为 Kubernetes 提供了存储卷的自动供给能力。&lt;/p&gt;

&lt;p&gt;一般对这个系统的介绍，都是基于 Docker 的容器内完成的，个人爱好原因，还不太习惯把这个事情放到集群里面，所以介绍一下用 Yum 方式的安装过程。&lt;/p&gt;

&lt;p&gt;我们使用三台服务器作为存储集群，操作系统为 CentOS 7。另外假设每台 Gluster FS 服务器挂在有名为 /dev/sdc 的裸设备，安装过程需要有互联网连接。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heketi 服务器：10.211.55.31&lt;/li&gt;
&lt;li&gt;Gluster 服务器：

&lt;ul&gt;
&lt;li&gt;10.211.55.31&lt;/li&gt;
&lt;li&gt;10.211.55.32&lt;/li&gt;
&lt;li&gt;10.211.55.33&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;heketi-的安装和初始设置&#34;&gt;Heketi 的安装和初始设置&lt;/h2&gt;

&lt;p&gt;这个很简单，CentOS 的 EPEL Repository 中就提供了他的安装包。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;yum install -y heketi heketi-client
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;安装之后，会生成 Heketi 的 Service，建立 /etc/heketi，并在其中生成一个叫 heketi.json 的配置文件。这里提供一个样本：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;{
  &amp;quot;port&amp;quot;: &amp;quot;7070&amp;quot;,
  &amp;quot;use_auth&amp;quot;: false,
  &amp;quot;jwt&amp;quot;: {
    &amp;quot;admin&amp;quot;: {
      &amp;quot;key&amp;quot;: &amp;quot;My Secret&amp;quot;
    },
    &amp;quot;user&amp;quot;: {
      &amp;quot;key&amp;quot;: &amp;quot;My Secret&amp;quot;
    }
  },
  &amp;quot;glusterfs&amp;quot;: {
    &amp;quot;executor&amp;quot;: &amp;quot;ssh&amp;quot;,
    &amp;quot;sshexec&amp;quot;: {
      &amp;quot;keyfile&amp;quot;: &amp;quot;/etc/heketi/heketi_key&amp;quot;,
      &amp;quot;user&amp;quot;: &amp;quot;root&amp;quot;,
      &amp;quot;port&amp;quot;: &amp;quot;22&amp;quot;,
      &amp;quot;fstab&amp;quot;: &amp;quot;/etc/fstab&amp;quot;
    },
    &amp;quot;executor&amp;quot;: &amp;quot;ssh&amp;quot;,
    &amp;quot;db&amp;quot;: &amp;quot;/var/lib/heketi/heketi.db&amp;quot;,
    &amp;quot;loglevel&amp;quot;: &amp;quot;debug&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这个简单的配置文件说明：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;在 7070 提供服务。&lt;/li&gt;
&lt;li&gt;数据库保存在 &lt;code&gt;/var/lib/heketi/heketi.db&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;关闭认证&lt;/li&gt;
&lt;li&gt;利用 ssh 和 GlusterFS 集群成员进行通信&lt;/li&gt;
&lt;li&gt;ssh 证书保存在 /etc/heketi/heketi_key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;既然提到证书，就用 ssh-keygen 来生成一套：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh-keygen -t rsa -q -f /etc/heketi/heketi_key -N &#39;&#39;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;后面将会使用这套证书来完成对 GlusterFS 的控制。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意，这里要保证上面提到的&lt;strong&gt;数据库、配置以及证书文件&lt;/strong&gt;，一定要确认 Heketi 用户有权进行访问。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;glusterfs-安装&#34;&gt;GlusterFS 安装&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;启用仓库：&lt;code&gt;yum install -y centos-release-gluster&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;安装软件：&lt;code&gt;yum install -y glusterfs-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启用服务：&lt;code&gt;systemctl enable glusterfs-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启动服务：&lt;code&gt;systemctl start glusterfs-server&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;注意这里要把上个步骤生成的公钥（heketi_key.pub）加入到本机的信任列表中，例如&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat /tmp/heketi_key.pub &amp;gt;&amp;gt; /root/.ssh/authorized_key&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&#34;集群初始化&#34;&gt;集群初始化&lt;/h2&gt;

&lt;p&gt;Heketi 对存储的拓扑结构是这样的：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- Topology
    - Cluster a
        - Node a1
            - Device a11
            - Device a12
        - Node a2
    - Cluster b
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;所以初始化过程就按照从上到下的方式来进行：&lt;/p&gt;

&lt;h3 id=&#34;建立集群&#34;&gt;建立集群&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;heketi-cli create cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;创建成功后，会显示一个集群 ID。&lt;/p&gt;

&lt;h3 id=&#34;加入-node&#34;&gt;加入 Node&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;heketi-cli node add --cluster=[clusterid] \
--management-host-name=[node-host] \
--storage-host-name=[node-host] \
--zone=1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;运行成功会显示新加入的 Node 的 Node ID。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add Node 过程失败可能需要查看一下防火墙&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;加入-device&#34;&gt;加入 Device&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;heketi device add \
--name=/dev/sdc
--host=[host-id]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;自动一点&#34;&gt;自动一点&lt;/h3&gt;

&lt;p&gt;下面的脚本会把运行参数中指定的第一参数作为主机地址，第二参数作为设备名称加入第一个集群&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/sh
export HEKETI_CLI_SERVER=http://127.0.0.1:7070
CLUSTER_ID=`heketi-cli cluster list | tail -n 1 | xargs `
CLUSTER=&amp;quot;--cluster=$CLUSTER_ID&amp;quot;
HOST=&amp;quot;--management-host-name=$1 --storage-host-name=$1&amp;quot;
ZONE=&amp;quot;--zone=1&amp;quot;
NODE_ID=`heketi-cli node add $CLUSTER $HOST $ZONE | grep -v -i &amp;quot;Cluster&amp;quot; | grep -i &amp;quot;id&amp;quot; | cut -d : -f 2 | xargs`
heketi-cli device add --name=$2 --node=$NODE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;命令需要用 &amp;lsquo;-s&amp;rsquo; 开关指定操作的 Heketi 服务地址。
可以用环境变量来简化一下： export HEKETI_CLI_SERVER=&amp;ldquo;&lt;a href=&#34;http://127.0.0.1:7070&amp;quot;。&#34; target=&#34;_blank&#34;&gt;http://127.0.0.1:7070&amp;quot;。&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;topology&#34;&gt;Topology&lt;/h2&gt;

&lt;p&gt;利用 &lt;code&gt;heketi-cli topology info&lt;/code&gt;，会输出当前的集群结构。而且也可以用 JSON 格式导入和导出整个 Topology。下面的例子供参考：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
    &amp;quot;volumes&amp;quot;: [],
    &amp;quot;nodes&amp;quot;: [{
      &amp;quot;zone&amp;quot;: 1,
      &amp;quot;hostnames&amp;quot;: {
        &amp;quot;manage&amp;quot;: [&amp;quot;10.211.55.19&amp;quot;],
        &amp;quot;storage&amp;quot;: [&amp;quot;10.211.55.19&amp;quot;]
      },
      &amp;quot;cluster&amp;quot;: &amp;quot;f6e6de7dc99ca3ed627e2ab3ae68f9ac&amp;quot;,
      &amp;quot;id&amp;quot;: &amp;quot;95d3d4fec82be4d2a55ae0aa17344af5&amp;quot;,
      &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
      &amp;quot;devices&amp;quot;: [{
        &amp;quot;name&amp;quot;: &amp;quot;/dev/sdc&amp;quot;,
        &amp;quot;storage&amp;quot;: {
          &amp;quot;total&amp;quot;: 33419264,
          &amp;quot;free&amp;quot;: 33419264,
          &amp;quot;used&amp;quot;: 0
        },
        &amp;quot;id&amp;quot;: &amp;quot;e4e1b97d38ed5ae70323458c1b8e57b5&amp;quot;,
        &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
        &amp;quot;bricks&amp;quot;: []
      }]
    }, {
      &amp;quot;zone&amp;quot;: 1,
      &amp;quot;hostnames&amp;quot;: {
        &amp;quot;manage&amp;quot;: [&amp;quot;10.211.55.21&amp;quot;],
        &amp;quot;storage&amp;quot;: [&amp;quot;10.211.55.21&amp;quot;]
      },
      &amp;quot;cluster&amp;quot;: &amp;quot;f6e6de7dc99ca3ed627e2ab3ae68f9ac&amp;quot;,
      &amp;quot;id&amp;quot;: &amp;quot;ab36d04dbface40904a05c33f3fd9800&amp;quot;,
      &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
      &amp;quot;devices&amp;quot;: [{
        &amp;quot;name&amp;quot;: &amp;quot;/dev/sdc&amp;quot;,
        &amp;quot;storage&amp;quot;: {
          &amp;quot;total&amp;quot;: 33419264,
          &amp;quot;free&amp;quot;: 33419264,
          &amp;quot;used&amp;quot;: 0
        },
        &amp;quot;id&amp;quot;: &amp;quot;a33dee6fd8355c6aa9ff5e2783ecef49&amp;quot;,
        &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
        &amp;quot;bricks&amp;quot;: []
      }]
    }, {
      &amp;quot;zone&amp;quot;: 1,
      &amp;quot;hostnames&amp;quot;: {
        &amp;quot;manage&amp;quot;: [&amp;quot;10.211.55.20&amp;quot;],
        &amp;quot;storage&amp;quot;: [&amp;quot;10.211.55.20&amp;quot;]
      },
      &amp;quot;cluster&amp;quot;: &amp;quot;f6e6de7dc99ca3ed627e2ab3ae68f9ac&amp;quot;,
      &amp;quot;id&amp;quot;: &amp;quot;bfd478cb0a0a562386c06967fb2b31bc&amp;quot;,
      &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
      &amp;quot;devices&amp;quot;: [{
        &amp;quot;name&amp;quot;: &amp;quot;/dev/sdc&amp;quot;,
        &amp;quot;storage&amp;quot;: {
          &amp;quot;total&amp;quot;: 33419264,
          &amp;quot;free&amp;quot;: 33419264,
          &amp;quot;used&amp;quot;: 0
        },
        &amp;quot;id&amp;quot;: &amp;quot;24c5a97ccad5b3fc35977bc7419c27ee&amp;quot;,
        &amp;quot;state&amp;quot;: &amp;quot;online&amp;quot;,
        &amp;quot;bricks&amp;quot;: []
      }]
    }],
    &amp;quot;id&amp;quot;: &amp;quot;f6e6de7dc99ca3ed627e2ab3ae68f9ac&amp;quot;
  }]
}
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
  </channel>
</rss>
