こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
今回は前回なんとなく試してみたCephFSをもう少しだけそれっぽく、具体的にはWordpressのデータをCephFSに保存するような環境を構築していきたいと思います。
Rook-Cephの環境構築及び前回の記事は以下となりますので、別途参考にしていただければと思います。
環境イメージ
今回構築する環境イメージは以下となります。
4台構成のk8sクラスタ上にRook-Ceph環境をデプロイしており、その環境上にさらにWordpressとMySQL podを1台ずつ。NodePortとClusterIPを1つずつデプロイしていきます。MySQL podとPVC/SCを関連付けることでMySQLのデータをCephFS上に保存し永続化するようにしています。WordpressとMySQLはClusterIPを使うことでコネクションを確立しています。
構築
CephFSのデプロイ
今回使用するCephFSをデプロイするためのyamlを以下に用意しました。
特に拘りがなければmetadata.nameあたりを気を付ければいいと思います。今回はwpfsという名前のCephFSを作成したいと思います。
apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
name: wpfs
namespace: rook-ceph
spec:
metadataPool:
replicated:
size: 3
requireSafeReplicaSize: true
parameters:
compression_mode:
none
dataPools:
- name: replicated
failureDomain: host
replicated:
size: 3
requireSafeReplicaSize: true
parameters:
compression_mode:
none
preserveFilesystemOnDelete: 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.kubernetes.io/zone
annotations:
labels:
resources:
これをベースにデプロイしていきます。
root@rancher:~/wordpress# kubectl apply -f filesystem.yaml
cephfilesystem.ceph.rook.io/wpfs created
CephのWebコンソールのFileSystemを確認するとwpfsというものが表示されていると思います。
Poolが2つ出来ていることを確認しましょう。2つの内訳としてmetadata poolとdata poolとなっているのですが、CephFSを利用するには、この2つのpoolが存在していることが必須となります。
今回はwpfs-metadataというmetadata poolとwpfs-replicatedというdate poolが作成されていることがわかります。
metadata poolとdata poolについて理解をするのであれば公式サイトくらいしか参考にならないかと思いますが、CephFSのページだけでは理解まで至れないと思います。Cephの全体感を俯瞰することで理解もしやすくなるかと思います。
ここでの操作で、イメージでは以下の部分のデプロイが完了したことになります。
StorageClassとPVCのデプロイとバグの回避策
それぞれのyamlファイルを以下に示します。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: wp-rook-cephfs
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
clusterID: rook-ceph
fsName: wpfs
pool: wpfs-replicated
csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wp-cephfs-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: wp-rook-cephfs
これらをデプロイしていきます。
PVCデプロイ後、ステータスを確認してみてください。私の環境だとなぜかPending状態が頻発していました。
root@rancher:~/wordpress# kubectl apply -f mysql-storageclass.yaml
storageclass.storage.k8s.io/wp-rook-cephfs created
root@rancher:~/wordpress# kubectl apply -f mysql-pvc.yaml
persistentvolumeclaim/wp-cephfs-pvc created
root@rancher:~/wordpress# kubectl get pv,pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/wp-cephfs-pvc Pending wp-rook-cephfs 2m38s
PVCとSCをdescribeして詳細を確認してみます。SCは問題なさそうなのですがPVCだけおかしいです。
root@rancher:~/wordpress# kubectl describe pvc wp-cephfs-pvc
Name: wp-cephfs-pvc
Namespace: default
StorageClass: wp-rook-cephfs
Status: Pending
Volume:
Labels: <none>
Annotations: volume.beta.kubernetes.io/storage-provisioner: rook-ceph.cephfs.csi.ceph.com
volume.kubernetes.io/storage-provisioner: rook-ceph.cephfs.csi.ceph.com
Finalizers: [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode: Filesystem
Used By: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 56s (x10 over 5m12s) rook-ceph.cephfs.csi.ceph.com_csi-cephfsplugin-provisioner-d7f599b4b-pznmj_268a59f4-34ed-4e79-8328-de5e8208f6ce External provisioner is provisioning volume for claim "default/wp-cephfs-pvc"
Warning ProvisioningFailed 56s (x10 over 5m12s) rook-ceph.cephfs.csi.ceph.com_csi-cephfsplugin-provisioner-d7f599b4b-pznmj_268a59f4-34ed-4e79-8328-de5e8208f6ce failed to provision volume with StorageClass "wp-rook-cephfs": rpc error: code = Internal desc = rados: ret=-2, No such file or directory: "subvolume group 'csi' does not exist"
Normal ExternalProvisioning 14s (x22 over 5m12s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "rook-ceph.cephfs.csi.ceph.com" or manually created by system administrator
root@rancher:~/wordpress# kubectl describe sc wp-rook-cephfs
Name: wp-rook-cephfs
IsDefaultClass: No
Annotations: kubectl.kubernetes.io/last-applied-configuration={"allowVolumeExpansion":true,"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"wp-rook-cephfs"},"mountOptions":null,"parameters":{"clusterID":"rook-ceph","csi.storage.k8s.io/controller-expand-secret-name":"rook-csi-cephfs-provisioner","csi.storage.k8s.io/controller-expand-secret-namespace":"rook-ceph","csi.storage.k8s.io/node-stage-secret-name":"rook-csi-cephfs-node","csi.storage.k8s.io/node-stage-secret-namespace":"rook-ceph","csi.storage.k8s.io/provisioner-secret-name":"rook-csi-cephfs-provisioner","csi.storage.k8s.io/provisioner-secret-namespace":"rook-ceph","fsName":"wpfs","pool":"wpfs-replicated"},"provisioner":"rook-ceph.cephfs.csi.ceph.com","reclaimPolicy":"Retain"}
Provisioner: rook-ceph.cephfs.csi.ceph.com
Parameters: clusterID=rook-ceph,csi.storage.k8s.io/controller-expand-secret-name=rook-csi-cephfs-provisioner,csi.storage.k8s.io/controller-expand-secret-namespace=rook-ceph,csi.storage.k8s.io/node-stage-secret-name=rook-csi-cephfs-node,csi.storage.k8s.io/node-stage-secret-namespace=rook-ceph,csi.storage.k8s.io/provisioner-secret-name=rook-csi-cephfs-provisioner,csi.storage.k8s.io/provisioner-secret-namespace=rook-ceph,fsName=wpfs,pool=wpfs-replicated
AllowVolumeExpansion: True
MountOptions: <none>
ReclaimPolicy: Retain
VolumeBindingMode: Immediate
Events: <none>
どうもこれはバグの一種のようで、以下のサイトにそのような記載があります。
解決策としては「csi-cephfsplugin-provisioner をすべて削除して再作成することで修正しました。」とのこと。
試してみます。csi-cephfsplugin-provisionerはRSのpodになるため、deleteをしてもk8sがそれを検知して新しいpodをすぐにデプロイしてくれます。心置きなくdeleteしましょう。
root@rancher:~/rook/deploy/examples/csi/cephfs# kubectl get pod -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-dmq86 3/3 Running 0 7d9h
csi-cephfsplugin-ffswq 3/3 Running 0 7d9h
csi-cephfsplugin-lpqx7 3/3 Running 0 7d9h
csi-cephfsplugin-provisioner-d7f599b4b-k69jk 6/6 Running 0 7d9h
csi-cephfsplugin-provisioner-d7f599b4b-pznmj 6/6 Running 0 7d9h
csi-rbdplugin-2bdph 3/3 Running 0 7d9h
csi-rbdplugin-4zvs5 3/3 Running 0 7d9h
csi-rbdplugin-cnrvp 3/3 Running 0 7d9h
csi-rbdplugin-provisioner-59f7df7cf8-h9xcd 6/6 Running 0 7d9h
csi-rbdplugin-provisioner-59f7df7cf8-k8t9r 6/6 Running 0 7d9h
rook-ceph-crashcollector-k8s-ceph01-5fc9bdbdb-kj6j5 1/1 Running 0 5d10h
rook-ceph-crashcollector-k8s-ceph02-747fff597-hpc8x 1/1 Running 0 34m
rook-ceph-crashcollector-k8s-ceph03-646858d5f4-mb9dv 1/1 Running 0 34m
rook-ceph-mds-wpfs-a-d9fdf9c78-9rtbq 1/1 Running 0 34m
rook-ceph-mds-wpfs-b-546b6f95f6-k7kwk 1/1 Running 0 34m
rook-ceph-mgr-a-755fcffc96-2rwvw 1/1 Running 7 (5d10h ago) 7d9h
rook-ceph-mon-a-6548ffb8b8-5q8bh 1/1 Running 0 7d9h
rook-ceph-mon-b-77c7b44765-jh664 1/1 Running 0 7d9h
rook-ceph-mon-c-78464899cf-7lv2r 1/1 Running 0 7d9h
rook-ceph-operator-7857749b84-bqvw5 1/1 Running 0 7d9h
rook-ceph-osd-0-b7bcd647d-7l89n 1/1 Running 1 (14h ago) 7d9h
rook-ceph-osd-1-5b99db5858-46bmv 1/1 Running 2 (18h ago) 7d9h
rook-ceph-osd-2-56566b85b-99q8w 1/1 Running 3 (25h ago) 7d9h
rook-ceph-osd-prepare-k8s-ceph01-tbnx5 0/1 Completed 0 5h21m
rook-ceph-osd-prepare-k8s-ceph02-pvfmj 0/1 Completed 0 5h21m
rook-ceph-osd-prepare-k8s-ceph03-rgrs4 0/1 Completed 0 5h21m
rook-ceph-tools-7c497bc7b8-qwch5 1/1 Running 0 7d9h
root@rancher:~/rook/deploy/examples/csi/cephfs# kubectl get rs -n rook-ceph
NAME DESIRED CURRENT READY AGE
csi-cephfsplugin-provisioner-d7f599b4b 2 2 2 7d9h
csi-rbdplugin-provisioner-59f7df7cf8 2 2 2 7d9h
rook-ceph-crashcollector-k8s-ceph01-5fc9bdbdb 1 1 1 7d9h
rook-ceph-crashcollector-k8s-ceph01-684c8fd5f6 0 0 0 5d11h
rook-ceph-crashcollector-k8s-ceph02-6f59667ccf 0 0 0 7d9h
rook-ceph-crashcollector-k8s-ceph02-747fff597 1 1 1 7d9h
rook-ceph-crashcollector-k8s-ceph03-646858d5f4 1 1 1 6d22h
rook-ceph-crashcollector-k8s-ceph03-6c45c95b44 0 0 0 7d9h
rook-ceph-mds-wpfs-a-d9fdf9c78 1 1 1 35m
rook-ceph-mds-wpfs-b-546b6f95f6 1 1 1 35m
rook-ceph-mgr-a-755fcffc96 1 1 1 7d9h
rook-ceph-mon-a-6548ffb8b8 1 1 1 7d9h
rook-ceph-mon-b-77c7b44765 1 1 1 7d9h
rook-ceph-mon-c-78464899cf 1 1 1 7d9h
rook-ceph-operator-7857749b84 1 1 1 7d10h
rook-ceph-osd-0-b7bcd647d 1 1 1 7d9h
rook-ceph-osd-1-5b99db5858 1 1 1 7d9h
rook-ceph-osd-2-56566b85b 1 1 1 7d9h
rook-ceph-tools-7c497bc7b8 1 1 1 7d9h
root@rancher:~/rook/deploy/examples/csi/cephfs# kubectl delete pod csi-cephfsplugin-provisioner-d7f599b4b-k69jk -n rook-ceph
pod "csi-cephfsplugin-provisioner-d7f599b4b-k69jk" deleted
root@rancher:~/rook/deploy/examples/csi/cephfs# kubectl delete pod csi-cephfsplugin-provisioner-d7f599b4b-pznmj -n rook-ceph
pod "csi-cephfsplugin-provisioner-d7f599b4b-pznmj" deleted
root@rancher:~/rook/deploy/examples/csi/cephfs# kubectl get pod -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-dmq86 3/3 Running 0 7d10h
csi-cephfsplugin-ffswq 3/3 Running 0 7d10h
csi-cephfsplugin-lpqx7 3/3 Running 0 7d10h
csi-cephfsplugin-provisioner-d7f599b4b-6chgt 6/6 Running 0 38s
csi-cephfsplugin-provisioner-d7f599b4b-cvkff 6/6 Running 0 20s
csi-rbdplugin-2bdph 3/3 Running 0 7d10h
csi-rbdplugin-4zvs5 3/3 Running 0 7d10h
csi-rbdplugin-cnrvp 3/3 Running 0 7d10h
csi-rbdplugin-provisioner-59f7df7cf8-h9xcd 6/6 Running 0 7d10h
csi-rbdplugin-provisioner-59f7df7cf8-k8t9r 6/6 Running 0 7d10h
rook-ceph-crashcollector-k8s-ceph01-5fc9bdbdb-kj6j5 1/1 Running 0 5d10h
rook-ceph-crashcollector-k8s-ceph02-747fff597-hpc8x 1/1 Running 0 37m
rook-ceph-crashcollector-k8s-ceph03-646858d5f4-mb9dv 1/1 Running 0 37m
rook-ceph-mds-wpfs-a-d9fdf9c78-9rtbq 1/1 Running 0 37m
rook-ceph-mds-wpfs-b-546b6f95f6-k7kwk 1/1 Running 0 37m
rook-ceph-mgr-a-755fcffc96-2rwvw 1/1 Running 7 (5d10h ago) 7d9h
rook-ceph-mon-a-6548ffb8b8-5q8bh 1/1 Running 0 7d10h
rook-ceph-mon-b-77c7b44765-jh664 1/1 Running 0 7d9h
rook-ceph-mon-c-78464899cf-7lv2r 1/1 Running 0 7d9h
rook-ceph-operator-7857749b84-bqvw5 1/1 Running 0 7d10h
rook-ceph-osd-0-b7bcd647d-7l89n 1/1 Running 1 (14h ago) 7d9h
rook-ceph-osd-1-5b99db5858-46bmv 1/1 Running 2 (18h ago) 7d9h
rook-ceph-osd-2-56566b85b-99q8w 1/1 Running 3 (26h ago) 7d9h
rook-ceph-osd-prepare-k8s-ceph01-tbnx5 0/1 Completed 0 5h24m
rook-ceph-osd-prepare-k8s-ceph02-pvfmj 0/1 Completed 0 5h24m
rook-ceph-osd-prepare-k8s-ceph03-rgrs4 0/1 Completed 0 5h24m
rook-ceph-tools-7c497bc7b8-qwch5 1/1 Running 0 7d9h
2,3分待つと、PVCのPendingが解消すると思います。
root@rancher:~/wordpress# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
wp-cephfs-pvc Bound pvc-191d2765-7d2e-45d1-a373-6bd5ed2b7a00 10Gi RWO wp-rook-cephfs 6m58s
Wordpress/MySQLのpod,serviceをデプロイ
用意したyamlは以下となります。今回はConfigMapやSecret等を使わずに環境変数を設定していきます。MySQLのpodに対してどのPVCを使うのかが気を付けるポイントでしょうか。
apiVersion: v1
kind: Pod
metadata:
name: wordpress-pod
labels:
app: wordpress
spec:
containers:
- name: wordpress-con
image: wordpress:php8.1-apache
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: mysql-clusterip
- name: WORDPRESS_DB_USER
value: devuser
- name: WORDPRESS_DB_PASSWORD
value: password
- name: WORDPRESS_DB_NAME
value: gke-wordpress-database
apiVersion: v1
kind: Service
metadata:
name: wordpress-nodeport
spec:
ports:
- name: port-1
port: 80
protocol: TCP
targetPort: 80
nodePort: 30080
selector:
app: wordpress
type: NodePort
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
labels:
app: mysql
spec:
containers:
- name: mysql-con
image: mysql:8.0-debian
ports:
- containerPort: 3306
env:
- name: MYSQL_USER
value: devuser
- name: MYSQL_PASSWORD
value: password
- name: MYSQL_ROOT_PASSWORD
value: password
- name: MYSQL_DATABASE
value: gke-wordpress-database
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql-vol-pvc
volumes:
- name: mysql-vol-pvc
persistentVolumeClaim:
claimName: wp-cephfs-pvc
apiVersion: v1
kind: Service
metadata:
name: mysql-clusterip
spec:
selector:
app: mysql
type: ClusterIP
ports:
- name: mysql
port: 3306
protocol: TCP
targetPort: 3306
これらをデプロイしていきます。
root@rancher:~/wordpress# kubectl apply -f mysql-pod.yaml
pod/mysql-pod created
root@rancher:~/wordpress# kubectl apply -f mysql-clusterip.yaml
service/mysql-clusterip created
root@rancher:~/wordpress# kubectl apply -f wordpress-pod.yaml
pod/wordpress-pod created
root@rancher:~/wordpress# kubectl apply -f wordpress-nodeport.yaml
service/wordpress-nodeport created
wordpressのNodePortは30080を指定しているので、それをURLに打ち込んで接続してみます。
もしかするとデプロイ直後ではDatabase Connection failed的なエラーが見えてしまうかもしれませんが、少し待つと以下のような見慣れた画面が表示されると思います。
適当に設定をして、以下のような環境を用意できました。
検証
いつも通り、データの永続化ができているかを確認してみます。今回の場合MySQLのpodではなくCephFSにデータが保存されているかを確認したいため、MySQL podをreplaceするような形で検証をしていきたいと思います。
以下がそのコマンドの実行結果となります。AGEが低くなっていることからdelete→createが走っていることがわかりますね。
root@rancher:~/wordpress# kubectl replace --force -f mysql-pod.yaml
pod "mysql-pod" deleted
pod/mysql-pod replaced
root@rancher:~/wordpress# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-pod 0/1 ContainerCreating 0 6s
wordpress-pod 1/1 Running 0 8m29s
root@rancher:~/wordpress# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-pod 1/1 Running 0 20s
wordpress-pod 1/1 Running 0 8m43s