hidemium's blog

日々学んだことをアウトプットする。

Rook Cephを使った分散ストレージのインストール

前回は、IngressSSL/TLSを有効にする方法を試してみました。今回は、Rook Cephを使って分散ストレージのインストールを試してみました。

hidemium.hatenablog.com

構成

PersistentVolumeについて

KubernetesのPersistentVolume(PV)を利用するために、ボリュームプラグインとしてKubernetesに組み込まれたIn-Tree Volume PluginとContainer Storage Interface(CSI)を利用することができます。詳細は以下のリストにありますが、ベンダー向けのIn-Tree Volume PluginからCSIに置き換わってきています。

Persistent Volumes | Kubernetes

homelabで利用する場合は、NFSを用意したり、vSphereのCSIのvSphere Container Storage Plug-inを利用するという方法が取れるかと思います。

VMware vSphere Container Storage Plug-in Documentation

今回の構成では、仮想マシンをworkerノードとしており、workerノードを物理サーバーと見たててハイパーコンバージドインフラストラクチャのような構成がためせないかと思い、分散ストレージのRook Cephを試してみました。

Rook Cephを利用する場合は、Ceph CSIを利用する形になります。

Rook Cephについて

Rook Cephは、Kubernetes上に分散ストレージのCephをデプロイし、ストレージの運用(展開、ブートストラップ、構成、プロビジョニング、スケーリング、アップグレード、移行、災害復旧、監視、およびリソース管理)を自動化してくれるストレージオペレーターです。

Rook

Cephは、オブジェクト、ブロック、ファイル ストレージといった複数のインターフェースでアクセスできる分散オブジェクトストレージプラットフォームです。

Welcome to Ceph — Ceph Documentation

Cephは4つのコンポーネントから成り立っています。

  1. Ceph Monitor (ceph-mon)
  2. Ceph Manager (ceph-rgw)
  3. Ceph OSD (object storage daemon (ceph-osd))
  4. Ceph Metadata Server (ceph-mds)

Ceph Monitorはクラスター状態を監視します。Monitorは少なくても3つ必要となります。

Ceph Managerはメトリクスやシステム負荷を監視やダッシュボードの提供します。Managerはすくなくても2つ必要となります。

Ceph OSDはデータを保存し、データのレプリケーションリカバリ、リバランスを処理し、Ceph Monitor と Ceph Manager に監視情報を提供し ます。OSDは少なくても3つ必要となります。

Ceph Metadata Serverは、CephFSのメタデータを保存し、Ceph Block Device とCephオブジェクトストレージは使用されません。

Kubernetesの再構築

Rook Cephを試すにあたり、以前構築した手順から少し変更を加えます。

hidemium.hatenablog.com

Rook Cephでは通常のデプロイをする場合は、最低3台のノードが必要なため、workerノードを2台から4台に増やします。Kubesprayのhosts.ymlを以下のように書き換えます。

$ vi hosts.yml
all:
  hosts:
    kube-master01:
      ansible_host: 10.0.50.30
      ip: 10.0.50.30
      access_ip: 10.0.50.30
    kube-master02:
      ansible_host: 10.0.50.31
      ip: 10.0.50.31
      access_ip: 10.0.50.31
    kube-master03:
      ansible_host: 10.0.50.32
      ip: 10.0.50.32
      access_ip: 10.0.50.32
    kube-worker01:
      ansible_host: 10.0.50.33
      ip: 10.0.50.33
      access_ip: 10.0.50.33
    kube-worker02:
      ansible_host: 10.0.50.34
      ip: 10.0.50.34
      access_ip: 10.0.50.34
    kube-worker03:
      ansible_host: 10.0.50.35
      ip: 10.0.50.35
      access_ip: 10.0.50.35
    kube-worker04:
      ansible_host: 10.0.50.36
      ip: 10.0.50.36
      access_ip: 10.0.50.36
  children:
    kube_control_plane:
      hosts:
        kube-master01:
        kube-master02:
        kube-master03:
    kube_node:
      hosts:
        kube-worker01:
        kube-worker02:
        kube-worker03:
        kube-worker04:
    etcd:
      hosts:
        kube-master01:
        kube-master02:
        kube-master03:
    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:
    calico_rr:
      hosts: {}

また、CNIをcalicoからflannelに変更します。

$ vi inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
- kube_network_plugin: calico
+ kube_network_plugin: flannel

