はじめに
おうちのk8s環境でクラウド環境と同様なストレージサービスを利用したい(まだまだこれから勉強なのですが、とりあえず永続ボリュームがサクッとつくれないと不便だと思っている)ので、Rook Cephの環境を構築しました。
以下の記事には大変お世話になりました。わかってしまえば簡単なことも、自分は結構時間をとってしまったので、誰かのお役に立てればと思い、記事として残します。
TopoLVMによるPVC-basedなRook/Ceph with Pod Topology Spread Constraints
RancherでTopoLVMの動作環境を構築する方法
環境
ESXi6.7
-
vm
- k8s-master (cpu x2, mem 4GB,HDD System:30GB) x 1台
- k8s-node1~3(cpu x2, mem 4GB,HDD System:30GB Storage用:50GB) x 3台
- jumpserver x 1台 (Vagrant, kubespray作業用VM)
-
os
- k8s-master, k8s-node1~3 Ubuntu20.04LTS
- jumpserver:CentOS8.2.2004
k8s環境
TopoLVMを使用したRook Ceph
手順
VMの構築
ベースOSの選定
Ubuntuを使っている記事が多いので、無難にUbuntuにしました。
(VMのディスクサイズをカスタマイズしたかったので自前のboxを作りました)
一応、コマンドを記載しておきます。
OSの更新
apt-get update
apt-get upgrade -y
apt-get dist-upgrade -y
再起動
shutdown -r now
sshの設定
mkdir /home/vagrant/.ssh
chmod 700 /home/vagrant/.ssh
cd /home/vagrant/.ssh
curl -k -L -o authorized_keys 'https://github.com/hashicorp/vagrant/blob/master/keys/vagrant.pub'
chmod 600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant:vagrant /home/vagrant/.ssh
パスワードなしでsudo可の設定
visodo
以下の行を最終行に追加する
vagrant ALL=(ALL) NOPASSWD: ALL
sshdのUseDNSをnoにしてssh接続を高速化する
vi /etc/ssh/sshd_config
UseDNS no がコメント化されている行があるので先頭の#を外す
軽量化
apt-get clean
apt-get autoremove
export HISTSIZE=0
rm -f /home/vagrant/.bash_history
rm -f /root/.bash_history
rm -rf /var/log/*
rm -rf /tmp/*
dd if=/dev/zero of=/tmp/ZERO bs=1M
rm /tmp/ZERO
仮想マシンを停止
shutdown -h now
boxイメージの作成
以下の記事を参照して作成します。
→Vagrant box用イメージの作成
VangantでVM構築
VagrantでESXi上に新規にk8s構築用のVMを4台作成します(作業用のVMは別に用意してあります)。
Vagrant実行環境の準備
作業用のVMはCentOS8.2です(もともとあるものを流用)。
以下の手順でVagrant実行環境を準備します。
CentOS8.2にVagrantをインストール
VM構築
各Workerノードにシステムディスクとは別のディスク(50GB)を追加して構築します。
構築後、50GBのディスクが/dev/sdbとして見えることを前提としています。
以下のVagrantファイルを使用して構築しています。
Vagrantfile
config.yaml
vagrant multi sequenceで作成していて一気に構築できるはずなのですが、エラーになるので一個ずつ作成しています。
vagrantはあまり触ったことがないのでここは気にしないでおきます。。。
# /bin/bash
vagrant up k8s-master
vagrant up k8s-node1
vagrant up k8s-node2
vagrant up k8s-node3
kubesprayによるk8sの構築
kubespray実行環境のセットアップ
ここでは、jumpserverにkubesprayの実行環境を構築します。
事前設定
jumpserverのssh公開鍵を各workerノードのauthorized_keysにコピーします。
各workerノードにsshpassをインストールします。
これは、前述の「VM構築」で構築時に設定しました(Vagrantfile参照)。
jumpserverの設定
git clone https://github.com/kubernetes-sigs/kubespray.git
dnf install python38 -y
pip3 install --upgrade pip
cd kubespray
pip3 install -r requirements.txt
k8sの構築
設定
Inventory/Playbookの内容確認を確認し、書き換えます。
IPSの部分は作成するノードすべてのIPアドレスを記載します。
cp -rfp inventory/sample inventory/mycluster
declare -a IPS=(192.168.123.180 192.168.123.181 192.168.123.182 192.168.123.183)
CONFIG_FILE=inventory/mycluster/hosts.yml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
自動生成されたhosts.ymlファイルを以下のように編集します。
デフォルトでは、node1、node2、node3、node4のような名前がホスト名になってしまうため、わかりやすくするためです。
また、Control Plane 1台、Workerノード 3台になるように、設定を見直します。
etcdはControl Planeでのみ起動するようにします。
hosts.yml
all:
hosts:
k8s-master:
ansible_host: 192.168.123.180
ip: 192.168.123.180
access_ip: 192.168.123.180
k8s-node1:
ansible_host: 192.168.123.181
ip: 192.168.123.181
access_ip: 192.168.123.181
k8s-node2:
ansible_host: 192.168.123.182
ip: 192.168.123.182
access_ip: 192.168.123.182
k8s-node3:
ansible_host: 192.168.123.183
ip: 192.168.123.183
access_ip: 192.168.123.183
children:
kube-master:
hosts:
k8s-master:
kube-node:
hosts:
k8s-node1:
k8s-node2:
k8s-node3:
etcd:
hosts:
k8s-master:
k8s-cluster:
children:
kube-master:
kube-node:
calico-rr:
hosts: {}
構築
以下のコマンドを実行してk8s環境を構築します。
ansible-playbook -i inventory/mycluster/hosts.yml cluster.yml -b -v --private-key=~/.ssh/id_rsa
TopoLVMの設定
ここからは、kubectlが実行できる環境で実施します(k8s-masterで実施しました)。
TopoLVMのデプロイの手順と比較しながら見てもらえるとわかりやすいと思います。
TopoLVMのインストール
すべてのWorkerノードで以下のシェルを実行し、TopoLVMをインストールします。
(Vagrantファイル内からシェルを実行して一気に構築してしまってもよいかもしれません)
# !/bin/bash
# install TopoLVM ★2020/8/12時点でバージョンは0.5.3が最新
echo "TopoLVM install"
pvcreate /dev/sdb
vgcreate datagroup /dev/sdb
mkdir -p /root/lvmd
cd /root/lvmd
wget https://github.com/topolvm/topolvm/releases/download/v0.5.3/lvmd-0.5.3.tar.gz
tar zxvf lvmd-0.5.3.tar.gz
mkdir /opt/sbin
chown root:root lvmd
mv lvmd /opt/sbin/lvmd
git clone --single-branch --branch v0.5.3 https://github.com/topolvm/topolvm.git
sed -i -e 's/^\(\s*volume-group: \).*$/\1datagroup/g' ./topolvm/deploy/lvmd-config/lvmd.yaml
mkdir /etc/topolvm
cp -p ./topolvm/deploy/lvmd-config/lvmd.yaml /etc/topolvm/lvmd.yaml
cp -p ./topolvm/deploy/systemd/lvmd.service /etc/systemd/system/lvmd.service
systemctl enable --now lvmd
echo "TopoLVM installed"
TopoLVMのためのk8sの設定
k8sの設定
cert-managerのデプロイ
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.16.1/cert-manager.yaml
topolvm-system名前空間の作成
git clone --single-branch --branch v0.5.3 https://github.com/topolvm/topolvm.git
kubectl apply -f ./topolvm/deploy/manifests/base/namespace.yaml
topolvm-schedulerの設定ファイルの配備
mkdir -p /etc/kubernetes/topolvm/
cp -p ./topolvm/deploy/scheduler-config/* /etc/kubernetes/topolvm/
topolvm-schedulerの設定
今回は、DaemonSetとしてtopolvm-schedulerを動作させます。
(Deployment and Serviceを使用して動作させることも可能なようです。)
kubectlを実行するサーバ(例:Control plane)でソースをDLします。
dnf install git -y
git clone --single-branch --branch v0.5.3 https://github.com/topolvm/topolvm.git
使用するマニフェストは以下のファイルす。
topolvm/deploy/manifests/overlays/daemonset-scheduler/scheduler.yaml
変更するポイント
・hostNetwork: true
kube-scheduler がhostNetworkを使用していない場合は、hostNetworkの値を変更する必要があります。
わからなかったら以下のコマンドで確認します。
kubectl get pods -n kube-system
kubectl get pod kube-scheduler-xxxxxxx -n kube-system -o yaml
自分の環境では変更しません。
・key: node-role.kubernetes.io/master
control plane ノードに一致するラベルを指定する必要があります。
以下のコマンドを実行して上記ラベルが control planeノードに存在するか確認します。
存在しなければ値を変更する必要があります。
kubectl get node --show-labels
自分の環境では変更しません。
TopoLVM Webhookからシステム名前空間を保護
kubectl label ns kube-system topolvm.cybozu.com/webhook=ignore
TopoLVMのデプロイ
Kustomizeのインストール
公式ではKustomizeを使用してデプロイしているのでそれに従います。
→Kustomizeとは、kubernetesのYAML設定ファイルをパッケージングするツールです。
wget https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh
bash ./install_kustomize.sh
mv kustomize /usr/local/bin/kustomize
kustomizeを使用してTopoLVMをデプロイ
/usr/local/bin/kustomize build ./topolvm/deploy/manifests/overlays/daemonset-scheduler | kubectl apply -f -
node Podの起動を待つ
kubectl get pods -n topolvm-system -l app.kubernetes.io/name=node
cert-managerマニフェストを生成する
kubectl apply -f ./topolvm/deploy/manifests/base/certificates.yaml
TopoLVMのpodが起動していることを確認する
kubectl get pods -n topolvm-system --watch
kube-schedulerの設定
vi /etc/kubernetes/manifests/kube-scheduler.yaml
以下のように編集します。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-scheduler
tier: control-plane
name: kube-scheduler
namespace: kube-system
spec:
containers:
- command:
- kube-scheduler
- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
- --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
- --bind-address=0.0.0.0
- --kubeconfig=/etc/kubernetes/scheduler.conf
- --leader-elect=true
- --port=0
- --config=/var/lib/scheduler/scheduler-config.yaml #★追加
image: k8s.gcr.io/kube-scheduler:v1.18.6
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
path: /healthz
port: 10259
scheme: HTTPS
initialDelaySeconds: 15
timeoutSeconds: 15
name: kube-scheduler
resources:
requests:
cpu: 100m
volumeMounts:
- mountPath: /etc/kubernetes/scheduler.conf
name: kubeconfig
readOnly: true
- mountPath: /var/lib/scheduler #★追加
name: topolvm-config #★追加
readOnly: true #★追加
hostNetwork: true
priorityClassName: system-cluster-critical
volumes:
- hostPath:
path: /etc/kubernetes/scheduler.conf
type: FileOrCreate
name: kubeconfig
- hostPath: #★追加
path: /etc/kubernetes/topolvm #★追加
type: Directory #★追加
name: topolvm-config #★追加
status: {}
Rook/Cephのデプロイ
参考:https://tenzen.hatenablog.com/entry/2020/07/12/231235
https://qiita.com/MahoTakara/items/a1ed9811c790cd2a0d5f
事前準備
3つのworker nodeがそれぞれ別rackにあることを想定して、各ノードにrackをラベルとして与えます。
それぞれのノードにosd podが分散するように構築してきます。
kubectl label node k8s-node1 topology.rook.io/rack=rackA
kubectl label node k8s-node2 topology.rook.io/rack=rackB
kubectl label node k8s-node3 topology.rook.io/rack=rackC
common operator のデプロイ
「common.yaml」「operator.yaml」をデプロイします。
git clone --single-branch --branch release-1.4 https://github.com/rook/rook.git
Common Resources
kubectl create -f rook/cluster/examples/kubernetes/ceph/common.yaml
Operator
kubectl create -f rook/cluster/examples/kubernetes/ceph/operator.yaml
「cluster-on-pvc.yaml」の編集
OSDの数は6、rackおよびrack内のノードで分散配置するように設定しています。
(TopoLVMによるPVC-basedなRook/Ceph with Pod Topology Spread Constraints)の設定ほぼそのままです。
今回は、3rackかつ1ノード/rackで分散されるので各workerノードに2OSD podが起動することになります。
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:v15.2.4
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: 6
portable: false
tuneSlowDeviceClass: true
encrypted: false
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:
# rackで分散配置
- maxSkew: 1
topologyKey: topology.rook.io/rack
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- rook-ceph-osd
- rook-ceph-osd-prepare
# rack内のnodeで分散配置(今回はrack内にnode1台なので意味はない)
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
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
cluster-on-pvc のデプロイ
kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-vagrant/master/k8s-storage/cluster-on-pvc.yaml
CephFSのデプロイ
kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-vagrant/master/k8s-ubuntu/rook/filesystem.yaml
Rook toolboxのセットアップ
cephの状態を確認します。
kubectl apply -f ./rook/cluster/examples/kubernetes/ceph/toolbox.yaml
podの起動を確認する(STATUSがRunningになるのを待つ)
root@k8s-master:~# kubectl -n rook-ceph get pod -l "app=rook-ceph-tools"
NAME READY STATUS RESTARTS AGE
rook-ceph-tools-7d9467775-xm984 1/1 Running 0 63s
root@k8s-master:~#
ポッドに接続
root@k8s-master:~# kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
[root@rook-ceph-tools-7d9467775-xm984 /]#
ceph statusを実行します。
healthがHEALTH_OKになっていることが確認できます。
[root@rook-ceph-tools-7d9467775-xm984 /]# ceph status
cluster:
id: ed6cbc67-9813-439c-9111-d7d3ee19d1ca
health: HEALTH_OK
services:
mon: 3 daemons, quorum a,b,c (age 10m)
mgr: a(active, since 9m)
mds: yasubehefs:1 {0=yasubehefs-a=up:active} 1 up:standby-replay
osd: 6 osds: 6 up (since 9m), 6 in (since 9m)
task status:
scrub status:
mds.yasubehefs-a: idle
mds.yasubehefs-b: idle
data:
pools: 2 pools, 64 pgs
objects: 22 objects, 2.2 KiB
usage: 6.0 GiB used, 54 GiB / 60 GiB avail
pgs: 64 active+clean
io:
client: 1.2 KiB/s rd, 2 op/s rd, 0 op/s wr
[root@rook-ceph-tools-7d9467775-xm984 /]#
cephのダッシュボードにアクセスする
参考:ROOK Ceph のブロックストレージを検証したメモ
サービスがClusterIPになっているのでNodePortに変更してアクセスする。
kubectl patch service rook-ceph-mgr-dashboard -n rook-ceph -p '{"spec":{"type":"NodePort"}}'
ポート番号を確認します。
root@k8s-master:~# kubectl -n rook-ceph get service rook-ceph-mgr-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-ceph-mgr-dashboard NodePort 10.233.15.104 <none> 8443:32702/TCP 9h
root@k8s-master:~#
以下のURLでアクセスします。
https://192.168.123.181:32702/
ユーザ:admin
パスワードは以下で取得します。
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{['data']['password']}" | base64 --decode && echo
動作確認
ブロックストレージが使えるのか動作を確認してみます。
「RancherでTopoLVMの動作環境を構築する方法」ここのサンプルを借用させていただきました。
testpod.yaml
kind: PersistentVolumeClaim # PersistentVolumeClaimの作成
apiVersion: v1
metadata:
name: topolvm-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi # 1GiBのボリュームを作る
storageClassName: topolvm-provisioner # topoLVMから
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app.kubernetes.io/name: my-pod
spec:
containers:
- name: ubuntu
image: quay.io/cybozu/ubuntu:18.04
command: ["/usr/local/bin/pause"]
volumeMounts:
- mountPath: /test1 # /test1にマウントする
name: my-volume
volumes: # このボリュームを作って
- name: my-volume
persistentVolumeClaim:
claimName: topolvm-pvc
デプロイします。
root@k8s-master:~# kubectl apply -f testpod.yaml
persistentvolumeclaim/topolvm-pvc created
pod/my-pod created
root@k8s-master:~#
起動を確認します。
root@k8s-master:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-pod 1/1 Running 0 35m
root@k8s-master:~#
1Giのpvcが作られています。
root@k8s-master:~# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
topolvm-pvc Bound pvc-a16fa45e-2ae5-4d99-844c-5207767fe4e8 1Gi RWO topolvm-provisioner 43m
root@k8s-master:~#
cephのボリュームがPVで割り当たっています。
ceph自身もPVで作られています。
root@k8s-master:~# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-1a3d8280-a60a-4c48-9abc-d14b1b1d6600 3Gi RWO Delete Bound rook-ceph/rook-ceph-mon-b topolvm-provisioner 10h
pvc-2bdaa2ea-c38d-42cf-904f-ded8a482f975 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-4-5mvmj topolvm-provisioner 10h
pvc-313c2cee-86cc-415c-b707-e97e9c1f18c0 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-0-lfgqp topolvm-provisioner 10h
pvc-56510718-faef-4950-8c5e-2c3b5754b0fc 3Gi RWO Delete Bound rook-ceph/rook-ceph-mon-c topolvm-provisioner 10h
pvc-67cfbfd3-439d-4ab3-bcb2-e3a060d63038 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-2-xxdl5 topolvm-provisioner 10h
pvc-7feee616-eee7-497a-a8f7-85907cc40c80 3Gi RWO Delete Bound rook-ceph/rook-ceph-mon-a topolvm-provisioner 10h
pvc-866dc1a3-de63-4046-a120-a13bf1d73e6e 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-1-9v2bd topolvm-provisioner 10h
pvc-a16fa45e-2ae5-4d99-844c-5207767fe4e8 1Gi RWO Delete Bound default/topolvm-pvc topolvm-provisioner 44m
pvc-b89bef94-22f4-4a26-ace4-fbad54f2dccd 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-3-cchh6 topolvm-provisioner 10h
pvc-c1ac3bd5-90d9-4f1b-ad15-f0dc2a551a55 10Gi RWO Delete Bound rook-ceph/topolvm-ssd-cluster-data-5-qmzxk topolvm-provisioner 10h
root@k8s-master:~#
乗り込んで、期待通りか確認します。
/test1にマウントされてました。
kubectl exec -it my-pod bash
root@my-pod:/# mount | grep test1
/dev/topolvm/453c2052-eacc-4da1-b9b6-845ba1acd615 on /test1 type xfs (rw,relatime,lazytime,wsync,attr2,inode64,logbufs=8,logbsize=32k,noquota)
root@my-pod:/#
まとめ
おうち環境でも永続ボリュームが作れるようになりました。
kubesprayやKustomizeもただ使っているだけなので徐々に慣れていきたいです。
参考URL
TopoLVMによるPVC-basedなRook/Ceph with Pod Topology Spread Constraints
RancherでTopoLVMの動作環境を構築する方法
kubespray
Deploying TopoLVM