ストレージオーケストレーター Rook : 第4話 追撃! トリプル・ポッド

まいど。レッドハットでストレージを中心にクラウドインフラを生業にしている宇都宮です。

Rook 1.1がリリースされました。色々なアップデートがありますが、Ceph-CSIがproduction-readyで対応したことからCephにとって大きな一歩になるでしょう。
さて前回は、Rook-Cephで障害を起こしてみてアプリに与える影響がどんなもんかを見てみました。今回はちょっと座学的になりますがRook-Ceph CSIの紹介とアーキテクチャのお話しをしたいと思います。

去る9/11(水)にOpenShift Meetup #6が開催されました。雷雲うごめく中お越しいただいた皆様、ご登壇くださった皆様、本当にありがとうございました!
そしてもう次回のOpenShift Meetup #7の情報が公開されています。注目のService MeshとServerless特集です!Twitter枠は空きがありますし、名古屋、大阪、福岡のサテライト会場でもLive中継されまーす!

OpenShift Meetup #5のセッション動画がcrash.academyさんで公開されています。Operatorガチな方々のセッションをご覧下さい!

あとRookとOpenShift Japan CommunityのTwitterアカウントがあります。@japan_rookと@openshiftjpです。フォローお願いします!

以上宣伝でした!

CSI : Container Storage Interface

はいそれでは本題に入ります。Rook-Ceph CSIをご紹介しますがその前にCSIってナンダ?というお話です。

CSIって何よ

CSIはKubernetes以外にもMesosとかCloudFoundryとかいろんなコンテナオーケストレーターシステム(COs)から、いろんなストレージを使えるように標準化されたストレージ管理APIです。
CSIがあることでユーザーはストレージに縛られることなくCOを選ぶことができるし、ストレージプロバイダはCO毎にドライバーを作ってメンテしなくて済みます。また、CSIはCOのコアの部分から隔離される形で実装されます。よってCOの開発側としてはコアの部分に謎のドライバロジックを埋め込むリスクもなくなりますし、ストレージのドライバ部分はテストしなくて済みます。
三方良しなアーキテクチャとして前々から必要性は言及されていたのですが、Kubernetesではv1.13でCSI 1.0がGAになりました。こちらの通り、色んなストレージプロバイダがCSI driverをリリースしています。
ちなみにKubernetesでは"in-tree plugin"と呼ばれる、Kubernetesのバイナリに組み込まれているストレージのドライバーが何種類かありますが、これら"in-tree"なドライバーは全てCSIに置き換えられるようになります。
"ストレージ CSI"でWeb検索するとたくさん記事が出てくるので、合わせて見てもらうとより理解が深まると思います。

f:id:ututaq:20190924184636p:plain
Container Storage Interfaceのざっくりした図

Rook-Cephのアーキテクチャ

よく見るRook-Cephのアーキテクチャ

Web検索で"Rook Ceph"とかで画像検索すると、こんな図をよく見ることができます。

f:id:ututaq:20190924184726p:plain
Rook-Ceph Architecture

まあ確かにこうなんやけど、、、具体的にデプロイした姿を見ればより理解が深まると思います。というわけで実際にRook-Cephデプロイして見てみましょう。なんと今回はCSI仕様です。ババーン。

Rook 1.1でCephをデプロイしてみよう

ではさっそく最新のRook 1.1を使ってRook-Cephを見てみましょう。今回はこんな6ノードのk8sクラスタを使います。worker nodeにそれぞれ10GBのEBSを1個ずつ付けてます。

[utubo@tutsunom ~]$ kubectl get node -L nodetype --sort-by='{.metadata.creationTimestamp}'
NAME                             STATUS   ROLES    AGE     VERSION   NODETYPE
ip-172-20-117-198.ec2.internal   Ready    master   32m     v1.15.3   
ip-172-20-37-240.ec2.internal    Ready    master   26m     v1.15.3   
ip-172-20-86-56.ec2.internal     Ready    master   19m     v1.15.3   
ip-172-20-70-151.ec2.internal    Ready    node     14m     v1.15.3   
ip-172-20-54-38.ec2.internal     Ready    node     7m41s   v1.15.3   
ip-172-20-121-163.ec2.internal   Ready    node     2m12s   v1.15.3   

