Rookの概要とRook-Ceph
この記事はRookだらけの Advent Calendar 2019 1日目の記事です。
うつぼです。Advent Calendar用にRookの記事を書きます。赤帽エンジニアブログに(勝手に)連載中のストレージオーケストレーター Rookよりも、ちょっとおとなしい感じで書こうと思います。
とは言え初日はRookの概要的なことをまとめたりRook-Cephをやってみます。赤帽エンジニアブログで書いた内容と思いっきりカブりますが、これがないと2日目以降がやりにくくなると思うので…
Rookとは何か
Rookとは、Kubernetesで使うストレージオーケストレーターです。
RookによってCephやEdgeFSなどのSDSや、CockroachDBやYugabyteDBといった分散データベースを、Kubernetesクラスタ上で簡単に展開して分散ストレージクラスタを作ることができます。
Rookは対応するソフトウェアごとにOperatorが用意されます。OperatorによってDay1およびDay 2のオペレーションが(全部ではないが)自動化されることで、Kubernetesのストレージ周りの運用を楽にしてくれます。
Rookは2018年にCNCFの15番目のプロジェクトとして承認され、現在IncubatingなOSSです。日に日に開発が行われている、現在アツいストレージ関連のソフトウェアの一つと言えるでしょう。
Rookに対応するソフトウェア
Rookに対応するソフトウェアは、12/1の時点で7つです。
Name | API Group | Status |
---|---|---|
Ceph | ceph.rook.io/v1 | V1(Stable) |
EdgeFS | edgefs.rook.io/v1 | V1(Stable) |
Cassandra | cassandra.rook.io/v1alpha1 | Alpha |
CockroachDB | cockroachdb.rook.io/v1alpha1 | Alpha |
Minio | minio.rook.io/v1alpha1 | Alpha |
NFS | nfs.rook.io/v1alpha1 | Alpha |
YugabyteDB | yugabytedb.rook.io/v1alpha1 | Alpha |
https://rook.io/docs/rook/v1.1/quickstart-toc.html
kubernetesクラスター上でストレージを展開する意義
ストレージやDBと言えば止まったら大事故に繋がるシステムなので、直感的には、コンテナで構成するのはどうなの?と感じるかもしれません。しかし大きなメリットがあるのです。
Kubernetesの神がかったリソース管理の仕組みを使える
Kubernetesクラスター上でストレージが展開されるということで、これらは全てPodで稼働します。
例えば仮にストレージソフトウェアのPodが落ちたとしても、自動で配置可能なノードにPodを再スケジュールしてストレージクラスタに再加入させて、自動修復させることができます。ストレージクラスタの拡張/縮小はkubernetes scale
をベースに行えるし、ソフトウェアアップグレードもコンテナイメージを順次新しい物に置き換えてPodを上げればいいです。データの冗長性や整合性はストレージソフトウェアの機能によって担保します。
インフラ管理者の宿命と諦めていた従来のストレージ運用作業はかなり楽になります。
Interoperabilityという名の鎖から解き放たれる
Kubernetesのバージョンさえ満たしていればどんな環境でも展開できます。オンプレだろうがクラウドだろうが関係ありません。OSやハイパーバイザーのバージョンだとかI/Oアダプターの型番だとかドライバーのバージョンだとか、従来のストレージでネックになっていた事をほとんど考慮しなくていいという実践的な嬉しさもあります。
アップグレードやストレージ更改のたびに戦ってきたInteroeprabilityとほとんど戦わなくてすみます。
Rook-Cephをやってみる
Twitterでjapan_rookとか名乗ってるわりに、うつぼはRook-Cephしか芸がありません。恥ずかしいですが、ここでもRook-Cephをやってみます。
普通にやるだけではさすがに芸がないので、Cephクラスターが展開される様子を追っかけてみましょう。
Kubernetesクラスターを用意します
master x 3, worker(kubernetes.io/role=node
) x 3です。workerにはそれぞれ20GiBのデバイスを1つずつ搭載しています。このデバイスをCephで使います。
[utubo@tutsunom ceph]$ kubectl get node --sort-by=".metadata.creationTimestamp" NAME STATUS ROLES AGE VERSION ip-172-20-104-194.ec2.internal Ready master 4m20s v1.15.5 ip-172-20-36-239.ec2.internal Ready master 4m4s v1.15.5 ip-172-20-79-199.ec2.internal Ready master 3m32s v1.15.5 ip-172-20-32-157.ec2.internal Ready node 103s v1.15.5 ip-172-20-82-111.ec2.internal Ready node 101s v1.15.5 ip-172-20-103-26.ec2.internal Ready node 99s v1.15.5
Quickstartの手順にしたがってみます
Ceph Storage Quickstartのkuberctl create
3発が一番簡単にCephをデプロイする方法です。
[utubo@tutsunom ~]$ git clone -b release-1.1 https://github.com/rook/rook.git [utubo@tutsunom ~]$ cd rook/cluster/examples/kubernetes/ceph
kubectl create -f common.yaml
最初にnamespaceを作って、CRDやRBAC, ServiceAccountなどのリソースを作ってくれます。
[utubo@tutsunom ceph]$ kubectl create -f common.yaml namespace/rook-ceph created customresourcedefinition.apiextensions.k8s.io/cephclusters.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/cephfilesystems.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/cephnfses.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/cephobjectstores.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/cephobjectstoreusers.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/cephblockpools.ceph.rook.io created customresourcedefinition.apiextensions.k8s.io/volumes.rook.io created customresourcedefinition.apiextensions.k8s.io/objectbuckets.objectbucket.io created customresourcedefinition.apiextensions.k8s.io/objectbucketclaims.objectbucket.io created clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-object-bucket created clusterrole.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt created clusterrole.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt-rules created role.rbac.authorization.k8s.io/rook-ceph-system created clusterrole.rbac.authorization.k8s.io/rook-ceph-global created clusterrole.rbac.authorization.k8s.io/rook-ceph-global-rules created clusterrole.rbac.authorization.k8s.io/rook-ceph-mgr-cluster created clusterrole.rbac.authorization.k8s.io/rook-ceph-mgr-cluster-rules created clusterrole.rbac.authorization.k8s.io/rook-ceph-object-bucket created serviceaccount/rook-ceph-system created rolebinding.rbac.authorization.k8s.io/rook-ceph-system created clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-global created serviceaccount/rook-ceph-osd created serviceaccount/rook-ceph-mgr created serviceaccount/rook-ceph-cmd-reporter created role.rbac.authorization.k8s.io/rook-ceph-osd created clusterrole.rbac.authorization.k8s.io/rook-ceph-osd created clusterrole.rbac.authorization.k8s.io/rook-ceph-mgr-system created clusterrole.rbac.authorization.k8s.io/rook-ceph-mgr-system-rules created role.rbac.authorization.k8s.io/rook-ceph-mgr created role.rbac.authorization.k8s.io/rook-ceph-cmd-reporter created rolebinding.rbac.authorization.k8s.io/rook-ceph-cluster-mgmt created rolebinding.rbac.authorization.k8s.io/rook-ceph-osd created rolebinding.rbac.authorization.k8s.io/rook-ceph-mgr created rolebinding.rbac.authorization.k8s.io/rook-ceph-mgr-system created clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-mgr-cluster created clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-osd created rolebinding.rbac.authorization.k8s.io/rook-ceph-cmd-reporter created podsecuritypolicy.policy/rook-privileged created clusterrole.rbac.authorization.k8s.io/psp:rook created clusterrolebinding.rbac.authorization.k8s.io/rook-ceph-system-psp created rolebinding.rbac.authorization.k8s.io/rook-ceph-default-psp created rolebinding.rbac.authorization.k8s.io/rook-ceph-osd-psp created rolebinding.rbac.authorization.k8s.io/rook-ceph-mgr-psp created rolebinding.rbac.authorization.k8s.io/rook-ceph-cmd-reporter-psp created serviceaccount/rook-csi-cephfs-plugin-sa created serviceaccount/rook-csi-cephfs-provisioner-sa created role.rbac.authorization.k8s.io/cephfs-external-provisioner-cfg created rolebinding.rbac.authorization.k8s.io/cephfs-csi-provisioner-role-cfg created clusterrole.rbac.authorization.k8s.io/cephfs-csi-nodeplugin created clusterrole.rbac.authorization.k8s.io/cephfs-csi-nodeplugin-rules created clusterrole.rbac.authorization.k8s.io/cephfs-external-provisioner-runner created clusterrole.rbac.authorization.k8s.io/cephfs-external-provisioner-runner-rules created clusterrolebinding.rbac.authorization.k8s.io/rook-csi-cephfs-plugin-sa-psp created clusterrolebinding.rbac.authorization.k8s.io/rook-csi-cephfs-provisioner-sa-psp created clusterrolebinding.rbac.authorization.k8s.io/cephfs-csi-nodeplugin created clusterrolebinding.rbac.authorization.k8s.io/cephfs-csi-provisioner-role created serviceaccount/rook-csi-rbd-plugin-sa created serviceaccount/rook-csi-rbd-provisioner-sa created role.rbac.authorization.k8s.io/rbd-external-provisioner-cfg created rolebinding.rbac.authorization.k8s.io/rbd-csi-provisioner-role-cfg created clusterrole.rbac.authorization.k8s.io/rbd-csi-nodeplugin created clusterrole.rbac.authorization.k8s.io/rbd-csi-nodeplugin-rules created clusterrole.rbac.authorization.k8s.io/rbd-external-provisioner-runner created clusterrole.rbac.authorization.k8s.io/rbd-external-provisioner-runner-rules created clusterrolebinding.rbac.authorization.k8s.io/rook-csi-rbd-plugin-sa-psp created clusterrolebinding.rbac.authorization.k8s.io/rook-csi-rbd-provisioner-sa-psp created clusterrolebinding.rbac.authorization.k8s.io/rbd-csi-nodeplugin created clusterrolebinding.rbac.authorization.k8s.io/rbd-csi-provisioner-role created
kubectl create -f operator.yaml
rook-ceph-operatorを作ってくれます。別窓でwatch kubectl -n rook-ceph get pod
していると、operatorの次にrook-discover agentが生まれるのが見えます。rook-discoverはdaemonsetなので各worker上で動きます。
[utubo@tutsunom ceph]$ kubectl create -f operator.yaml deployment.apps/rook-ceph-operator created
別窓
[utubo@tutsunom ceph]$ watch kubectl -n rook-ceph get pod NAME READY STATUS RESTARTS AGE rook-ceph-operator-fb8b96548-rxzn6 0/1 ContainerCreating 0 11s ↓ NAME READY STATUS RESTARTS AGE rook-ceph-operator-fb8b96548-rxzn6 1/1 Running 0 33s rook-discover-5qqs8 1/1 Running 0 9s rook-discover-8jn4w 0/1 ContainerCreating 0 9s rook-discover-msfjm 0/1 ContainerCreating 0 9s ↓ NAME READY STATUS RESTARTS AGE rook-ceph-operator-fb8b96548-rxzn6 1/1 Running 0 52s rook-discover-5qqs8 1/1 Running 0 28s rook-discover-8jn4w 1/1 Running 0 28s rook-discover-msfjm 1/1 Running 0 28s
kubectl create -f cluster.yaml
ここが見どころです。operatorによって次々とCephのコンポーネントが生成される様子は圧巻。ぜひここでも別窓でwatch kubectl -n rook-ceph get pod
しておいて下さい。
※出力が長くなるので生まれるPodだけ書きます。
[utubo@tutsunom ceph]$ kubectl create -f cluster.yaml cephcluster.ceph.rook.io/rook-ceph created
別窓
[utubo@tutsunom ceph]$ watch kubectl -n rook-ceph get pod 1. Ceph-CSIのpluginを生成 NAME READY STATUS RESTARTS AGE csi-cephfsplugin-79hrg 3/3 Running 0 8s csi-cephfsplugin-pnrg9 3/3 Running 0 8s csi-cephfsplugin-provisioner-974b566d9-kk95l 4/4 Running 0 8s csi-cephfsplugin-provisioner-974b566d9-r8p5d 0/4 ContainerCreating 0 8s csi-cephfsplugin-zwm4m 0/3 ContainerCreating 0 8s csi-rbdplugin-4mhvb 3/3 Running 0 8s csi-rbdplugin-5gwtb 3/3 Running 0 8s csi-rbdplugin-j7kx9 0/3 ContainerCreating 0 8s csi-rbdplugin-provisioner-579c546f5-s7j7q 0/5 ContainerCreating 0 8s csi-rbdplugin-provisioner-579c546f5-z84jx 0/5 ContainerCreating 0 8s rook-ceph-detect-version-vfxrt 0/1 Init:0/1 0 2s ---略--- ↓ 2. rook-ceph-mon-x-canary --> rook-ceph-mon-x の順でCeph MONを生成 NAME READY STATUS RESTARTS AGE ---略--- rook-ceph-mon-a-canary-7469b766b6-4r9wn 0/1 Terminating 0 11s rook-ceph-mon-b-canary-795fb574cc-ldmwr 1/1 Running 0 10s rook-ceph-mon-c-canary-9c4dbbd5b-6ff8b 1/1 Running 0 10s ---略--- ↓ NAME READY STATUS RESTARTS AGE ---略--- rook-ceph-mon-a-9b889cd9f-dvmr2 1/1 Running 0 24s rook-ceph-mon-b-758455b88f-cw6pz 1/1 Running 0 15s rook-ceph-mon-c-698785577b-plhb2 0/1 Init:0/2 0 1s ---略--- ↓ 3. Ceph MGRを生成 NAME READY STATUS RESTARTS AGE ---略--- rook-ceph-mgr-a-546669c64f-pvr4d 1/1 Running 0 16s ---略--- ↓ 4. rook-ceph-osd-prepare --> rook-ceph-osd-x の順でCeph OSDを生成 NAME READY STATUS RESTARTS AGE ---略--- rook-ceph-osd-prepare-ip-172-20-103-26.ec2.internal-hmpl5 0/1 PodInitializing 0 3s rook-ceph-osd-prepare-ip-172-20-32-157.ec2.internal-9jsgh 0/1 PodInitializing 0 3s rook-ceph-osd-prepare-ip-172-20-82-111.ec2.internal-6d4b9 0/1 PodInitializing 0 3s ---略--- ↓ NAME READY STATUS RESTARTS AGE ---略--- rook-ceph-osd-0-757bf68778-p9qx8 1/1 Running 0 8s rook-ceph-osd-1-6d4b48bb84-r7mdz 1/1 Running 0 7s rook-ceph-osd-2-5bcf8c96dc-snxx2 1/1 Running 0 7s rook-ceph-osd-prepare-ip-172-20-103-26.ec2.internal-hmpl5 0/1 Completed 0 39s rook-ceph-osd-prepare-ip-172-20-32-157.ec2.internal-9jsgh 0/1 Completed 0 39s rook-ceph-osd-prepare-ip-172-20-82-111.ec2.internal-6d4b9 0/1 Completed 0 39s ---略---
以上で終わりです。最後はこんな感じになります。
[utubo@tutsunom ceph]$ kubectl -n rook-ceph get pod NAME READY STATUS RESTARTS AGE csi-cephfsplugin-79hrg 3/3 Running 0 2m11s csi-cephfsplugin-pnrg9 3/3 Running 0 2m11s csi-cephfsplugin-provisioner-974b566d9-kk95l 4/4 Running 0 2m11s csi-cephfsplugin-provisioner-974b566d9-r8p5d 4/4 Running 0 2m11s csi-cephfsplugin-zwm4m 3/3 Running 0 2m11s csi-rbdplugin-4mhvb 3/3 Running 0 2m11s csi-rbdplugin-5gwtb 3/3 Running 0 2m11s csi-rbdplugin-j7kx9 3/3 Running 0 2m11s csi-rbdplugin-provisioner-579c546f5-s7j7q 5/5 Running 0 2m11s csi-rbdplugin-provisioner-579c546f5-z84jx 5/5 Running 0 2m11s rook-ceph-mgr-a-546669c64f-pvr4d 1/1 Running 0 63s rook-ceph-mon-a-9b889cd9f-dvmr2 1/1 Running 0 100s rook-ceph-mon-b-758455b88f-cw6pz 1/1 Running 0 91s rook-ceph-mon-c-698785577b-plhb2 1/1 Running 0 77s rook-ceph-operator-fb8b96548-rxzn6 1/1 Running 0 4m6s rook-ceph-osd-0-757bf68778-p9qx8 1/1 Running 0 8s rook-ceph-osd-1-6d4b48bb84-r7mdz 1/1 Running 0 7s rook-ceph-osd-2-5bcf8c96dc-snxx2 1/1 Running 0 7s rook-ceph-osd-prepare-ip-172-20-103-26.ec2.internal-hmpl5 0/1 Completed 0 39s rook-ceph-osd-prepare-ip-172-20-32-157.ec2.internal-9jsgh 0/1 Completed 0 39s rook-ceph-osd-prepare-ip-172-20-82-111.ec2.internal-6d4b9 0/1 Completed 0 39s rook-discover-5qqs8 1/1 Running 0 3m42s rook-discover-8jn4w 1/1 Running 0 3m42s rook-discover-msfjm 1/1 Running 0 3m42s
ちゃんとCephとして稼働してることも確認できます。
[utubo@tutsunom ceph]$ kubectl create -f toolbox.yaml deployment.apps/rook-ceph-tools created [utubo@tutsunom ceph]$ kubectl exec -it `kubectl get pod -l app=rook-ceph-tools -o 'jsonpath={.items[].metadata.name}'` \ > ceph status cluster: id: a12e3584-b4b0-4939-98ba-1a086579d233 health: HEALTH_OK services: mon: 3 daemons, quorum a,b,c (age 3m) mgr: a(active, since 3m) osd: 3 osds: 3 up (since 2m), 3 in (since 2m) data: pools: 0 pools, 0 pgs objects: 0 objects, 0 B usage: 3.0 GiB used, 54 GiB / 57 GiB avail pgs:
コマンド3発だけで、CSI pluginとMON, MGR, OSDが次々と生まれてCephクラスタができました。こんなに簡単にクラスタを作れるのは衝撃的です。
しかもAGEのカラムに注目すると、rook-ceph-operatorを作ってからわずか4分です。Rookのおかげで4分でストレージが作れます。これはもう革命だ!
まとめ
Rookは対応するSDSやDBのoperatorでストレージのオーケストレーションを行うツールです。
ストレージの構築から運用まで、強力に手助けしてくれる革命的なツールです。
後半はRookでCephクラスタを作るところを追っかけてみましたが、実際に試してみるとよりRookの威力を実感すると思います。ぜひ試してみて下さいね。