masterノードとworkerノードのデプロイ

Ubuntu 22.04のテンプレートを作成し、以下のスペックでテンプレートを用意しておきます。

  • CPU: 1vCPU
  • Memory: 4GB
  • Disk: 100GB

masterノードとworkerノードのスペックはそれぞれの以下の通りになります。

node vCPU Memory Disk1 Disk2
master 1 4GB 100GB -
worker 1 4GB 100GB 100GB

govcを使って、テンプレートからのクローンやcloud-initの設定、追加ディスクのアタッチをまとめて、以下のように実行できます。

$ for VMNAME in kube-worker0{1..4}; do
  echo ${VMNAME}
  export VM="/Datacenter/vm/path/to/$VMNAME"
  govc vm.clone -vm template-vm -on=false -folder="/Datacenter/vm/k8s" $VMNAME
  export METADATA=$(gzip -c9 <metadata-${VMNAME}.yaml | { base64 -w0 2>/dev/null || base64; }) USERDATA=$(gzip -c9 <userdata-kube.yaml | { base64 -w0 2>/dev/null || base64; })
  govc vm.change -vm "${VM}" -e guestinfo.metadata="${METADATA}" -e guestinfo.metadata.encoding="gzip+base64" -e guestinfo.userdata="${USERDATA}" -e guestinfo.userdata.encoding="gzip+base64"
  govc vm.disk.create -vm ${VM} -name ${VMNAME}/${VMNAME}-disk2 -ds  datastore_name -size 100G
  govc vm.power -on "${VM}"
done

削除する場合は、以下のようにも実行できます。

$ for VMNAME in kube-worker0{1..3}; do
  echo ${VMNAME}
  export VM="/Datacenter/vm/path/to/$VMNAME"
  govc vm.info "${VM}"
  govc vm.destroy "${VM}"
done

Kubesprayによるクラスタ構築

以下のコマンドで再度Kubernetesクラスタを構築します。

$ ansible-playbook -i inventory/mycluster/hosts.yml  --become --become-user=root cluster.yml

workerノードの状態の確認

デプロイ直後のworkerノードの状態を確認しておきます。

Disk2として接続したディスクが、 sdb として表示されていることが分かります。 sda 側はOS領域としてLVMで構成されています。

$ lsblk -f
NAME                      FSTYPE      FSVER    LABEL UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
loop0                     squashfs    4.0                                                         0   100% /snap/lxd/23541
loop2                     squashfs    4.0                                                         0   100% /snap/core20/1738
loop3                     squashfs    4.0                                                         0   100% /snap/snapd/17883
loop4                     squashfs    4.0                                                         0   100% /snap/lxd/22923
loop5                     squashfs    4.0                                                         0   100% /snap/snapd/17950
loop6                     squashfs    4.0                                                         0   100% /snap/core20/1778
sda                                                                                                        
├─sda1                                                                                                     
├─sda2                    ext4        1.0            a2ece314-f49d-4c09-ad59-6f90402eb8e6      1.3G    14% /boot
└─sda3                    LVM2_member LVM2 001       nv6J0B-VyPL-K1x1-Rfti-oHC0-94RQ-DQ3tex                
  └─ubuntu--vg-ubuntu--lv ext4        1.0            2bcaf132-16b8-4b64-9e35-f200b40dfbf9       81G    12% /
sdb

Rookのインストール

それではRookのインストールを行っています。

まずは、rookのリポジトリをダウンロードします。

$ git clone --single-branch --branch v1.10.9 https://github.com/rook/rook.git

Rook Operatorをデプロイします。

$ cd rook
$ cd deploy/examples
$ kubectl create -f crds.yaml -f common.yaml -f operator.yaml

rook-ceph-operatorのpodが起動してきたことを確認します。

$ kubectl get pods -n rook-ceph
NAME                                  READY   STATUS    RESTARTS   AGE
rook-ceph-operator-76686d66c9-tjh8c   1/1     Running   0          6m13s

次にCeph Clusterをデプロイします。

$ kubectl create -f cluster.yaml

以下のようにpodが起動してくることを確認します。