あいにくOperatorHubのRook-Cephはまだ1.1じゃないんで、githubからインストールします。

*コマンド出力省略
[utubo@tutsunom ~]$ git clone https://github.com/rook/rook.git
[utubo@tutsunom ~]$ cd rook/cluster/examples/kubernetes/ceph
[utubo@tutsunom ceph]$ kubectl create -f common.yaml
[utubo@tutsunom ceph]$ kubectl create -f operator.yaml
[utubo@tutsunom ceph]$ kubectl create -f cluster.yaml

これで終わりですよ。やっぱ簡単だなぁ。幸せだなぁ。ぼかぁ君と居ると(略
5,6分コトコト煮込んでいると自動的にCephクラスタができてます。kubectl get allで見てみましょう。

[utubo@tutsunom ceph]$ kubectl get all -n rook-ceph
NAME                                                             READY   STATUS      RESTARTS   AGE
pod/csi-cephfsplugin-87xc7                                       3/3     Running     0          3m43s
pod/csi-cephfsplugin-j9dhm                                       3/3     Running     0          3m43s
pod/csi-cephfsplugin-provisioner-68b89bfd6c-ms22r                4/4     Running     0          3m43s
pod/csi-cephfsplugin-provisioner-68b89bfd6c-nc6q6                4/4     Running     0          3m43s
pod/csi-cephfsplugin-slvzj                                       3/3     Running     0          3m43s
pod/csi-rbdplugin-4ftsw                                          3/3     Running     0          3m43s
pod/csi-rbdplugin-d4plf                                          3/3     Running     0          3m43s
pod/csi-rbdplugin-dghcl                                          3/3     Running     0          3m43s
pod/csi-rbdplugin-provisioner-669fdd7465-4fjj2                   5/5     Running     0          3m43s
pod/csi-rbdplugin-provisioner-669fdd7465-d452m                   5/5     Running     0          3m43s
pod/rook-ceph-mgr-a-f4d9d7c66-qgqxt                              1/1     Running     0          2m19s
pod/rook-ceph-mon-a-6986bcb454-thb5x                             1/1     Running     0          2m57s
pod/rook-ceph-mon-b-8974d98f9-gxgnj                              1/1     Running     0          2m48s
pod/rook-ceph-mon-c-6957d6db48-5tp5j                             1/1     Running     0          2m33s
pod/rook-ceph-operator-54665977bf-8kqqs                          1/1     Running     0          5m8s
pod/rook-ceph-osd-0-5d4ff9f46d-cf8mj                             1/1     Running     0          79s
pod/rook-ceph-osd-1-5479f66fc9-xwgk9                             1/1     Running     0          78s
pod/rook-ceph-osd-2-77464c5648-shgtl                             1/1     Running     0          78s
pod/rook-ceph-osd-prepare-ip-172-20-121-163.ec2.internal-cntf7   0/1     Completed   0          114s
pod/rook-ceph-osd-prepare-ip-172-20-54-38.ec2.internal-c42bz     0/1     Completed   0          114s
pod/rook-ceph-osd-prepare-ip-172-20-70-151.ec2.internal-65s66    0/1     Completed   0          114s
pod/rook-discover-9vx4z                                          1/1     Running     0          5m7s
pod/rook-discover-gdsn7                                          1/1     Running     0          5m7s
pod/rook-discover-psnz5                                          1/1     Running     0          5m7s

NAME                               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/csi-cephfsplugin-metrics   ClusterIP   100.64.60.214    <none>        8080/TCP,8081/TCP   3m44s
service/csi-rbdplugin-metrics      ClusterIP   100.65.62.154    <none>        8080/TCP,8081/TCP   3m44s
service/rook-ceph-mgr              ClusterIP   100.71.205.11    <none>        9283/TCP            115s
service/rook-ceph-mgr-dashboard    ClusterIP   100.69.192.148   <none>        8443/TCP            116s
service/rook-ceph-mon-a            ClusterIP   100.70.114.174   <none>        6789/TCP,3300/TCP   2m58s
service/rook-ceph-mon-b            ClusterIP   100.70.177.170   <none>        6789/TCP,3300/TCP   2m51s
service/rook-ceph-mon-c            ClusterIP   100.67.165.255   <none>        6789/TCP,3300/TCP   2m39s

NAME                              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/csi-cephfsplugin   3         3         3       3            3           <none>          3m44s
daemonset.apps/csi-rbdplugin      3         3         3       3            3           <none>          3m44s
daemonset.apps/rook-discover      3         3         3       3            3           <none>          5m8s

NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/csi-cephfsplugin-provisioner   2/2     2            2           3m44s
deployment.apps/csi-rbdplugin-provisioner      2/2     2            2           3m44s
deployment.apps/rook-ceph-mgr-a                1/1     1            1           2m20s
deployment.apps/rook-ceph-mon-a                1/1     1            1           2m58s
deployment.apps/rook-ceph-mon-b                1/1     1            1           2m49s
deployment.apps/rook-ceph-mon-c                1/1     1            1           2m34s
deployment.apps/rook-ceph-operator             1/1     1            1           5m9s
deployment.apps/rook-ceph-osd-0                1/1     1            1           80s
deployment.apps/rook-ceph-osd-1                1/1     1            1           79s
deployment.apps/rook-ceph-osd-2                1/1     1            1           79s

NAME                                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/csi-cephfsplugin-provisioner-68b89bfd6c   2         2         2       3m44s
replicaset.apps/csi-rbdplugin-provisioner-669fdd7465      2         2         2       3m44s
replicaset.apps/rook-ceph-mgr-a-f4d9d7c66                 1         1         1       2m20s
replicaset.apps/rook-ceph-mon-a-6986bcb454                1         1         1       2m58s
replicaset.apps/rook-ceph-mon-b-8974d98f9                 1         1         1       2m49s
replicaset.apps/rook-ceph-mon-c-6957d6db48                1         1         1       2m34s
replicaset.apps/rook-ceph-operator-54665977bf             1         1         1       5m9s
replicaset.apps/rook-ceph-osd-0-5d4ff9f46d                1         1         1       80s
replicaset.apps/rook-ceph-osd-1-5479f66fc9                1         1         1       79s
replicaset.apps/rook-ceph-osd-2-77464c5648                1         1         1       79s

NAME                                                             COMPLETIONS   DURATION   AGE
job.batch/rook-ceph-osd-prepare-ip-172-20-121-163.ec2.internal   1/1           36s        116s
job.batch/rook-ceph-osd-prepare-ip-172-20-54-38.ec2.internal     1/1           37s        116s
job.batch/rook-ceph-osd-prepare-ip-172-20-70-151.ec2.internal    1/1           36s        116s

おや、前回までの出力と違いますね。 - csi-cephfspluginとかcsi-rbdplugin-provisionerとか、CSIドライバーっぽいのができてる - rook-ceph-agentが無い

そうなんです。1.1からRook-CephはCSIがデフォルトのドライバになります。だから特にCSI絡みのマニフェストファイルをkubectl createしなくてもCSIドライバーのPodが入るようになっています。
そして、rook-ceph-agentが無いのも実はこれに関連しています。rook-ceph-agentはFlexVolumeというストレージドライバで、worker nodeがCephのストレージをattachしたりmountしたりして使うために必要なドライバの役割を果たしていました。CSIがデフォルトになるまではFlexVolumeがデフォルトだったんですが、1.1からそれが逆転したのでrook-ceph-agentはいなくなりました。
ちなみにFlexVolumeはまだサポートされるので、operatorをデプロイするマニフェストファイルでFlexVolumeをEnableにすると、rook-ceph-agentはプロビジョンされます。

Podの配置を絵で見てみよう

割と結構な数のPodがたくさんあってごちゃごちゃしていますが、絵にするとこんな風になっています。

f:id:ututaq:20190924184817p:plain
Rook-Ceph CSI Pods

Podは大きくわけてRook, Ceph, Ceph CSIの3種類に群に分かれます。ガイア、マッシュ、オルテガと名付けるのはさすがに無理がありますが、こいつらのジェットストリームアタックによってアプリケーションにPVを提供するわけですね。はい。
ざっくり説明します。

Rook

  • rook-ceph-operator
    Rook-Ceph Operatorそのもの。
  • rook-discover
    worker nodeに接続されるストレージデバイスをリアルタイムに検知する。Cephクラスタが稼働中にノードにデバイスを挿すと、discoverにより自動的に認識されるが、その後Operatorが定義されているルールに則してCephクラスタに新規osdとして追加するかしないか決める。

Ceph

  • rook-ceph-mon
    Cephクラスタ全体を監視する。"MONitor"。障害等によるトポロジーの変化を察知し望ましい姿への復帰(下がった冗長性の復旧など)を司る。ユーザ認証も担う。
  • rook-ceph-osd
    Cephクラスタの保存媒体であるデバイスを抽象化した姿。"Object Store Device/Daemon"(諸説あり)。通常1デバイス=1osdの対応。Cephの全てのデータはosdによってデバイスに読み書きされる。
  • rook-ceph-mgr : Cephクラスターの管理面を担う。"ManaGeR"。Dashboardを提供したり、Prometheus,Zabbixなど外部ツールへのAPIを提供したりする。

Ceph CSI

Ceph CSIのPodに注目してみましょう。

  • csi-rbdplugin, csi-cephfsplugin
  • csi-rbdplugin-provisioner, csi-cephfsplugin-provisioner

というのがあります。
前者はApp PodがCeph RBD/CephFSのPVを使うためのドライバで、全てのworker nodeにプロビジョンされます。
後者はざっくり言えばmasterのkube-apiserverに飛んできたCeph RBD/CephFS PV関連のリクエストをwatchして、飛んできたらストレージシステムに対してトリガーするという仲介役と捉えればOKです。

絵の右側の通り、どのPodも複数のコンテナで構成されていますが、この中でオレンジのコンテナはKubernetesの開発側から共通で提供されていて、グリーンのコンテナはストレージプロバイダーが独自に開発して提供するものです。例えばcis-rbdplugin-provisionerを覗いてみましょう。

[utubo@tutsunom ceph]$ kubectl get pod csi-rbdplugin-provisioner-669fdd7465-4fjj2 -o json | jq -r '.status.containerStatuses[] | .name, .image' | xargs -n2
csi-provisioner quay.io/k8scsi/csi-provisioner:v1.3.0
csi-rbdplugin quay.io/cephcsi/cephcsi:v1.2.0
csi-rbdplugin-attacher quay.io/k8scsi/csi-attacher:v1.2.0
csi-snapshotter quay.io/k8scsi/csi-snapshotter:v1.2.0
liveness-prometheus quay.io/cephcsi/cephcsi:v1.2.0

5つコンテナがあるんですが、csi-provisioner,csi-rbdplugin-attacher,csi-rbdplugin-attacherquay.io/k8scsi/からpullしていて、csi-rbdplugin,liveness-prometheusquay.io/cephcsi/からpullしてることがわかります。
ストレージプロバイダーはオレンジのsidecarの仕様に合わせて、緑色のコンテナイメージだけを開発・メンテすることになります。kubernetesの中身には一切手を付けないようになっているので、ドライバの修正やアップデートをしやすくなっていますね。

これらのPodが具体的にどんな動きをするのかは、OpenShift Meetup #6のサイトにアップされている資料で何となくうかがい知ることができますので、よかったら見てみて下さい。

まとめ

そういうわけで今回は最新のRook 1.1でRook-Ceph CSIをデプロイしたときのアーキテクチャを紹介しました。何だかいろいろとできていないことがある気がするんですが、今回はここまで。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません