NutanixのCSI Volume Pluginの裏側にあるストレージについて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/6d22e4bc-29e2-b4b7-8094-9993a1c77937.png)


本記事は、Kubernetes Advent Calendar 2019の[2枚目](https://qiita.com/advent-calendar/2019/kubernetes2)の15日目、12月15日分としての投稿になります。

**本記事の内容は、この日付時点の情報（Nutanix CSI Plugin 1.x系）に基づいています。そのため，今後新しいバージョンが提供された場合に，当該記載と矛盾が生じる場合がありますのでご注意ください。**

#はじめに
Kubernetesのストレージ、特にオンプレミス環境におけるストレージの悩みはロードバランサーどうするか問題に並んで悩ましい問題の一つかなと個人的に感じています。

Kubernetesの運用や利用している方の中には、低いレイヤーにあるKubernetesのためのコンピュートリソースやストレージリソースは別のチームが面倒を見ているので、あまり気にしていない、というケースもあるかもしれません。

しかし、オンプレミスでインフラストラクチャーを運用すると言うことは、当たり前ですがKubernetesに限らずコンピュートやストレージの比較的低いレイヤーのリソースマネジメントからは逃れることができません。

最近、オンプレミスでも利用可能なKubernetesストレージとしてRookやLonghornなどのプロダクトが何かと話題になっていますが、今回は、そんなKubernetesのストレージに関する話題について（ちょっとプロプライエタリなプロダクトの話しを含みますが…）、巷ではあまり知られてないCSI Volume Pluginについて紹介してみます。

#Karbonを含むKubernetesにNutanixのストレージを提供するCSI Volume Plugin
##NutanixとKarbonとは
オンプレミスの、しかも仮想化のプロダクトを出している会社がなんでKubernetes？と言う印象を受けた方もいるかもしれませんし、コンテナやKubernetesの世界の方々には、そもそもNutanixとか聞いたこと無いんだけど？と言う方もいるかと思いますので、最初にその辺少しだけおさらいです。

###Karbonとは
NutanixはプロプラエタリなHCI(ハイパーコンバージドインフラストラクチャ)プロダクトですが、その上で動くマネージドなKubernetes(より厳密にCNCFのカテゴリーの区分で言うのであればCertified Kubernetes - Hosted)があり、Nutanixを持っていれば、特に特別なライセンス等を必要とすることなく使え、サポートも付いています。
ちと古いですが、詳細は昨年のKubernetes Advent Calendar 2018の[NutanixのオンプレミスなマネージドKubernetesサービス「Karbon」](https://qiita.com/hanakara_milk/items/cc087617ebef0651ff29)をご覧ください。

###Nutanixとは
Nutanixはもともとオンプレミスの環境において、様々なベンダーのサーバー、ストレージとそれを繋ぐストレージファブリックで構成されるインフラストラクチャーの管理の複雑さやスケールの難しさを汎用的なx86サーバーとSoftware Definedな分散アーキテクチャを用いて、高いスケーラビリティとクラスタリング技術による高い可用性や耐障害性を有するdesign for failureな仮想化インフラストラクチャーを提供するプロダクトです。
また、パブリッククラウドのように低いレイヤーをSoftwareで抽象化し、そこをあまり意識しなくても、それらの管理はダッシュボードやAPIで全てできるような使い勝手や価値を提供できるのも特徴の1つになっています。

##NutanixのCSI Volume Pluginとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/9d77cc8f-4ffe-2276-9e53-483d196b0348.png)

その中で提供されるSoftware Definedな分散ストレージは、NutanixのKarbonでもCSIのVolume Pluginを通じて使われており、HCIの特性を活かし、従来のオンプレミスKubernetesにおけるストレージの悩みを解消することができます。
あまりプロプラエタリなプロダクトの話ばかりをするのもこのAdvent Calendarの趣旨にあまり
あまり合わないと思いますので、ここからは、誰でも無償で利用可能なNutanix Community Editionをベースにして話を進めていきます。
なお、Nutanix Community Editionの紹介については、こちらもちと古いですが[【2016年版】Nutanix CE再入門＋最新情報（その1：ハイパーコンバージドインフラとNutanix CEの概要）](https://qiita.com/hanakara_milk/items/316c59130454f9da92d3)あたりをご覧下さい。

###CSI Volume Pluginの裏側にいるストレージの概要
NutanixのCSI Volume PluginによってKubernetesのコンテナ達が利用するストレージそのものの機能について少し触れておきたいと思います。
従来、Kubernetesを利用する上でデータの永続化機能はKubernetesによって抽象化され、Kubernetesの利用者はストレージの機能そのものやストレージ内部の実装を気にする必要はありませんが、特にオンプレミスのKubernetes環境でステートフルなコンテナ運用を行っていくユーザーにとっては、そのストレージの信頼性や機能、性能と言ったところは知っておきたいものになるかもしれません。

CSI Volume Pluginを通じて利用するストレージは、Nutanixの機能によって提供される分散SDS（Software Defined Storage）になります。NutanixのSDSを含むコアアーキテクチャは、Nutanixの創業メンバーの1人でもあり、もともとGoogleでGoogleのファイルシステムを設計したリードのアーキテクトであった人間が作り上げた、パブリッククラウドのアーキテクチャデザインや思想をエンタープライズの世界に提供することを目標に掲げ作られたものになっています。

特徴的な部分について、以下のようなものがあります。

- ストレージへのデータの書き込み時、自動的に1つ以上複製を作成する
- 障害等で定義されたデータの複製数を下回った場合、自動でそれを検知し即座に複製から復元する
- SSD、HDDで構成されるストレージにおけるデータの階層化を自動で行う
- データの実体をメタデータで管理することでCoR（Copy on Redirect）を用いてクローンやスナップショットが一瞬で作成ができる
- その他、圧縮、重複排除、イレージャーコーディング、レプリケーションの機能、など

そして従来からのNutanixのHCIの特徴を活かしてストレージが不足した場合にはノード（ここでのノードとはKubernetesのノードではなくNutanixのクラスターを構成するノード）を1-Clickで追加することで、システム停止を伴うこと無く高い可用性を持つストレージ領域が自動で拡張されていきます。
つまり、既に仮想化の世界で十分な実績をもって運用されているストレージがKubernetes上のPodに安定的に提供されることになります。

###CSI Volume Pluginの概要
NutanixのCSI Volume Pluginはこちらの、[https://github.com/nutanix/csi-plugin](https://github.com/nutanix/csi-plugin) で入手することが可能です（Karbonを利用している場合にはKubernetesクラスターをデプロイする際に自動で展開されますが、Non-Nutanixな環境では、こちらからPluginを入手し展開します）。

このCSI Volume PluginはKarbonで利用するKubernetes上のPodだけでなく、Non-Nutanixな環境で構成するKubernetes上のPodにもストレージを提供することが可能で、PVCによる動的なストレージのプロビジョニングをサポートしています。また、このCSI Volume PluginはNutanixのストレージ機能を利用してPodにブロックとファイル、ぞれぞれのストレージが提供可能です。

>
CSI VOLUME DRIVER 1.1のドキュメントより抜粋・引用：
Kubernetes is an open-source platform that orchestrates the deployment, scaling, and operations of application containers across host clusters. Nutanix-hosted VMs or bare metal servers comprise a host cluster.
>
Nutanix supports dynamic provisioning of PersistentVolumeClaims (PVC) using the CSI Volume Driver, which runs in a Kubernetes pod. An administrator must configure a storage class for the persistent volume provisioner. 
The provisioner watches for a PVC request for the configured storage class and then creates a PersistentVolume (PV) for that request.

このCSI Volume Pluginは、NutanixのKarbonでマネージされるKubernetes上だけでなく、Non-Nutanixな環境のKubernetes上のPodにインストールすることで、Non-Nutanixな環境のKubernetes上のPodから、Nutanixのストレージを利用することが可能になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/2d410fe0-a14b-badb-6c22-9cf80e795e0d.png)

**12月22日追記：**
[Nutanixの外にあるKubernetesからCSI Volume Pluginを使ってNutanixのストレージをPersistent Volumesとして利用する](https://qiita.com/hanakara_milk/items/36a7f38413c0f9f503a9) を別のAdvent Calendarのほうで投稿しました。

##NutanixのCSI Volume Pluginの振る舞い
今回は時間の都合上、Non-Nutanixな環境のKubernetesからの利用について紹介できませんが、Karbonの上でどのように動いているのかを参考までに見ていきます。先に結論だけ言ってしまうと、当たり前ですがCSIに準拠しているPluginなので、特別に珍しいことができるわけではなくCSIとして「ふつー」の振る舞いをします。
今回は簡単にその振る舞いを見るために、WordPressを1つデプロイしてみます。

###CSI Volume PluginでPVCによるVolumeの要求
以下のUIは、NutanixのCommunity Edition上で動作しているKarbonのUI画面です。WordPressをデプロイ前は、KarbonによってKubernetesクラスターが作成されると同時にデプロイされるElasticsearchとPrometheusのためのVolumeがあるだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/4b048ca5-8948-dcfa-b996-bbd0bd1b9b89.png)

一方で、Nutanixそのものの管理UIであるPrismのストレージのダッシュボードから見た場合は、Kubernetesクラスターが作成された際に利用されるetcdのためのストレージ領域と前述のElasticsearchとPrometheusで要求されたストレージ領域が見えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/74642403-3c6b-956f-3ee0-2b3bce41475a.png)

今回は簡単なデモのため、1つのyamlに`Service`、`PersistentVolumeClaim`、`Deployment`全部入りなこんな具合のyamlをapplyしてみます。
なお、以下の2つのyamlをapplyする前に`Secret`に`kubectl create secret generic mysql-pass --from-literal=password=[YOUR-PASSWORD]`なんかを作成しています。

```yaml:mysql-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
```
それからWordPress本体のyamlも同様にapplyしてみます。

```yaml:wordpress-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: NodePort
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
```

この2つのyamlファイルをapplyすることで、どうなったかを見ていきます。先ほどと同様にKarbonのUI画面で、Volumeを見ていくと、先ほどまで2つだったVolumeが4つに増え、mysql-pv-claimとwp-pv-claimが増えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/931b4234-3b7d-538b-615f-5b5b7a17e4ba.png)

また、Nutanixの管理UIであるPrismのストレージのダッシュボードから見ても、`pvc-4648134d-1f48-11ea-831c-506b8df55666`と`pvc-94facb9c-1f48-11ea-831c-506b8df55666`が追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/a45030b8-9dcf-05ae-95ad-94aeeb0b8b02.png)

