はじめに
Kubernetesは一時的なコンテナワークロードに最適化されていますが、実運用においては、データベースやログなど、永続的なデータを扱うケースが避けられません。
そのようなニーズに応えるのが、Ceph という分散ストレージシステムです。そして、Ceph を Kubernetes クラスタ上に簡単にデプロイ・管理できるようにしたのが Rook です。
第1章.Cephとは
Ceph(セフ) は、高い信頼性とスケーラビリティを持つ オープンソースの分散ストレージシステム です。オブジェクト、ブロック、ファイルといった複数のストレージインターフェースを一元的に提供できる点が大きな特徴です。
Cephの主な構成要素
用語 | 説明 |
---|---|
OSD(Object Storage Daemon) | データを実際に保存するプロセス(デーモン)で、スケールアウト可能。 |
MON(Monitor) | クラスタの状態を監視・管理するコンポーネント。 |
MGR(Manager) | 監視や管理、ダッシュボードなどの拡張機能を提供。 |
MDS(Metadata Server) | CephFS(ファイルシステム)に必要なメタデータ管理を担当。 |
RGW(RADOS Gateway) | オブジェクトストレージとしてのS3/Swift互換インターフェースを提供。 |
複数のフロントエンド機能とOSDを組み合わせることで、以下のように ブロック / ファイル / オブジェクト という異なるストレージサービスを柔軟に提供できる分散ストレージです。
Cephのメリット
用語 | 説明 |
---|---|
自己修復 | ディスク故障などに自動で対応可能。 |
スケーラブル | ノードやディスクの追加に柔軟に対応。 |
高可用性 | 複数のレプリカやEC(Erasure Coding)で耐障害性を確保。 |
これらの特徴により、Cephはオンプレミスやハイブリッドクラウド環境で非常に強力なストレージ基盤として採用されています。
第2章.Rookとは
Rook は、Kubernetesネイティブなストレージオーケストレーターです。Kubernetes クラスタ上で分散ストレージシステムをCRD(Custom Resource Definition)ベース で管理することを目的としています。
Kubernetesとの統合
Rook は Kubernetes Operator の仕組みを用いており、ストレージシステムのデプロイやアップグレード、障害時の自動復旧を自動化できます。またHelmやマニフェストで定義するだけで、Cephクラスタの構築が可能です。
第3章.環境の前提
今回は以下の環境で構築しています。
- コントロールプレーンノード1台:
- OS:Rocky Linux 9.5 (Blue Onyx)
- CPU:4
- メモリ:8G
- ワーカーノード1台
- OS:Rocky Linux 9.5 (Blue Onyx)
- CPU:4
- メモリ:8G
- Kubernetes:v1.33.2
- iSCSIストレージ:各ノードにsdb(128G)追加
- rook-ceph:v1.17.6
第4章.環境構築
各ノードにiSCSIでディスクを追加します。そのディスク領域をCephの領域として利用することを想定しています。また、この環境ではコントロールプレーンノードと、ワーカーノードは1台ずつで、コントローププレーンノード上でもPodをスケジューリングできるようにします。
環境構築 - 事前準備
各ノードには、iSCSIでディスクしています。targetcli-fb
を使用したストレージの追加については、以下でまとめました。
先述のとおり、コントロールプレーンノード、ワーカーノードが1台ずつしかないので、コントロールプレーンノードでもPodをスケジューリングできるようにします。
$ kubectl taint nodes kube-cpn-rocky-001 node-role.kubernetes.io/control-plane:NoSchedule-
公式ドキュメントに従い、必要なパッケージのインストールやカーネルモジュールがプローブされていることを確認しておきます。
lbm2のインストール
$ sudo yum install lvm2
出力例
$ sudo yum install -y lvm2
Last metadata expiration check: 0:34:49 ago on Sun 20 Jul 2025 11:50:37 AM JST.
Package lvm2-9:2.03.24-2.el9.x86_64 is already installed.
Dependencies resolved.
==============================================================================================================================================================================
Package Architecture Version Repository Size
==============================================================================================================================================================================
Upgrading:
device-mapper x86_64 9:1.02.202-6.el9 baseos 137 k
device-mapper-event x86_64 9:1.02.202-6.el9 baseos 34 k
device-mapper-event-libs x86_64 9:1.02.202-6.el9 baseos 31 k
device-mapper-libs x86_64 9:1.02.202-6.el9 baseos 178 k
lvm2 x86_64 9:2.03.28-6.el9 baseos 1.5 M
lvm2-libs x86_64 9:2.03.28-6.el9 baseos 1.0 M
Transaction Summary
==============================================================================================================================================================================
Upgrade 6 Packages
Total download size: 2.9 M
Downloading Packages:
(1/6): device-mapper-event-libs-1.02.202-6.el9.x86_64.rpm 220 kB/s | 31 kB 00:00
(2/6): device-mapper-event-1.02.202-6.el9.x86_64.rpm 185 kB/s | 34 kB 00:00
(3/6): device-mapper-1.02.202-6.el9.x86_64.rpm 1.4 MB/s | 137 kB 00:00
(4/6): lvm2-libs-2.03.28-6.el9.x86_64.rpm 3.0 MB/s | 1.0 MB 00:00
(5/6): device-mapper-libs-1.02.202-6.el9.x86_64.rpm 1.3 MB/s | 178 kB 00:00
(6/6): lvm2-2.03.28-6.el9.x86_64.rpm 4.9 MB/s | 1.5 MB 00:00
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 3.0 MB/s | 2.9 MB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Upgrading : device-mapper-libs-9:1.02.202-6.el9.x86_64 1/12
Upgrading : device-mapper-9:1.02.202-6.el9.x86_64 2/12
Upgrading : device-mapper-event-libs-9:1.02.202-6.el9.x86_64 3/12
Upgrading : device-mapper-event-9:1.02.202-6.el9.x86_64 4/12
Running scriptlet: device-mapper-event-9:1.02.202-6.el9.x86_64 4/12
Upgrading : lvm2-libs-9:2.03.28-6.el9.x86_64 5/12
Upgrading : lvm2-9:2.03.28-6.el9.x86_64 6/12
Running scriptlet: lvm2-9:2.03.28-6.el9.x86_64 6/12
Running scriptlet: lvm2-9:2.03.24-2.el9.x86_64 7/12
Cleanup : lvm2-9:2.03.24-2.el9.x86_64 7/12
Running scriptlet: lvm2-9:2.03.24-2.el9.x86_64 7/12
Cleanup : lvm2-libs-9:2.03.24-2.el9.x86_64 8/12
Running scriptlet: device-mapper-event-9:1.02.198-2.el9.x86_64 9/12
Cleanup : device-mapper-event-9:1.02.198-2.el9.x86_64 9/12
Cleanup : device-mapper-9:1.02.198-2.el9.x86_64 10/12
Cleanup : device-mapper-event-libs-9:1.02.198-2.el9.x86_64 11/12
Cleanup : device-mapper-libs-9:1.02.198-2.el9.x86_64 12/12
Running scriptlet: device-mapper-libs-9:1.02.198-2.el9.x86_64 12/12
Verifying : device-mapper-event-libs-9:1.02.202-6.el9.x86_64 1/12
Verifying : device-mapper-event-libs-9:1.02.198-2.el9.x86_64 2/12
Verifying : lvm2-libs-9:2.03.28-6.el9.x86_64 3/12
Verifying : lvm2-libs-9:2.03.24-2.el9.x86_64 4/12
Verifying : device-mapper-event-9:1.02.202-6.el9.x86_64 5/12
Verifying : device-mapper-event-9:1.02.198-2.el9.x86_64 6/12
Verifying : device-mapper-9:1.02.202-6.el9.x86_64 7/12
Verifying : device-mapper-9:1.02.198-2.el9.x86_64 8/12
Verifying : lvm2-9:2.03.28-6.el9.x86_64 9/12
Verifying : lvm2-9:2.03.24-2.el9.x86_64 10/12
Verifying : device-mapper-libs-9:1.02.202-6.el9.x86_64 11/12
Verifying : device-mapper-libs-9:1.02.198-2.el9.x86_64 12/12
Upgraded:
device-mapper-9:1.02.202-6.el9.x86_64 device-mapper-event-9:1.02.202-6.el9.x86_64 device-mapper-event-libs-9:1.02.202-6.el9.x86_64
device-mapper-libs-9:1.02.202-6.el9.x86_64 lvm2-9:2.03.28-6.el9.x86_64 lvm2-libs-9:2.03.28-6.el9.x86_64
Complete!
カーネルモージュールの確認
$ sudo modprobe rbd
$ lsmod | grep -i rbd
rbd 155648 0
libceph 614400 1 rbd
環境構築 - Rookの準備
rookをGitレポジトリをクローンします。ここに入っているvalues.yamlを編集して、helmでインストールしていきます。
$ git clone --single-branch --branch v1.17.6 https://github.com/rook/rook.git
本環境は少ないリソースなので、rook-ceph-cluster/values.yaml
以下のように変更いたしました。
# cephClusterSpec.mon
- count: 3
- allowMultiplePerNode: false
+ count: 1
+ allowMultiplePerNode: true
# cephClusterSpec.mgr
- count: 2
- allowMultiplePerNode: false
+ count: 1
+ allowMultiplePerNode: true
# cephClusterSpec.placement
- # placement:
- # all:
- # tolerations:
+ placement:
+ all:
+ tolerations:
+ - key: "node-role.kubernetes.io/control-plane"
+ operator: "Exists"
+ effect: "NoSchedule"
# cephClusterSpec.resources
- mgr:
- requests:
- cpu: "500m"
+ mgr:
+ requests:
+ cpu: "100m"
- mon:
- limits:
- memory: "2Gi"
- requests:
- cpu: "1000m"
- memory: "1Gi"
+ mon:
+ limits:
+ memory: "512Mi"
+ requests:
+ cpu: "100m"
+ memory: "256Mi"
- osd:
- limits:
- memory: "4Gi"
- requests:
- cpu: "1000m"
- memory: "4Gi"
+ osd:
+ limits:
+ memory: "2Gi"
+ requests:
+ cpu: "200m"
+ memory: "512Mi"
# mgr-sidecar
- mgr-sidecar:
- limits:
- memory: "100Mi"
- requests:
- cpu: "100m"
- memory: "40Mi"
+ mgr-sidecar:
+ limits:
+ memory: "128Mi"
+ requests:
+ cpu: "100m"
+ memory: "64Mi"
# crashcollector
- crashcollector:
- limits:
- memory: "60Mi"
- requests:
- cpu: "100m"
- memory: "60Mi"
+ crashcollector:
+ limits:
+ memory: "30Mi"
+ requests:
+ cpu: "30m"
+ memory: "20Mi"
# logcollector
- logcollector:
- limits:
- memory: "1Gi"
- requests:
- cpu: "100m"
- memory: "100Mi"
+ logcollector:
+ limits:
+ memory: "128Mi"
+ requests:
+ cpu: "50m"
+ memory: "64Mi"
# cleanup
- cleanup:
- limits:
- memory: "1Gi"
- requests:
- cpu: "500m"
- memory: "100Mi"
+ cleanup:
+ limits:
+ memory: "512Mi"
+ requests:
+ cpu: "200m"
+ memory: "64Mi"
# exporter
- exporter:
- limits:
- memory: "128Mi"
- requests:
- cpu: "50m"
- memory: "50Mi"
+ exporter:
+ limits:
+ memory: "32Mi"
+ requests:
+ cpu: "50m"
+ memory: "10Mi"
# cephClusterSpec.storage
- useAllNodes: true
- useAllDevices: true
+ useAllNodes: false
+ useAllDevices: false
+ nodes:
+ - name: "kube-cpn-rocky-001"
+ devices:
+ - name: "sdb"
+ - name: "kube-wn-rocky-001"
+ devices:
+ - name: "sdb"
# cephFileSystems.spec.metadataPool.replicated.size
- size: 3
+ size: 2
# cephFileSystems.spec.dataPools[0].replicated.size
- size: 3
+ size: 2
# cephFileSystems.metadataServer.resources
- limits:
- memory: "4Gi"
- requests:
- cpu: "1000m"
- memory: "4Gi"
+ limits:
+ memory: "128Mi"
+ requests:
+ cpu: "50m"
+ memory: "64Mi"
# cephObjectStores.spec.metadataPool.replicated.size
- size: 3
+ size: 2
# cephObjectStores.spec.gateway.resources
- limits:
- memory: "2Gi"
- requests:
- cpu: "1000m"
- memory: "1Gi"
+ limits:
+ memory: "256Mi"
+ requests:
+ cpu: "100m"
+ memory: "128Mi"
環境構築 - Operatorのインストール
では、実際にCephのインストールをしていきます。まずはKubernetes上でCephクラスタを管理・自動化するコントローラとなるOperatorをインストールします。
$ cd rook/deploy/charts/rook-ceph
$ helm repo add rook-release https://charts.rook.io/release
"rook-release" has been added to your repositories
$ helm install --create-namespace --namespace rook-ceph rook-ceph rook-release/rook-ceph -f values.yaml
NAME: rook-ceph
LAST DEPLOYED: Mon Jul 21 00:13:42 2025
NAMESPACE: rook-ceph
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The Rook Operator has been installed. Check its status by running:
kubectl --namespace rook-ceph get pods -l "app=rook-ceph-operator"
Visit https://rook.io/docs/rook/latest for instructions on how to create and configure Rook clusters
Important Notes:
- You must customize the 'CephCluster' resource in the sample manifests for your cluster.
- Each CephCluster must be deployed to its own namespace, the samples use `rook-ceph` for the namespace.
- The sample manifests assume you also installed the rook-ceph operator in the `rook-ceph` namespace.
- The helm chart includes all the RBAC required to create a CephCluster CRD in the same namespace.
- Any disk devices you add to the cluster in the 'CephCluster' must be empty (no filesystem and no partitions).
$ helm list -n rook-ceph
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
rook-ceph rook-ceph 1 2025-07-21 00:13:42.444158413 +0900 JST deployed rook-ceph-v1.17.6 v1.17.6
環境構築 - Clusterのインストール
次に実際に構築・運用されるCeph本体のストレージクラスタをインストールします。
$ cd rook/deploy/charts/rook-ceph-cluster
$ helm install --create-namespace --namespace rook-ceph rook-ceph-cluster \
--set operatorNamespace=rook-ceph rook-release/rook-ceph-cluster -f values.yaml
NAME: rook-ceph-cluster
LAST DEPLOYED: Mon Jul 21 00:27:33 2025
NAMESPACE: rook-ceph
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The Ceph Cluster has been installed. Check its status by running:
kubectl --namespace rook-ceph get cephcluster
Visit https://rook.io/docs/rook/latest/CRDs/Cluster/ceph-cluster-crd/ for more information about the Ceph CRD.
Important Notes:
- You can only deploy a single cluster per namespace
- If you wish to delete this cluster and start fresh, you will also have to wipe the OSD disks using `sfdisk`
$ helm list -n rook-ceph
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
rook-ceph rook-ceph 1 2025-07-21 00:13:42.444158413 +0900 JST deployed rook-ceph-v1.17.6 v1.17.6
rook-ceph-cluster rook-ceph 1 2025-07-21 00:27:33.894690573 +0900 JST deployed rook-ceph-cluster-v1.17.6 v1.17.6
環境構築 - Cephのステータス確認
すべてのPodが立ち上がったことを確認します。
$ kubectl get pods -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-ctcnt 3/3 Running 0 49m
csi-cephfsplugin-pmbgq 3/3 Running 0 49m
csi-cephfsplugin-provisioner-65db79cdbf-fszhc 6/6 Running 0 49m
csi-cephfsplugin-provisioner-65db79cdbf-l5lbw 6/6 Running 0 49m
csi-rbdplugin-9hqdr 3/3 Running 0 49m
csi-rbdplugin-provisioner-554f545465-7n94s 6/6 Running 0 49m
csi-rbdplugin-provisioner-554f545465-b2bn2 6/6 Running 0 49m
csi-rbdplugin-wxglw 3/3 Running 0 49m
rook-ceph-crashcollector-kube-cpn-rocky-001-744f985587-hc8rt 1/1 Running 0 47m
rook-ceph-crashcollector-kube-wn-rocky-001-769665b6bf-fq7b5 1/1 Running 0 46m
rook-ceph-exporter-kube-cpn-rocky-001-645d4cc647-gwbpn 1/1 Running 0 47m
rook-ceph-exporter-kube-wn-rocky-001-65d5f74b9c-vkjzh 1/1 Running 0 46m
rook-ceph-mds-ceph-filesystem-a-55c54dbcd8-gg88c 2/2 Running 0 46m
rook-ceph-mds-ceph-filesystem-b-7c7d4854db-vzgjv 2/2 Running 0 46m
rook-ceph-mgr-a-7d9f6f5b68-t2d2d 2/2 Running 0 32m
rook-ceph-mon-a-85c9cf6794-tgv2w 2/2 Running 0 48m
rook-ceph-operator-598f985d87-dnbth 1/1 Running 0 49m
rook-ceph-osd-0-765749cfbb-xthf8 2/2 Running 0 37m
rook-ceph-osd-1-c7d8565f6-47wbb 2/2 Running 0 37m
rook-ceph-osd-prepare-kube-cpn-rocky-001-tnj5j 0/1 Completed 0 32m
rook-ceph-osd-prepare-kube-wn-rocky-001-fxh58 0/1 Completed 0 32m
rook-ceph-rgw-ceph-objectstore-a-796f4688d9-6ns55 2/2 Running 0 36m
第5章.動作確認
それでは実際にPersistent Volumeを作成して問題なく利用できることを確認します。
動作確認 - PVCの作成
以下のマニフェストを用意しました。今回はFileSystemでPVCを作成します。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-ceph-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 64Mi
storageClassName: ceph-filesystem
では実際にPVCを作成します。
$ kubectl apply -f ceph-pvc.yaml
persistentvolumeclaim/my-ceph-pvc created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
my-ceph-pvc Bound pvc-35c33e34-f4ae-4c4d-af8c-cb35536fa780 64Mi RWX ceph-filesystem <unset> 4s
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-35c33e34-f4ae-4c4d-af8c-cb35536fa780 64Mi RWX Delete Bound default/my-ceph-pvc ceph-filesystem <unset> 6s
動作確認 - Podからの利用
次に先ほどをPVCを利用できるようにPodを作成します。以下のマニフェストを用意しました。
apiVersion: v1
kind: Pod
metadata:
name: ceph-test-pod
spec:
containers:
- name: app
image: busybox
command: [ "sleep", "3600" ]
volumeMounts:
- mountPath: /mnt/mydata
name: ceph-vol
volumes:
- name: ceph-vol
persistentVolumeClaim:
claimName: my-ceph-pvc
では実際にPodを作成します。
$ kubectl apply -f ceph-pod.yaml
pod/ceph-test-pod created
Podに入って、ファイルを作成します。
$ kubectl exec -it ceph-test-pod -- sh
/ # cd mnt/mydata/
/mnt/mydata # touch sample.txt
/mnt/mydata # exit
一度Podを削除して、再度Pod作成します。再度デプロイしたのち、同じフォルダに先ほど作成したファイルが存在していることが確認できました。PV/PVCは問題なく使えていそうです。
$ kubectl delete -f ceph-pod.yaml
pod "ceph-test-pod" deleted
$ kubectl apply -f ceph-pod.yaml
pod/ceph-test-pod created
$ kubectl exec -it ceph-test-pod -- sh
/ # cd mnt/mydata/
/mnt/mydata # ls
sample.txt
以上です。