お試し Rook/Ceph

# はじめに
Kubernetes の PersistentVolume にはいくつもの種類があります。
今まで、以下の記事で２種類を試してみました。

* [Longhorn（v1.0） with Rancher](https://qiita.com/t_ume/items/a6bbb920238ec8b3d47f)
* [glusterfs on k8s](https://qiita.com/t_ume/items/cce5f4cebf77af293b91)

今回は Ceph を試してみようと思います。
構築には Rook という Storage Operator を使って行きます。

# 環境情報
kubeadm で構築した Kubernetes 上に構築します。

* OS：Ubuntu 18.04.5 LTS
* Kubernetes：v1.19.7
  * Node は３台構成です
  * Node にはルートディスクの他に PV 用の空ディスクをアタッチしています（※1）
* Ceph：15.2.11
* Rook：v1.6.1

Rook / Ceph の細かい前提条件は以下を参考に。
今回は基本の条件は満たしていたので特に追加の設定はしませんでした。

* [Rook Prerequisites](https://github.com/rook/rook/blob/master/Documentation/k8s-pre-reqs.md)
* [Ceph Prerequisites](https://github.com/rook/rook/blob/master/Documentation/ceph-prerequisites.md)

```console:※1
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda      8:0    0  10G  0 disk
  sda1   8:1    0  10G  0 part /
sdb      8:16   0  10M  0 disk
sdc      8:32   0  50G  0 disk  ★ 空のディスク
```

# Rook/Ceph deploy
まずは Rook を用意して Ceph デプロイの準備をします。

```
# Rook の資材をダウンロード
$ git clone --single-branch --branch v1.6.1 https://github.com/rook/rook.git

# example 内を確認
# Ceph 以外にも Cassandra / NFS を構築できます
$ ls rook/cluster/examples/kubernetes/
README.md  cassandra  ceph  mysql.yaml  nfs  wordpress.yaml

# 資材の配置ディレクトリに移動
# 今回の資材以外にも様々なパターンの yaml が用意されている
$ cd rook/cluster/examples/kubernetes/ceph/
$ ls
ceph-client.yaml                      dashboard-external-http.yaml   object-bucket-claim-delete.yaml   pool-test.yaml
cluster-external-management.yaml      dashboard-external-https.yaml  object-bucket-claim-retain.yaml   pool.yaml
cluster-external.yaml                 dashboard-ingress-https.yaml   object-ec.yaml                    pre-k8s-1.16
cluster-on-pvc.yaml                   dashboard-loadbalancer.yaml    object-external.yaml              rbdmirror.yaml
cluster-stretched.yaml                direct-mount.yaml              object-multisite-pull-realm.yaml  rgw-external.yaml
cluster-test.yaml                     filesystem-ec.yaml             object-multisite.yaml             scc.yaml
cluster.yaml                          filesystem-mirror.yaml         object-openshift.yaml             storageclass-bucket-delete.yaml
common-external.yaml                  filesystem-test.yaml           object-test.yaml                  storageclass-bucket-retain.yaml
common-second-cluster.yaml            filesystem.yaml                object-user.yaml                  test-data
common.yaml                           flex                           object.yaml                       toolbox-job.yaml
crds.yaml                             import-external-cluster.sh     operator-openshift.yaml           toolbox.yaml
create-external-cluster-resources.py  monitoring                     operator.yaml
create-external-cluster-resources.sh  nfs-test.yaml                  osd-purge.yaml
csi                                   nfs.yaml                       pool-ec.yaml

# 共通設定（Namespace / Role・RoleBindings など）を作成
$ kubectl create -f common.yaml
・・・

# Namespace が作成されていることを確認
$ kubectl get ns rook-ceph
NAME        STATUS   AGE
rook-ceph   Active   6m54s

# Rook の CRD（CustomResourceDefinitions）を作成
$ kubectl create -f crds.yaml
・・・

# CRD が登録されていることを確認
$ kubectl api-resources | grep rook
cephblockpools                           ceph.rook.io    true   CephBlockPool
cephclients                              ceph.rook.io    true   CephClient
cephclusters                             ceph.rook.io    true   CephCluster
cephfilesystemmirrors                    ceph.rook.io    true   CephFilesystemMirror
cephfilesystems                          ceph.rook.io    true   CephFilesystem
cephnfses              nfs               ceph.rook.io    true   CephNFS
cephobjectrealms                         ceph.rook.io    true   CephObjectRealm
cephobjectstores                         ceph.rook.io    true   CephObjectStore
cephobjectstoreusers   rcou,objectuser   ceph.rook.io    true   CephObjectStoreUser
cephobjectzonegroups                     ceph.rook.io    true   CephObjectZoneGroup
cephobjectzones                          ceph.rook.io    true   CephObjectZone
cephrbdmirrors                           ceph.rook.io    true   CephRBDMirror
volumes                rv                rook.io         true   Volume

# Rook の Ceph 用 Operator をデプロイします
$ kubectl create -f operator.yaml

# Operator の起動を確認
$  kubectl get cm,po -n rook-ceph
NAME                                  DATA   AGE
configmap/rook-ceph-operator-config   13     87s

NAME                                     READY   STATUS    RESTARTS   AGE
pod/rook-ceph-operator-95f44b96c-zfbhv   1/1     Running   0          87s
```

準備が出来たので早速 Ceph クラスタをデプロイしていきます。
先程の yaml 一覧に CRD の定義の例があるのでそちらを使ってデプロイしていきます。
ちなみに用意されている yaml には用途に応じていくつかの例があります。

* cluster-test.yaml
  * 開発環境用
  * ノードは1台から利用可能
  * Ceph のバージョンは v16 が指定されている
* cluster.yaml
  * 本番環境用
  * ノードは3台必要
  * Ceph のバージョンは v15.2.11 が指定されている
  * 今回はこちらを利用する
* cluster-on-pvc.yaml
  * パブクラ環境で PVC を利用する場合に利用？

Ceph デプロイのドキュメントは以下を参考にしました。
用意されている yaml を参考に適宜設定を変更することでカスタマイズした Ceph をデプロイすることが出来ます。

* [Ceph Examples](https://rook.io/docs/rook/v1.6/ceph-examples.html)

早速用意された yaml を使って Ceph をデプロイします。

```
# CR（CustomResource） である cephclusster のデプロイ
$ kubectl create -f cluster.yaml
cephcluster.ceph.rook.io/rook-ceph created

# しばらくするとコンテナが起動してくるので状況を確認
$ kubectl get po -n rook-ceph
NAME                                            READY   STATUS              RESTARTS   AGE
csi-cephfsplugin-7cm6r                          0/3     ContainerCreating   0          2s
csi-cephfsplugin-krs4r                          0/3     ContainerCreating   0          2s
csi-cephfsplugin-provisioner-5b989b9977-2t9dq   0/6     ContainerCreating   0          2s
csi-cephfsplugin-provisioner-5b989b9977-shwr9   0/6     ContainerCreating   0          2s
csi-cephfsplugin-xdnlf                          0/3     ContainerCreating   0          2s
csi-rbdplugin-56rlt                             3/3     Running             0          3s
・・・

# 作成された CR でも状況を確認できる
$  kubectl get cephclusters.ceph.rook.io  -n rook-ceph
NAME       DATADIRHOSTPATH  MONCOUNT  AGE    PHASE        MESSAGE                HEALTH  EXTERNAL
rook-ceph  /var/lib/rook    3         4m23s  Progressing  Configuring Ceph Mons

# デプロイ完了後の状態
$ kubectl get po -n rook-ceph
NAME                                             READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-5qcsr                           3/3     Running     0          3m29s
csi-cephfsplugin-8rh7q                           3/3     Running     0          3m29s
csi-cephfsplugin-m5rwp                           3/3     Running     0          3m29s
csi-cephfsplugin-provisioner-5b989b9977-2nfwd    6/6     Running     0          3m28s
csi-cephfsplugin-provisioner-5b989b9977-kmpzd    6/6     Running     0          3m28s
csi-rbdplugin-5vgnh                              3/3     Running     0          3m30s
csi-rbdplugin-provisioner-55f998c984-dfjzt       6/6     Running     0          3m30s
csi-rbdplugin-provisioner-55f998c984-sbqd8       6/6     Running     0          3m30s
csi-rbdplugin-qtkf5                              3/3     Running     0          3m30s
csi-rbdplugin-r2qm9                              3/3     Running     0          3m30s
rook-ceph-crashcollector-nd01-5b6f6c8974-wgw9s   1/1     Running     0          69s
rook-ceph-crashcollector-nd02-84bc45b685-cvvvc   1/1     Running     0          91s
rook-ceph-crashcollector-nd03-66b4dd645b-nk22j   1/1     Running     0          102s
rook-ceph-mgr-a-5c67fd5c76-ggrlg                 1/1     Running     0          79s
rook-ceph-mon-a-677c4fc69b-prvq7                 1/1     Running     0          3m18s
rook-ceph-mon-b-5b86596d64-w7mk5                 1/1     Running     0          111s
rook-ceph-mon-c-56598d55f5-g5559                 1/1     Running     0          91s
rook-ceph-operator-95f44b96c-gzh69               1/1     Running     0          8m25s
rook-ceph-osd-0-7754f799b8-dcdl7                 1/1     Running     0          70s
rook-ceph-osd-1-566b84474b-hzjht                 1/1     Running     0          70s
rook-ceph-osd-2-85b456dd84-2grnl                 1/1     Running     0          69s
rook-ceph-osd-prepare-nd01-gqbrq                 0/1     Completed   0          52s
rook-ceph-osd-prepare-nd02-d98t8                 0/1     Completed   0          49s
rook-ceph-osd-prepare-nd03-xg5z2                 0/1     Completed   0          47s

$ kubectl get cephclusters
NAME       DATADIRHOSTPATH  MONCOUNT  AGE    PHASE  MESSAGE                       HEALTH        EXTERNAL
rook-ceph  /var/lib/rook    3         5m35s  Ready  Cluster created successfully  HEALTH_WARN
```

無事に Ceph が起動しました。
途中で ```Pending``` や ```Init``` で止まった際には各 Pod を ```kubectl describe``` や ```kubectl log``` で確認してみてください。また、```rook-ceph-operator-XXXX``` を ```kubectl log``` で確認すると進行状態などもわかるので適宜確認してみるのも良いと思います。

どうにもならない時には一度削除して作り直してみるのも手です。
以下に手順があるのでご参考までに。私も失敗したときは消して作り直しました・・・

* [Cleaning up a Cluster](https://rook.io/docs/rook/v1.6/ceph-teardown.html)

# 動作確認
Ceph がデプロイできたので早速試していきましょう。
まずは Ceph に CLI でアクセスしてみます。```Toolbox``` と呼ばれる ceph コマンドが実行できる Pod の yaml があるのでデプロイして利用します。

```
# toolbox のデプロイ
$ kubectl apply -f toolbox.yaml
deployment.apps/rook-ceph-tools created

$ kubectl get po -l app=rook-ceph-tools
NAME                               READY   STATUS    RESTARTS   AGE
rook-ceph-tools-57787758df-s596f   1/1     Running   0          2m38s

# ceph コマンドでバージョンと状態を確認
$ kubectl exec rook-ceph-tools-57787758df-s596f -- ceph version
ceph version 15.2.11 (e3523634d9c2227df9af89a4eac33d16738c49cb) octopus (stable)

$ kubectl exec rook-ceph-tools-57787758df-s596f -- ceph status
  cluster:
    id:     25b3fce4-14e3-46c9-a9ce-f753ccaff570
    health: HEALTH_WARN
            mons are allowing insecure global_id reclaim
            mons a,c are low on available space

  services:
    mon: 3 daemons, quorum a,b,c (age 13m)
    mgr: a(active, since 12m)
    osd: 3 osds: 3 up (since 12m), 3 in (since 12m)

  data:
    pools:   1 pools, 1 pgs
    objects: 0 objects, 0 B
    usage:   3.0 GiB used, 147 GiB / 150 GiB avail
    pgs:     1 active+clean
```

それでは実際に Ceph を使って コンテナにマウントできる PV を作成します。
Ceph を利用した PV を作成するために、まずは StorageClass を作成します。
PVC 作成時に StorageClass を指定することで、StorageClass で定義されている種類の PV を動的に作成できるようになります。
StorageClass の yaml は以下に用意されているので、そちらを利用します。

* ```rook/cluster/examples/kubernetes/ceph/csi/rbd```

```
$ ls
pod.yaml        pvc-restore.yaml  snapshot.yaml       storageclass-ec.yaml    storageclass.yaml
pvc-clone.yaml  pvc.yaml          snapshotclass.yaml  storageclass-test.yaml

# StorageClass / CephBlockPool を登録
$ kubectl create -f storageclass.yaml
cephblockpool.ceph.rook.io/replicapool created
storageclass.storage.k8s.io/rook-ceph-block created

$ kubectl get sc
NAME              PROVISIONER                  RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
rook-ceph-block   rook-ceph.rbd.csi.ceph.com   Delete          Immediate           true                   103s
```

準備ができたので実際に PV = Ceph のブロックストレージ（RBD）を作成します。
今回はサンプルで用意されている WordPress をデプロイしていきます。
サンプル yaml は以下のパスに格納されています。

* ```rook/cluster/examples/kubernetes```

```
$ ls
README.md  cassandra  ceph  mysql.yaml  nfs  wordpress.yaml

# MySQL のデプロイ
$ kubectl apply -f mysql.yaml -n default
service/wordpress-mysql created
persistentvolumeclaim/mysql-pv-claim created
deployment.apps/wordpress-mysql created

# WordPress 用の Web サーバをデプロイ
$ kubectl apply -f wordpress.yaml -n default
service/wordpress created
persistentvolumeclaim/wp-pv-claim created
deployment.apps/wordpress created

# デプロイしたコンテナを確認
$ kubectl get deploy,po -n default
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress         1/1     1            1           60s
deployment.apps/wordpress-mysql   1/1     1            1           2m41s

NAME                                   READY   STATUS    RESTARTS   AGE
pod/wordpress-7b989dbf57-7zrln         1/1     Running   0          60s
pod/wordpress-mysql-6965fc8cc8-jd8bm   1/1     Running   0          2m41s

# 作成された PV/PVC を確認
$ kubectl get pvc,pv -n default
NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
persistentvolumeclaim/mysql-pv-claim   Bound    pvc-bd039533-b11e-415b-b2c6-d2f5a62c3cd0   20Gi       RWO            rook-ceph-block   2m41s
persistentvolumeclaim/wp-pv-claim      Bound    pvc-7617ba88-3fd1-4382-96b8-766510571dfa   20Gi       RWO            rook-ceph-block   60s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS      REASON   AGE
persistentvolume/pvc-7617ba88-3fd1-4382-96b8-766510571dfa   20Gi       RWO            Delete           Bound    default/wp-pv-claim      rook-ceph-block            60s
persistentvolume/pvc-bd039533-b11e-415b-b2c6-d2f5a62c3cd0   20Gi       RWO            Delete           Bound    default/mysql-pv-claim   rook-ceph-block            2m39s

# アクセス確認用に NodePort で定義されている Service を確認
# wordpress のポート（今回は 30541）を確認
$ kubectl get svc -n default
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes        ClusterIP      10.96.0.1        <none>        443/TCP        9d
service/wordpress         LoadBalancer   10.111.139.194   <pending>     80:30541/TCP   60s
service/wordpress-mysql   ClusterIP      None             <none>        3306/TCP       2m41s
```

デプロイした WordPress へのアクセスは以下のような NodePort のポート番号と、Node の IPアドレスでアクセスできます。

* ```http://<Node IP>:<NodePort>/```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/6d88d3cd-c0a5-19b0-0a5a-88cbcd801c2c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/5fd2a6c6-4450-492a-1d9c-45a6fa959ad1.png)

# まとめ
今回は Rook を使って Ceph をデプロイしてみました。
Rook を使って導入すると非常に簡単に導入することが出来ました。
サンプルの yaml も豊富にあるので、yaml から利用用途に合わせてカスタマイズをすることも容易ではと思います。
また、Ceph はブロックストレージの他にもオブジェクトストレージ、ファイルストレージとして使うこともできるため利用用途は様々かと思います。
Ceph 自身は非常に奥が深いソフトウェアのため、中々使いこなすには難しいというところもありそうです・・・

次回は導入した Ceph について諸々確認してみようと思います。

# 参考
Rook/Ceph の詳しい説明は先人たちの資料を読みました。わかり易い・・・

https://speakerdeck.com/tsukaman/ceph-wan-quan-nili-jie-sita-tute-tweetsuruwei-falsesetusiyon-ceph-101

https://speakerdeck.com/sat/cephkurasutagou-zhu-hefalsedao

https://qiita.com/MahoTakara/items/a1ed9811c790cd2a0d5f

また、弊社メンバのブログも参考にさせていただきました。

https://qiita.com/FY0323/items/b979e283ee5a60e37951

https://techstep.hatenablog.com/archive/category/Ceph

https://zaki-hmkc.hatenablog.com/entry/2020/07/05/170830

https://qiita.com/zaki-lknr/items/fb5b361d5facb05a6b93

先人たちに感謝です。