コマンドライン上からは以下のように見えています。

```bash:
~/Documents/01_docs/demo/yaml ❯ kubectl get pv,pvc,sc,pods -n default
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                                            STORAGECLASS           REASON   AGE
persistentvolume/pvc-4648134d-1f48-11ea-831c-506b8df55666   20Gi       RWO            Delete           Bound    default/mysql-pv-claim                                           default-storageclass            35m
persistentvolume/pvc-55199cfd-1e24-11ea-831c-506b8df55666   10Gi       RWO            Delete           Bound    ntnx-system/prometheus-k8s-db-prometheus-k8s-0                   default-storageclass            35h
persistentvolume/pvc-94facb9c-1f48-11ea-831c-506b8df55666   20Gi       RWO            Delete           Bound    default/wp-pv-claim                                              default-storageclass            33m
persistentvolume/pvc-c476f529-1e23-11ea-831c-506b8df55666   20Gi       RWO            Delete           Bound    ntnx-system/elasticsearch-logging-data-elasticsearch-logging-0   default-storageclass            35h

NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           AGE
persistentvolumeclaim/mysql-pv-claim   Bound    pvc-4648134d-1f48-11ea-831c-506b8df55666   20Gi       RWO            default-storageclass   35m
persistentvolumeclaim/wp-pv-claim      Bound    pvc-94facb9c-1f48-11ea-831c-506b8df55666   20Gi       RWO            default-storageclass   33m

NAME                                                         PROVISIONER       AGE
storageclass.storage.k8s.io/default-storageclass (default)   com.nutanix.csi   35h

NAME                                   READY   STATUS    RESTARTS   AGE
pod/wordpress-76b5d9f5c8-djv5p         1/1     Running   0          33m
pod/wordpress-mysql-66594fb556-vg64r   1/1     Running   0          35m
```