$ kubectl -n rook-ceph get pod -o wide
NAME                                                      READY   STATUS      RESTARTS   AGE     IP             NODE            NOMINATED NODE   READINESS GATES
csi-cephfsplugin-688zw                                    2/2     Running     0          46h     10.0.50.35     kube-worker03   <none>           <none>
csi-cephfsplugin-8qtzx                                    2/2     Running     0          46h     10.0.50.36     kube-worker04   <none>           <none>
csi-cephfsplugin-bkdqh                                    2/2     Running     0          46h     10.0.50.34     kube-worker02   <none>           <none>
csi-cephfsplugin-njz7s                                    2/2     Running     0          46h     10.0.50.33     kube-worker01   <none>           <none>
csi-cephfsplugin-provisioner-75b9f74d7b-9spfw             5/5     Running     0          46h     10.233.68.4    kube-worker02   <none>           <none>
csi-cephfsplugin-provisioner-75b9f74d7b-bvhjd             5/5     Running     0          46h     10.233.70.5    kube-worker03   <none>           <none>
csi-rbdplugin-4h4lk                                       2/2     Running     0          46h     10.0.50.33     kube-worker01   <none>           <none>
csi-rbdplugin-bglgs                                       2/2     Running     0          46h     10.0.50.35     kube-worker03   <none>           <none>
csi-rbdplugin-p9xgj                                       2/2     Running     0          46h     10.0.50.34     kube-worker02   <none>           <none>
csi-rbdplugin-provisioner-66d48ddf89-b6845                5/5     Running     0          46h     10.233.67.5    kube-worker04   <none>           <none>
csi-rbdplugin-provisioner-66d48ddf89-rpjws                5/5     Running     0          46h     10.233.69.3    kube-worker01   <none>           <none>
csi-rbdplugin-pspw6                                       2/2     Running     0          46h     10.0.50.36     kube-worker04   <none>           <none>
rook-ceph-crashcollector-kube-worker01-9f7b6f546-q5h9b    1/1     Running     0          46h     10.233.69.6    kube-worker01   <none>           <none>
rook-ceph-crashcollector-kube-worker02-67f84cb9b9-qfgdz   1/1     Running     0          46h     10.233.68.9    kube-worker02   <none>           <none>
rook-ceph-crashcollector-kube-worker03-7687b79c6d-srxnr   1/1     Running     0          46h     10.233.70.6    kube-worker03   <none>           <none>
rook-ceph-crashcollector-kube-worker04-76c99494c5-6psss   1/1     Running     0          46h     10.233.67.11   kube-worker04   <none>           <none>
rook-ceph-mgr-a-6d8bb6dc9b-4hnkh                          3/3     Running     0          46h     10.233.67.7    kube-worker04   <none>           <none>
rook-ceph-mgr-b-96b47c755-bv2h8                           3/3     Running     0          46h     10.233.68.6    kube-worker02   <none>           <none>
rook-ceph-mon-a-bb685559c-gtjwm                           2/2     Running     0          46h     10.233.70.4    kube-worker03   <none>           <none>
rook-ceph-mon-b-6dcb8f97b9-xgnvn                          2/2     Running     0          46h     10.233.67.6    kube-worker04   <none>           <none>
rook-ceph-mon-c-c97b95cf6-l7ng4                           2/2     Running     0          46h     10.233.68.5    kube-worker02   <none>           <none>
rook-ceph-operator-54fc78d7c9-6n7gd                       1/1     Running     0          46h     10.233.67.2    kube-worker04   <none>           <none>
rook-ceph-osd-0-59645d69db-p7x56                          2/2     Running     0          46h     10.233.70.8    kube-worker03   <none>           <none>
rook-ceph-osd-1-69c67b85f9-cbqfc                          2/2     Running     0          46h     10.233.68.10   kube-worker02   <none>           <none>
rook-ceph-osd-2-7b56666677-qwt2x                          2/2     Running     0          46h     10.233.67.10   kube-worker04   <none>           <none>
rook-ceph-osd-3-5bf94d4467-pznrt                          2/2     Running     0          46h     10.233.69.5    kube-worker01   <none>           <none>
rook-ceph-osd-prepare-kube-worker01-l7pkg                 0/1     Completed   0          3h51m   10.233.69.13   kube-worker01   <none>           <none>
rook-ceph-osd-prepare-kube-worker02-dxx2c                 0/1     Completed   0          3h51m   10.233.68.24   kube-worker02   <none>           <none>
rook-ceph-osd-prepare-kube-worker03-2779b                 0/1     Completed   0          3h51m   10.233.70.18   kube-worker03   <none>           <none>
rook-ceph-osd-prepare-kube-worker04-vdd5w                 0/1     Completed   0          3h51m   10.233.67.23   kube-worker04   <none>           <none>

