前回は、IngressでSSL/TLSを有効にする方法を試してみました。今回は、Rook Cephを使って分散ストレージのインストールを試してみました。
構成
- vCenter 7.0 U3
- ESXi 7.0 Update 3
- Ubuntu 22.04 (テンプレートVM)
- open-vm-tools 11.3.5
- cloud-init 22.2
- Kubespray
- kubernetes v1.25.5
- MetalLB v0.12.1
- ingress-nginx v1.5.1
- CoreDNS
- EdgeRouter X
- Rook Ceph v1.10.9
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をデプロイし、ストレージの運用(展開、ブートストラップ、構成、プロビジョニング、スケーリング、アップグレード、移行、災害復旧、監視、およびリソース管理)を自動化してくれるストレージオペレーターです。
Cephは、オブジェクト、ブロック、ファイル ストレージといった複数のインターフェースでアクセスできる分散オブジェクトストレージプラットフォームです。
Welcome to Ceph — Ceph Documentation
Cephは4つのコンポーネントから成り立っています。
- Ceph Monitor (ceph-mon)
- Ceph Manager (ceph-rgw)
- Ceph OSD (object storage daemon (ceph-osd))
- 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を試すにあたり、以前構築した手順から少し変更を加えます。
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
Wordpress とWordpress用の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