###Podの削除によるPVCで要求したVolumeの削除
最後に、こちらのPodをお掃除します。`Reclaim Policy`は、Deleteで作ってあるデフォルトの`StorageClass`を利用しているため、この2つのPodを消すことで、PVCによって要求されたVolumeは綺麗になるハズです。

KarbonのUI画面は、WordPressをデプロイする前と同じ状態に戻りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/f640e009-01df-c01c-c263-b17877ecbb9b.png)


KarbonのPluginとしてデフォルトで利用可能なKibanaのLogTrailでログを追ってみましたが量が多いので抜粋したものが以下のような感じ。

```
Dec 16 00:28:18
karbon-ce-milk02-4e3adb-k8s-master-0 kube-apiserver-karbon-ce-milk02-4e3adb-k8s-master-0: I1215 15:28:18.284180
1 wrap.go:47] DELETE /api/v1/persistentvolumes/pvc-94facb9c-1f48-11ea-831c-506b8df55666: (12.0125ms) 200 [csi-provisioner/v0.0.0 (linux/amd64) kubernetes/$Format 172.16.10.43:54884]


Dec 16 00:28:27
karbon-ce-milk02-4e3adb-k8s-master-0 kube-apiserver-karbon-ce-milk02-4e3adb-k8s-master-0: I1215 15:28:27.208092
1 wrap.go:47] DELETE /api/v1/persistentvolumes/pvc-4648134d-1f48-11ea-831c-506b8df55666: (7.042595ms) 200 [csi-provisioner/v0.0.0 (linux/amd64) kubernetes/$Format 172.16.10.43:54884]
```

