Rook-CephのCephFSを使ってWordpress環境の構築をする

こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

今回は前回なんとなく試してみたCephFSをもう少しだけそれっぽく、具体的にはWordpressのデータをCephFSに保存するような環境を構築していきたいと思います。

Rook-Cephの環境構築及び前回の記事は以下となりますので、別途参考にしていただければと思います。

https://qiita.com/ohtsuka-shota/items/cc45d595f742f3625099

https://qiita.com/ohtsuka-shota/items/52f86c8cf53a29bc389f

# 環境イメージ
今回構築する環境イメージは以下となります。
4台構成のk8sクラスタ上にRook-Ceph環境をデプロイしており、その環境上にさらにWordpressとMySQL podを1台ずつ。NodePortとClusterIPを1つずつデプロイしていきます。MySQL podとPVC/SCを関連付けることでMySQLのデータをCephFS上に保存し永続化するようにしています。WordpressとMySQLはClusterIPを使うことでコネクションを確立しています。

![ceph-ページ9.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/a099e5a5-159f-f6ba-c2e5-cdf4d6d479c6.png)

# 構築
## CephFSのデプロイ
今回使用するCephFSをデプロイするためのyamlを以下に用意しました。
特に拘りがなければmetadata.nameあたりを気を付ければいいと思います。今回はwpfsという名前のCephFSを作成したいと思います。
```filesystem.yaml
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が作成されていることがわかります。
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/169e4476-bc03-546c-eebe-25fd942eb9e8.png)

metadata poolとdata poolについて理解をするのであれば公式サイトくらいしか参考にならないかと思いますが、CephFSのページだけでは理解まで至れないと思います。Cephの全体感を俯瞰することで理解もしやすくなるかと思います。

https://docs.ceph.com/en/quincy/cephfs/

https://www.youtube.com/watch?v=ZiAorJ-c2k4&t=1464s&pp=ygUEY2VwaA%3D%3D

ここでの操作で、イメージでは以下の部分のデプロイが完了したことになります。

![ceph-ページ9のコピー.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/6af77687-bf06-79f1-fced-ff4152626a6f.png)


## StorageClassとPVCのデプロイとバグの回避策
それぞれのyamlファイルを以下に示します。
```mysql-storageclass.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:
```
```mysql-pvc.yaml
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 をすべて削除して再作成することで修正しました。」とのこと。

https://github.com/rook/rook/issues/4012

試してみます。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
```

ここまでで以下の部分まで作成したこととなります。
![ceph-ページ9のコピー.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/91c96167-6c6b-581c-3c10-91086e94e03a.png)

## Wordpress/MySQLのpod,serviceをデプロイ
用意したyamlは以下となります。今回はConfigMapやSecret等を使わずに環境変数を設定していきます。MySQLのpodに対してどのPVCを使うのかが気を付けるポイントでしょうか。
```wordpress-pod.yaml
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
```
```wordpress-nodeport.yaml
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
```
```mysql-pod.yaml
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
```
```mysql-clusterip.yaml
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的なエラーが見えてしまうかもしれませんが、少し待つと以下のような見慣れた画面が表示されると思います。
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/fb5aa805-8f53-b97c-c960-7982cbf4d8dd.png)
適当に設定をして、以下のような環境を用意できました。
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/69104240-e9a6-2714-f805-8fd95cd75c48.png)

## 検証
いつも通り、データの永続化ができているかを確認してみます。今回の場合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
```

改めてWordpressに接続すると、先ほどと同じ画面が表示されているはずです。
![image (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/52b5a5c3-7d1d-afa2-2de0-ef89d2311bfc.png)