Ceph Clusterの状態を確認するため、以下のコマンドで確認します。MESSAGEが、Cluster created successfully となっており、HEALTHが HEALTH_OK となっていれば問題ありません。

$ kubectl -n rook-ceph get cephcluster
NAME        DATADIRHOSTPATH   MONCOUNT   AGE   PHASE   MESSAGE                        HEALTH        EXTERNAL
rook-ceph   /var/lib/rook     3          39h   Ready   Cluster created successfully   HEALTH_OK

toolboxを使って、Ceph Clusterの状態を確認しておきます。healthが HEALTH_OK となっていることが分かります。また、monのデーモンが3つ起動し、mgrが2つあり、osdが4つ起動していることが分かります。

$ kubectl apply -f toolbox.yaml
$ kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash
bash-4.4$ ceph status
  cluster:
    id:     13a113cd-9060-4f1a-9fef-44d1bfe4fe26
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum a,b,c (age 13h)
    mgr: b(active, since 13h), standbys: a
    osd: 4 osds: 4 up (since 13h), 4 in (since 13h)
 
  data:
    pools:   1 pools, 1 pgs
    objects: 2 objects, 449 KiB
    usage:   45 MiB used, 400 GiB / 400 GiB avail
    pgs:     1 active+clea

Rookのインストールの補足

特定ノードや特定デバイスにインストールをしたい場合に、cluster.yamlで以下のパラメータの設定を行います。

今回は、masterノードとworkerノードはKubesprayでデプロイする際に指定を行っており、workerノードはsdbがRaw Deviceとなっており、すべて同じ構成となっているためデフォルト値のまま利用しています。デフォルト値のままで、workerノードのsdbだけが利用されるようになります。

$ vi cluster.yaml
spec:
  storage: 
    useAllNodes: true
    useAllDevices: true
    # nodes:
    #   - name: "172.17.4.201"
    #     devices: # specific devices to use for storage can be specified for each node
    #       - name: "sdb"

Cephストレージクラスタを構成する場合は、システム要件として以下の少なくても一つの構成が必要となっています。

* Raw devices (no partitions or formatted filesystems)
* Raw partitions (no formatted filesystem)
* LVM Logical Volumes (no formatted filesystem)
* Persistent Volumes available from a storage class in block mode

仮想マシンにハード ディスク 2を接続し、OS内で特に設定はせずに、OSでデバイスが認識できていればシステム要件は満たせそうでした。

workerノードの状態の確認

Rookをインストール後のworkerノードの状態を確認しておきます。

Disk2として接続した sdb がceph_bluestoreとしてフォーマットされていることが分かります。Raw deviceの場合、自動的にceph_bluestoreが選択されるようです。

$ lsblk -f
NAME                FSTYPE         FSVER    LABEL UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
loop0               squashfs       4.0                                                         0   100% /snap/lxd/23541
loop1               squashfs       4.0                                                         0   100% /snap/core20/1778
loop2               squashfs       4.0                                                         0   100% /snap/snapd/17883
loop3               squashfs       4.0                                                         0   100% /snap/core20/1738
loop4               squashfs       4.0                                                         0   100% /snap/lxd/22923
loop5               squashfs       4.0                                                         0   100% /snap/snapd/17950
sda                                                                                                     
├─sda1                                                                                                  
├─sda2              ext4           1.0            a2ece314-f49d-4c09-ad59-6f90402eb8e6      1.3G    14% /boot
└─sda3              LVM2_member    LVM2 001       nv6J0B-VyPL-K1x1-Rfti-oHC0-94RQ-DQ3tex                
  └─ubuntu--vg-ubuntu--lv
                    ext4           1.0            2bcaf132-16b8-4b64-9e35-f200b40dfbf9     80.6G    12% /
sdb                 ceph_bluestore

StorageClassのデプロイ

ブロックストレージ(RDB)のStorageClassとCephBlockPoolをデプロイします。

$ cd deploy/examples
$ kubectl create -f csi/rbd/storageclass.yaml

Wordpressによる動作確認

Wordpress をデプロイし、動作確認を行います。

$ kubectl create -f mysql.yaml
$ kubectl create -f wordpress.yaml

WordpressWordpress用のMySQLのpodが起動していることを確認します。

$ kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
wordpress-7cf5c5c8b-lbjln          1/1     Running   0          2m9s
wordpress-mysql-6f99c59595-djvm9   1/1     Running   0          2m15s

Wordpressのサービスを確認すると、 type: LoadBalancer でMetalLBからIPアドレスが付与されていることが分かります。

$ kubectl get svc wordpress
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
wordpress   LoadBalancer   10.233.38.114   10.0.50.203   80:30242/TCP   19h

ブラウザから http://10.0.50.203/ にアクセスし、Wordpressの初期設定が画面が表示されることを確認します。

PVとPVCが作成されていることを確認します。

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS      REASON   AGE
pvc-32b6f27b-5d03-4ed8-9478-82cf64ed73f1   20Gi       RWO            Delete           Bound    default/mysql-pv-claim   rook-ceph-block            19h
pvc-bcfab821-a7f8-4df0-8788-0144e06f2435   20Gi       RWO            Delete           Bound    default/wp-pv-claim      rook-ceph-block            19h
$ kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
mysql-pv-claim   Bound    pvc-32b6f27b-5d03-4ed8-9478-82cf64ed73f1   20Gi       RWO            rook-ceph-block   19h
wp-pv-claim      Bound    pvc-bcfab821-a7f8-4df0-8788-0144e06f2435   20Gi       RWO            rook-ceph-block   19h

toolboxからceph statusを確認し、objectsやusageが増えていることを確認します。

bash-4.4$ ceph status
  cluster:
    id:     13a113cd-9060-4f1a-9fef-44d1bfe4fe26
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum a,b,c (age 14h)
    mgr: b(active, since 14h), standbys: a
    osd: 4 osds: 4 up (since 14h), 4 in (since 14h)
 
  data:
    pools:   2 pools, 33 pgs
    objects: 118 objects, 275 MiB
    usage:   816 MiB used, 399 GiB / 400 GiB avail
    pgs:     33 active+clean
 
  io:
    client:   2.0 KiB/s wr, 0 op/s rd, 0 op/s wr

リソースの削除

動作確認ができたため、リソースを削除しておきます。

$ kubectl delete -f wordpress.yaml
$ kubectl delete -f mysql.yaml

発生した事象について

上記の記載を見ると、特に通常の手順で簡単にインストールできそうに見えますが、いくつかはまりました。

KubesprayのデフォルトのCNIはcalicoですが、この状態でRookをインストールすると、Configuring Ceph Monsのメッセージのまま、monの起動でとまってしまい、インストールが正常に完了しませんでした。

$ kubectl -n rook-ceph get cephcluster
NAME        DATADIRHOSTPATH   MONCOUNT   AGE     PHASE         MESSAGE                 HEALTH   EXTERNAL
rook-ceph   /var/lib/rook     3          2m54s   Progressing   Configuring Ceph Mons

rook-ceph-operatorのログには、op-mon: mons running: [a]が表示され続ける状態となりました。

$ kubectl -n rook-ceph logs -l app=rook-ceph-operator -f
2023-01-18 21:40:56.423974 I | op-mon: waiting for mon quorum with [a]
2023-01-18 21:40:56.703448 I | op-mon: mons running: [a]
2023-01-18 21:41:17.104072 I | op-mon: mons running: [a]
2023-01-18 21:41:37.314370 I | op-mon: mons running: [a]
2023-01-18 21:41:57.519969 I | op-mon: mons running: [a]
2023-01-18 21:42:17.716778 I | op-mon: mons running: [a]
2023-01-18 21:42:37.944062 I | op-mon: mons running: [a]
2023-01-18 21:42:58.128773 I | op-mon: mons running: [a]
2023-01-18 21:43:18.339845 I | op-mon: mons running: [a]
2023-01-18 21:43:38.572259 I | op-mon: mons running: [a]

ログの出力として、他に異常はなく、何が起きているか確認できない状態でしたが、monの数を1に変更した場合に処理が通過することがあり、rook-ceph-operatorとmonのpod間の通信に問題がありそうということが見えていました。

また、以下のissueにも同様の事象が報告されており、calicoからflannelに変更することで事象が改善したとありました。

Mons not forming quorum · Issue #7769 · rook/rook · GitHub

こちらのissueでも議論されており、Rookとcalicoの組み合わせといったKubernetesのツール間での組み合わせ問題がありそうです。

Rook Ceph Mons unable to form quorum when using Calico CNI · Issue #5065 · rook/rook · GitHub

参考