TopoLVMによるPVC-basedなRook/Ceph with Pod Topology Spread Constraints
はじめに
2020/07/03にJapan Rook Meetup #3 - connpassにて「ML環境でのRook/Ceph」と題してお話させていただきました.
話の中でCSIにTopoLVMを使用したOSDs on PVCs環境を用いたデモを行ったのですが,その際使用した環境を構築した手順を残しておきます. また,本記事で紹介する構築はシングルマスター構成K8sクラスタですが,マスター冗長構成K8sクラスタにおいても同様の方法で構築することができます.
前提条件
スライド中にも記載しているのですが,以下の環境で構築します. パブリッククラウドを用いた環境ではないためパブリッククラウドを使用される際はご注意ください.
TopoLVMの導入
はじめにTopoLVMについて軽く紹介した後に実際に構築していきます.
TopoLVMとは
Kubernetes(以下K8s)でストレージを扱う際,マネージドK8sサービスではCSIドライバが用意されており,K8sでのダイナミックプロビジョニングなど非常に容易に行えるようになっています.(例えばEKSのAmazon EBS CSIドライバー)しかしながらベアメタルサーバなどの,特にローカルストレージを束ねてK8sのストレージとして使用しようとすると何らかのCSIドライバを用意してあげなくてはいけません.
TopoLVMではPVCが発行されるとLinuxのLogical Volumeの仕組みを利用し,TopoLVM用のK8s拡張スケジューラによって適切にPVを作成する Nodeを選択しLogical VolumeのVGからLVを切り出してダイナミックプロビジョニングしてくれます.
PVC-basedなRook/Cephを使う場合hostpathを利用して手動でPVを作成することも可能ですが,今回はTopoLVMをCSIドライバとして使用することでダイナミックプロビジョニングを可能にします.
より詳しいTopoLVMのアーキテクチャなどについてはTopoLVMを作成しているサイボウズさんのブログに詳しくまとめられているのでそちらをご覧ください.
TopoLVM準備
基本的に以下の公式ドキュメントに則って構築していきますので適宜参照してください.またこの節で行う工程はストレージを使用する全てのNodeで必須です.
まずはじめに使用ポートを開放します.
$ sudo ufw allow 9251
次にlvm2をインストールし,volume groupを作成していきます. 今回volume groupに使用する物理デバイス名は「/dev/disk/by-id/」を参照させます.物理デバイス名は各環境に合わせて以下作業を行ってください.
$ sudo apt install -y lvm2 $ sudo vgcreate myvg scsi-360022480166e76746b201caa42ba7db7 \ scsi-3600224804f19c35d51d9ec43cb37351a
上記ではvg名をmyvgとしていますが,任意の名前を使用可能です.
次にsystemdとしてlvmdを動かしていきます. 事前に以下からlvmdのビルド済みファイルをダウンロードして おいてください.本記事では執筆時点で最新版のv0.5.0を使用していきます.
次に以下からlvmd.serviceをダウンロードしてきてください.
ダウンロードできたら配置し,起動していきます.
$ sudo mkdir /opt/sbin $ mv lvmd /opt/sbin/lvmd $ mv lvmd.service /etc/systemd/system/lvmd.service $ sudo systemctl start lvmd
topolvm-schedulerの導入
topolvmではkube-schedulerを拡張するscheduler-extenderを使用しています.本節ではkubeadmを使用してK8sクラスタを構築する前提でtopolvm-schedulerの準備をしていきます.
まずはじめに使用するファイルを以下からダウンロードしてきてください.
次にダウンロードしてきたフォルダの「deploy/scheduler-config/scheduler-donfig.yaml」「deploy/scheduler-config/scheduler-policy.cfg」を以下のように配置します.
$ mkdir /etc/kubernetes/topolvm/ $ mv deploy/scheduler-config/* /etc/kubernetes/topolvm/
K8sクラスタの構築
共通事前準備
ポートを開放していきます.
- control plane node
$ sudo ufw allow 53 &&\ sudo ufw allow 6443-6444 &&\ sudo ufw allow 6789 &&\ sudo ufw allow 2379:2380/tcp &&\ sudo ufw allow 8285 &&\ sudo ufw allow 8472 &&\ sudo ufw allow 9153 &&\ sudo ufw allow 10000 &&\ sudo ufw allow 10250:10252/tcp &&\ sudo ufw allow 31416
- node
$ sudo ufw allow 53 &&\ sudo ufw allow 6444 &&\ sudo ufw allow 8225 &&\ sudo ufw allow 8472 &&\ sudo ufw allow 9153 &&\ sudo ufw allow 10000 &&\ sudo ufw allow 10250 &&\ sudo ufw allow 30000:32767/tcp &&\ sudo ufw allow 31416
Control Plane Node
まずはじめに以下のようなkubeadm-configファイル「kubeadm_config.yaml」を作成してtopolvm-schedulerを使用できるK8sクラスタを構築していきます.
apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: v1.18.3 scheduler: extraVolumes: - name: "config" hostPath: /etc/kubernetes/topolvm/ mountPath: /var/lib/scheduler readOnly: true extraArgs: config: /var/lib/scheduler/scheduler-config.yaml networking: podSubnet: "10.244.0.0/16"
上記のkubeadm-configファイルはCNIとしてflannelを使用する前提ですので,他のCNIを使用する場合は適宜変更してください.
作成したkubeadm-configを使用してK8sクラスタを構築します.
$ kubeadm init --upload-certs --config=/etc/kubeadm/kubeadm_config.yaml $ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
CNIをデプロイします.
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Node
kubeadm initの最後に出力されたトークンを使用してK8sクラスタに参加させます.
$ kubeadm join xxx.xxx.xxx.xxx:6443 --token hogehoge \ > --discovery-token-ca-cert-hash sha256:hogehoge
topolvmのデプロイ
事前準備
次節からではhelm3とkustmizeを使用してアプリケーションをデプロイしていくため事前準備としてhelm3とkustmizeをインストールしていきます.既にインストール済みの方は飛ばしていただいて大丈夫です.
helm3
ubuntu環境では以下のドキュメントにしたがってインストールしていきます.
curl https://helm.baltorepo.com/organization/signing.asc | sudo apt-key add - $ sudo apt-get install apt-transport-https --yes $ echo "deb https://baltocdn.com/helm/stable/debian/ all main" | \ sudo tee /etc/apt/sources.list.d/helm-stable-debian.list $ sudo apt-get update $ sudo apt-get install helm
kustomize
以下の公式Githubから最新のバイナリファイルをダウンロードしてきてください. 本記事ではv3.6.1を使用しています.
ダウンロードしたら,実行権限を与えて配置します.
$ tar -vfxz kustomize_v3.8.0_linux_amd64.tar.gz $ chmod -x kustomize_v3.8.0_linux_amd64 $ mv kustomize_v3.8.0_linux_amd64 /usr/local/bin/kustomize
デプロイ
まずはじめにtopolvmm-controllerが使用する自己証明書発行のためにcert-managerをデプロイします.
今回はhelm3を使用してデプロイしていきます.
$ helm repo add jetstack https://charts.jetstack.io $ kubectl create namespace cert-manager $ helm install cert-manager --namespace cert-manager jetstack/cert-manager \ --values $HOME/K8s_manifest/certmanager/values.yaml --version v0.15.1
次にkustomizeを用いてTopoLVMをデプロイしていきます. マニフェストは topolvm-schedulerの導入でダウンロードしてきた「topolvm/deplot/manifest/」を使用していきます.
$ kubectl label ns kube-system topolvm.cybozu.com/webhook=ignore $ kustomize build topolvm/deploy/manifest/overlays/daemonset-scheduler | kubectl apply -f -
次に,node Podが全て正常に起動したことを確認した後に,以下を実行します.
$ kubectl get po -n topolvm-system -l app.kubernetes.io/name=node NAME READY STATUS RESTARTS AGE node-b6r52 3/3 Running 0 6h1m node-d9dm4 3/3 Running 0 6h33m node-g7d92 3/3 Running 0 5h58m node-kk5wv 3/3 Running 0 6h33m node-qttzx 3/3 Running 0 6h33m node-w9nbc 3/3 Running 0 6h5m $ $ kubectl apply -f topolvm/deploy/manifest/base/certificates.yaml $ $ kubectl get po -n topolvm-system NAME READY STATUS RESTARTS AGE controller-6457d85455-8ks5k 5/5 Running 0 6h34m controller-6457d85455-9tqhf 5/5 Running 0 6h34m node-b6r52 3/3 Running 0 6h2m node-d9dm4 3/3 Running 0 6h34m node-g7d92 3/3 Running 0 5h59m node-kk5wv 3/3 Running 0 6h34m node-qttzx 3/3 Running 0 6h34m node-w9nbc 3/3 Running 0 6h6m topolvm-scheduler-4qvwm 1/1 Running 0 6h34m
以上でTopoLVMの準備は完了です.
Rook/Cephのデプロイ
事前準備
まずはじめに各Nodeにrackをラベルとして与えます. 「vm-w0」のようなところは適切なホスト名に置き換えてください.
$ kubectl label node vm-w0 topology.rook.io/rack=rackA $ kubectl label node vm-w1 topology.rook.io/rack=rackA $ kubectl label node vm-w2 topology.rook.io/rack=rackB $ kubectl label node vm-w3 topology.rook.io/rack=rackB $ kubectl label node vm-w4 topology.rook.io/rack=rackC $ kubectl label node vm-w5 topology.rook.io/rack=rackC
デプロイ
「common.yaml」「operator.yaml」をデプロイしていきます. ここは通常のHOST-basedパターンと同様です.
$ deploy K8s_manifest/rook-1.3.5/cluster/examples/kubernetes/ceph/common.yaml $ kubectl apply -f K8s_manifest/rook-1.3.5/cluster/examples/kubernetes/ceph/operator.yaml
次に「cluster-on-pvc.yaml」を以下のように書き換えます. 以下のマニフェストでは発表資料と同様に10GBのOSDを12個作成する構成になっています. またPodTopologySpreadConstaraintsにより,rack障害耐性,rack内node障害耐性を持たせた構成になっています. 注意点として必ず2箇所のstorageClassNameの指定はtopolvm-provisionerにしてください.
apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: name: rook-ceph namespace: rook-ceph spec: dataDirHostPath: /var/lib/rook mon: count: 3 allowMultiplePerNode: false volumeClaimTemplate: spec: storageClassName: topolvm-provisioner resources: requests: storage: 3Gi cephVersion: image: ceph/ceph:v14.2.9 allowUnsupported: false skipUpgradeChecks: false continueUpgradeAfterChecksEvenIfNotHealthy: false mgr: modules: - name: pg_autoscaler enabled: true dashboard: enabled: true ssl: true crashCollector: disable: false storage: storageClassDeviceSets: - name: topolvm-ssd-cluster count: 12 portable: false tuneSlowDeviceClass: true placement: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - rook-ceph-osd - key: app operator: In values: - rook-ceph-osd-prepare topologyKey: kubernetes.io/hostname topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.rook.io/rack whenUnsatisfiable: DoNotSchedule labelSelector: matchExpressions: - key: app operator: In values: - rook-ceph-osd - rook-ceph-osd-prepare - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule # whenUnsatisfiable: ScheduleAnyway labelSelector: matchExpressions: - key: app operator: In values: - rook-ceph-osd - rook-ceph-osd-prepare resources: volumeClaimTemplates: - metadata: name: data spec: resources: requests: storage: 10Gi storageClassName: topolvm-provisioner volumeMode: Block accessModes: - ReadWriteOnce disruptionManagement: managePodBudgets: false osdMaintenanceTimeout: 30 manageMachineDisruptionBudgets: false machineDisruptionBudgetNamespace: openshift-machine-api
CephFSのデプロイ
最後にCephFSもrack障害耐性,rack内node障害耐性を持たせてデプロイします.
以下のように「filesystem.yaml」を設定してください.
apiVersion: ceph.rook.io/v1 kind: CephFilesystem metadata: name: tenzenfs namespace: rook-ceph spec: metadataPool: failureDomain: rack replicated: size: 3 requireSafeReplicaSize: true dataPools: - failureDomain: rack replicated: size: 3 requireSafeReplicaSize: true compressionMode: none preservePoolsOnDelete: true metadataServer: activeCount: 1 activeStandby: true placement: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - rook-ceph-mds topologyKey: kubernetes.io/hostname preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - rook-ceph-mds topologyKey: topology.rook.io/rack annotations: resources:
デプロイしていきます.
$ kubectl apply -f filesystem.yaml
以上でjapan rook meetup #3 Hands onで使用した環境が出来上がります.
おわりに
今回はmeetupで使用した環境について紹介しました. 参考になれば幸いです.