Prismのストレージのダッシュボードからも綺麗さっぱり消えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/3335a3a3-dd9b-b7d9-c49b-04912e97d440.png)

Prismのタスクのダッシュボードから見ると、少し見づらいですが、マウスでドラッグした部分が実際にNutanix側のストレージが操作された様子で12/16/19, 12:28:04 AMあたりからNutanix側のストレージに対してタスクが走っている様子がうかがえます（この時点でJSTで15日の投稿が間に合わなかったことがバレます、ごめんなさい）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/132c533a-0866-da99-9473-baef0a68aa2f.png)

#まとめ
NutanixのCSI Volume Pluginは、パブリッククラウド生まれの思想に基づく高いスケーラビリティや可用性、耐障害性を有した、既に仮想化インフラストラクチャーそそのストレージとしても実績があるNutanix上のストレージをKubernetes上のPodに提供します。

このCSI Volume Pluginは通じて行われるKubernetes上のPodからのストレージ要求や削除の操作に対して、Kubernetes上のpv、pvcの操作だけでなく、Nutanixのストレージもシームレスに利用することが可能です。

Nutanixはプロプライエタリなプロダクトではありますが、誰でも無償で利用可能なCommunity Editionもあり、そちらでKarbonも動作しますので、（Community Editionをインストールすると言う手間はありますが…）、パブリッククラウドではなくオンプレミスで仮想化基盤もKubernetesもを使いたいが、どちらかと言うとKubernetesの構築が面倒という方、NutanixのCSI Volume Pluginに興味のある方は試してみてはいかがでしょうか。

明日（と言うか、もう今日になってしまいましたが）のKubernetes Advent Calendar 2019の2枚目、16日目の投稿は、@yukirii さんなります。