TECHSTEP

ITインフラ関連の記事を公開してます。

Rook-Ceph External Cluster ~VM上のCephクラスターをRookから利用する~

はじめに

Rook-Cephは、外部にあるCephクラスターを利用する機能を提供しています。

今回は、Rook OperatorをデプロイしたKubernetesから、VM上に構築されたCeph Clusterを利用する方法を紹介します。

External Clusterとは

Rookはストレージを利用するClientが、Clientと同じKubernetes上のストレージを利用するようデザインされています。しかし、常に同じKubernetes上のストレージを利用するだけでは、要件を満たせない場合があります。

  1. 一つのシングルクラスターでCephの管理を中央に集中させ、ストレージを利用する複数のKubernetes Clusterを利用する場合

  2. 利用者が既にCephの環境を所持しており、それがKubernetes環境上にない場合。例えばAnsible/ceph-deployなどで構築した環境を指す。

  3. 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)

  • ceph01: MON / OSD node
  • ceph02: MGR / OSD node
  • ceph03: OSD node

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

参考ドキュメント

Github - Rook/Rook: Rook and External Ceph Clusters

Rook Doc - Ceph Cluster CRD # External cluster