はじめに
Rook-Cephは、外部にあるCephクラスターを利用する機能を提供しています。
今回は、Rook OperatorをデプロイしたKubernetesから、VM上に構築されたCeph Clusterを利用する方法を紹介します。
External Clusterとは
Rookはストレージを利用するClientが、Clientと同じKubernetes上のストレージを利用するようデザインされています。しかし、常に同じKubernetes上のストレージを利用するだけでは、要件を満たせない場合があります。
一つのシングルクラスターでCephの管理を中央に集中させ、ストレージを利用する複数のKubernetes Clusterを利用する場合
利用者が既にCephの環境を所持しており、それがKubernetes環境上にない場合。例えばAnsible/ceph-deployなどで構築した環境を指す。
Kubernetes compute nodeからストレージを完全に隔離する場合。これはKubernetesシングルクラスターの場合でも、label、taint、toleration等の機能を利用することで、技術的には実現できる。
例えば、VM等にアプリケーションを配置する構成からKubernetes・コンテナを利用する構成に移行したいとき、永続的なデータをKubernetesに移行する前に、既存のCephクラスターを利用する場合が考えられます。
ここでは、Ceph Clusterを利用する側(Kubernetes cluster側)をLocal Cluster、利用される側のClusterをExternal Clusterとします。
検証環境
今回はAzureVMを利用し、以下のようなインスタンスを用意します。ネットワークはシンプルにするため、全てのVMを同じリージョン/仮想ネットワーク/サブネットに配置しました。
Local Cluster (Rook-Ceph Cluster)
- master node: 1台
- worker node: 1台
External Cluster (Ceph Cluster)
Kubernetes Clusterの構築
Kubernetesの構築にはkubeadmを利用し、こちらの記事の手順を利用しました。ただしCNIはflannelを利用しました。
[root@rook-master ~]# kubectl apply -f https://raw.githubusercontent.com/coreos/ flannel/master/Documentation/kube-flannel.yml podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds-amd64 created daemonset.apps/kube-flannel-ds-arm64 created daemonset.apps/kube-flannel-ds-arm created daemonset.apps/kube-flannel-ds-ppc64le created daemonset.apps/kube-flannel-ds-s390x created [root@rook-master ~]# [root@rook-master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION rook-master Ready master 3m15s v1.17.3 rook-worker Ready <none> 72s v1.17.3 [root@rook-master ~]
External Ceph Clusterの構築
Ceph Clusterの構築はceph-deployを利用するこちらの手順を参考にしました。
External Clusterの利用方法
ここからKubernetesクラスター上からExternal Clusterを利用する手順になります。まず、External Clusterを利用する条件を確認します。
- External Cluster側に最低1つのMON endpointが利用できること
- External Clusterを操作するのに必要なAdmin Keyring情報
- Local ClusterからExternal ClusterのMON・OSD・MGR・MDSへのネットワーク接続性があること
- External ClusterのCephバージョンが、Local Clusterの利用できるバージョンの条件を満たすこと
最後の条件について補足しておきます。今回利用するRook v1.2は、External ClusterのバージョンがCeph Nautilus以上であることが条件となります。
構築時点のExternal ClusterのCephバージョンはmimic v13.2.8であり、このままのバージョンでExternal Clusterを利用しようとすると、以下のようなエラーログが出力されます。
[root@rook-master ceph]# kubectl logs rook-ceph-operator-69d86f8597-gw646 -n rook-ceph | tail (中略) 2020-02-17 07:04:24.260434 E | op-cluster: failed to configure external ceph cluster. failed to detect and validate ceph version: failed to validate ceph version between external and local: unsupported ceph version "13.2.8-0 mimic", need at least nautilus, delete your cluster CR and create a new one with a correct ceph version [root@rook-master ceph]#
External ClusterのCephバージョンアップ
まずはExternal Clusterのバージョンアップを行います。手順はCeph公式ドキュメントに従います。
# バージョンアップ前 # status health_warnとなっているが検証用のため無視 [root@ceph01 ~]# ceph version ceph version 13.2.8 (5579a94fafbc1f9cc913a0f5d362953a5d9c3ae0) mimic (stable) [root@ceph01 ~]# ceph mon stat e1: 1 mons at {ceph02=10.3.0.5:6789/0}, election epoch 5, leader 0 ceph02, quorum 0 ceph02 [root@ceph01 ~]# ceph status cluster: id: ef9377bc-077a-4a0b-a6e3-69834df6cede health: HEALTH_WARN Reduced data availability: 1 pg inactive too few PGs per OSD (20 < min 30) services: mon: 1 daemons, quorum ceph02 mgr: ceph01(active) osd: 4 osds: 3 up, 3 in data: pools: 2 pools, 21 pgs objects: 7 objects, 149 B usage: 3.0 GiB used, 186 GiB / 189 GiB avail pgs: 4.762% pgs unknown 20 active+clean 1 unknown [root@ceph01 ~]# # MONノードのアップデート [root@ceph01 ~]# ceph-deploy install --release nautilus ceph02 (中略) [ceph02][DEBUG ] Complete! [ceph02][INFO ] Running command: ceph --version [ceph02][DEBUG ] ceph version 14.2.7 (3d58626ebeec02d8385a4cefb92c6cbc3a45bfe8) nautilus (stable) # OSDノードのアップデート [root@ceph01 ~]# ceph-deploy install --release nautilus ceph03 (中略) [ceph03][DEBUG ] Complete! [ceph03][INFO ] Running command: ceph --version [ceph03][DEBUG ] ceph version 14.2.7 (3d58626ebeec02d8385a4cefb92c6cbc3a45bfe8) nautilus (stable) [root@ceph01 ~]# ceph-deploy install --release nautilus ceph01 (中略) [ceph01][DEBUG ] Complete! [ceph01][INFO ] Running command: ceph --version [ceph01][DEBUG ] ceph version 14.2.7 (3d58626ebeec02d8385a4cefb92c6cbc3a45bfe8) nautilus (stable) # 各ノードにてサービスの再起動 ## ceph02 [root@ceph02 ~]# yum update [root@ceph02 ~]# systemctl status ceph-mon.target [root@ceph02 ~]# systemctl restart ceph-mon.target [root@ceph02 ~]# systemctl status ceph-osd.target [root@ceph02 ~]# systemctl restart ceph-osd.target ## ceph03 [root@ceph03 ~]# systemctl status ceph-osd.target [root@ceph03 ~]# systemctl restart ceph-osd.target ## ceph01 [root@ceph01 ~]# systemctl status ceph-osd.target [root@ceph01 ~]# systemctl restart ceph-osd.target
Local ClusterからExternal Clusterの利用
ここからLocal Cluster側の設定を行います。
Rook Operatorデプロイ
まずはRook Operatorをデプロイします。また今回はrook-ceph-external
という専用のNamespaceを利用するため、common-external.yaml
ファイルを合わせて利用します。
[root@rook-master ~]# git clone --single-branch --branch release-1.2 [root@rook-master ~]# cd rook/cluster/examples/kubernetes/ceph/ [root@rook-master ceph]# kubectl apply -f common.yaml [root@rook-master ceph]# kubectl apply -f operator.yaml [root@rook-master ceph]# kubectl apply -f common-external.yaml
ConfigMap・Secretリソースの生成
次にExternal Clusterを利用するためのConfigMap・Secretファイルを用意します。各ファイルはExternal ClusterのMON endpoint、Admin Keyring情報を持たせ、Local Clusterからその情報を利用するために生成します。
ConfigMap・Secretファイルの生成は、Rookリポジトリで用意されているimport-external-cluster.sh
シェルスクリプトを利用します。このスクリプトファイルは、あらかじめ設定した環境変数を利用してリソースを作成します。設定が必要な環境変数は以下の4つです。
# NAMESPACE:Local Clusterを利用するNamespace名 [root@rook-master ceph]# export NAMESPACE=rook-ceph-external # ROOK_EXTERNAL_FSID:External ClusterのFSID [root@rook-master ceph]# export ROOK_EXTERNAL_FSID=e7f7bb40-60e2-4fe9-bbbf-2aab93690f08 # ROOK_EXTERNAL_ADMIN_SECRET:External Clusterのcluster.adminのSecret [root@rook-master ceph]# export ROOK_EXTERNAL_ADMIN_SECRET=AQD/I0peSLF7GxAA/HnA9bnFdrBZvTfB6I29Tw== # ROOK_EXTERNAL_CEPH_MON_DATA:External ClusterのMON endpoint [root@rook-master ceph]# export ROOK_EXTERNAL_CEPH_MON_DATA=ceph02=10.3.0.5:6789
これらの情報は、External Cluster側で以下の通り確認することができます。
# ROOK_EXTERNAL_FSID [root@ceph01 ~]# ceph fsid ef9377bc-077a-4a0b-a6e3-69834df6cede # ROOK_EXTERNAL_ADMIN_SECRET [root@ceph01 ~]# ceph auth get-key client.admin AQD/I0peSLF7GxAA/HnA9bnFdrBZvTfB6I29Tw==[root@ceph01 ~]# # ROOK_EXTERNAL_CEPH_MON_DATA [root@ceph01 ~]# ceph mon stat e2: 1 mons at {ceph02=v1:10.3.0.5:6789/0}, election epoch 9, leader 0 ceph02, quorum 0 ceph02
Local Clusterで環境変数を設定したのち、import-external-cluster.sh
を実行します。
[root@rook-master ceph]# bash import-external-cluster.sh secret/rook-ceph-mon created configmap/rook-ceph-mon-endpoints created
Local Clusterデプロイ
最後にLocal Clusterをデプロイします。利用するcluster-external.yaml
では、External ClusterのCephバージョンを正しく指定する必要があります。
apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: name: rook-ceph-external namespace: rook-ceph-external spec: external: enable: true dataDirHostPath: /var/lib/rook cephVersion: image: ceph/ceph:v14.2.7 # external cluster versionと同じ値を指定
上記ファイルをデプロイ後、しばらくするとConnected
状態となります。
[root@rook-master ceph]# kubectl apply -f cluster-external.yaml cephcluster.ceph.rook.io/rook-ceph-external created [root@rook-master ceph]# kubectl get cephcluster.ceph.rook.io/rook-ceph-external -n rook-ceph-external NAME DATADIRHOSTPATH MONCOUNT AGE STATE HEALTH rook-ceph-external /var/lib/rook 2m Connected HEALTH_WARN [root@rook-master ceph]#
External Clusterの利用
Local ClusterからExternal Clusterに接続ができたので、External Clusterを利用してアプリケーションを稼働させます。
今回はブロックストレージを利用してアプリケーションPodを起動するため、CephBlockPool
StorageClass
リソースをデプロイし、PersistentVolumeClaims
経由でストレージを利用します。
利用するyamlファイルはそれぞれ以下の通りです。
apiVersion: ceph.rook.io/v1 kind: CephBlockPool metadata: name: replicapool02 namespace: rook-ceph-external spec: failureDomain: host replicated: size: 1
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: rook-ceph-block provisioner: rook-ceph.rbd.csi.ceph.com parameters: # clusterID is the namespace where the rook cluster is running # If you change this namespace, also change the namespace below where the secret namespaces are defined clusterID: rook-ceph-external # If you want to use erasure coded pool with RBD, you need to create # two pools. one erasure coded and one replicated. # You need to specify the replicated pool here in the `pool` parameter, it is # used for the metadata of the images. # The erasure coded pool must be set as the `dataPool` parameter below. #dataPool: ec-data-pool pool: replicapool02 # RBD image format. Defaults to "2". imageFormat: "2" # RBD image features. Available for imageFormat: "2". CSI RBD currently supports only `layering` feature. imageFeatures: layering # The secrets contain Ceph admin credentials. These are generated automatically by the operator # in the same namespace as the cluster. csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph-external csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph-external csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph-external # Specify the filesystem type of the volume. If not specified, csi-provisioner # will set default as `ext4`. csi.storage.k8s.io/fstype: ext4 # uncomment the following to use rbd-nbd as mounter on supported nodes #mounter: rbd-nbd allowVolumeExpansion: true reclaimPolicy: Delete
上記ファイルをデプロイします。Local Clusterにリソースが作成されるのに加え、External Cluster側でもPoolの作成を確認できます。
[root@rook-master rbd]# kubectl apply -f blockpool-external.yaml [root@rook-master rbd]# kubectl apply -f storageclass-external.yaml [root@rook-master rbd]# kubectl get cephblockpool.ceph.rook.io/replicapool02 -n rook-ceph-external NAME AGE replicapool02 21s [root@rook-master rbd]# kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 3s # External Clusterからも確認できる [root@ceph01 ~]# ceph osd pool ls pool01 pool02 replicapool02 ★
さて、あとはPersistentVolumeClaims
をデプロイすればよいのですが、このままPVCをデプロイすると、以下のようなメッセージが表示されPending
状態のままになってしまいます。
[root@rook-master rbd]# kubectl apply -f pvc.yaml persistentvolumeclaim/rbd-pvc created [root@rook-master rbd]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rbd-pvc Pending rook-ceph-block 3m22s [root@rook-master rbd]# kubectl describe pvc rbd-pvc (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Provisioning 109s (x9 over 3m57s) rook-ceph.rbd.csi.ceph.com_csi-rbdplugin-provisioner-7bb78d6c66-qx8hq_562412dd-2718-477d-97d3-9f7903415b96 External provisioner is provisioning volume for claim "default/rbd-pvc" Warning ProvisioningFailed 109s (x9 over 3m57s) rook-ceph.rbd.csi.ceph.com_csi-rbdplugin-provisioner-7bb78d6c66-qx8hq_562412dd-2718-477d-97d3-9f7903415b96 failed to provision volume with StorageClass "rook-ceph-block": rpc error: code = InvalidArgument desc = failed to fetch monitor list using clusterID (rook-ceph-external): missing configuration for cluster ID (rook-ceph-external) Normal ExternalProvisioning 3s (x17 over 3m57s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "rook-ceph.rbd.csi.ceph.com" or manually created by system administrator
この状態を改善するため、Local Clusterのrook-ceph-csi-config
ConfigMapを修正します。
[root@rook-master rbd]# kubectl describe cm rook-ceph-csi-config -n rook-ceph Name: rook-ceph-csi-config Namespace: rook-ceph Labels: <none> Annotations: <none> Data ==== csi-cluster-config-json: ---- [] # ここを修正する Events: <none> [root@rook-master rbd]# [root@rook-master rbd]# kubectl edit cm rook-ceph-csi-config -n rook-ceph configmap/rook-ceph-csi-config edited [root@rook-master rbd]# kubectl describe cm rook-ceph-csi-config -n rook-ceph Name: rook-ceph-csi-config Namespace: rook-ceph Labels: <none> Annotations: <none> Data ==== csi-cluster-config-json: ---- [{"clusterID":"rook-ceph-external","monitors":["10.3.0.5:6789"]}] # ClusterID、MON endpoint情報を追加する Events: <none> [root@rook-master rbd]#
上記のようにConfigMapを修正したのち、PVCを再デプロイすると、Bound
状態になります。ここまでくれば、あとはPodからPVC経由でストレージを利用できます。
[root@rook-master rbd]# kubectl describe pvc rbd-pvc (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ExternalProvisioning 5s persistentvolume-controller waiting for a volume to be created, either by external provisioner "rook-ceph.rbd.csi.ceph.com" or manually created by system administrator Normal Provisioning 5s rook-ceph.rbd.csi.ceph.com_csi-rbdplugin-provisioner-7bb78d6c66-qx8hq_562412dd-2718-477d-97d3-9f7903415b96 External provisioner is provisioning volume for claim "default/rbd-pvc" Normal ProvisioningSucceeded 2s rook-ceph.rbd.csi.ceph.com_csi-rbdplugin-provisioner-7bb78d6c66-qx8hq_562412dd-2718-477d-97d3-9f7903415b96 Successfully provisioned volume pvc-8f073de8-a2e2-461d-bff9-9c9525aa30a8 [root@rook-master rbd]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rbd-pvc Bound pvc-8f073de8-a2e2-461d-bff9-9c9525aa30a8 1Gi RWO rook-ceph-block 11s [root@rook-master rbd]# kubectl apply -f pod.yaml [root@rook-master rbd]# kubectl get pods NAME READY STATUS RESTARTS AGE csirbd-demo-pod 1/1 Running 0 10s [root@rook-master rbd]#
なお、今回利用しているpvc.yaml
pod.yaml
は以下の通りです。
--- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: rbd-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: rook-ceph-block
--- apiVersion: v1 kind: Pod metadata: name: csirbd-demo-pod spec: containers: - name: web-server image: nginx volumeMounts: - name: mypvc mountPath: /var/lib/www/html volumes: - name: mypvc persistentVolumeClaim: claimName: rbd-pvc readOnly: false