GKE上にWordpress環境作ってみる【vol.5 永続ボリュームをStorageClassでデプロイする！編】


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

私は今までにGKEにWordpress環境を少しずつ発展させる形で構築してきました。

https://qiita.com/ohtsuka-shota/items/48545c2b34bb251aa0e7

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

https://qiita.com/ohtsuka-shota/items/12a7f7a51e572f3da656

https://qiita.com/ohtsuka-shota/items/3d77d9e19075300ef2ef

今回は永続ボリュームデプロイ時にStorageClassを使用してみたいと思います。

# vol.4との比較

vol.4でも永続ボリュームを使用しましたが、その際にGCPのGCEにアクセスしWebコンソール上でポチポチしてストレージを用意しました。
検証用や、永続ボリュームを使用するpod等が少ない状態で有ればこれでも良いかもしれませんが、数が増えてくると地獄を見そうです。ヒューマンエラーも起こり得るでしょう。

<img width="821" alt="2023052107" src="https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/416357c7-8237-4e46-a157-fd83d8c0223a">

<img width="824" alt="2023052108" src="https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/95b81c84-f2af-436d-bb02-0f0ab04d97a6">

<img width="1122" alt="2023052109" src="https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/99e7f705-f18d-435c-8dfe-b46544255d4a">

k8sのStorageClassを使用すると、今回の様にGCPやAWS,AzureのようなPublicクラウドから、ローカルのNFSやOpenStackのCinder、Ceph等に自動的に必要なストレージを用意してくれるようになります。
具体的にはPVC起因でデプロイされるようになります。

https://kubernetes.io/docs/concepts/storage/storage-classes/#gce-pd


# 構築する環境

PV/PVC/StorageClassについて、イメージが若干おかしいかもしれませんが、私の頭の中では以下の様な構成になっております。
PVCをyamlからデプロイすると、PVCに関連付けられたStorageClassが反応しGCE上にストレージを作成しに行き、podは作成されたストレージに対してアタッチされます。

![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/c110119a-2414-49a9-a5f5-1ea98c3148c0)


# 用意したファイル一覧
新規作成及び修正分のみこちらに記載します。
残りのyamlはvol.4をご覧頂ければと思います。

## 新規作成
#### mysql-storageclass.yaml

GCE上にストレージを作成する為のyamlファイルとなります。
metadataの名前の部分がPVCのstorageClassNameと一致すると、キックされてストレージを作成しに行きます。

```mysql-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: mysql-storage-class
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
  fstype: ext4
  replication-type: none
```

## 修正
#### mysql-pvc.yaml
StorageClass使用にあたり、spec.storageClassName部分を修正しました。
```mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-vol-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: mysql-storage-class
  resources:
    requests:
      storage: 50Gi
```

# 構築

まず、GCE上にストレージが無い事とGKE上にPVCが無いことを確認します。
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/80352741-5aae-4b1e-88e7-42a4324d32ec)
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/f57a1231-4e59-4a0a-85ab-e8e20e0b4da8)

次にStorageClassをデプロイしてみます。
デプロイ後get,describeもしてみます。RECLAIMPOLICYがDeleteとなっていることからPVCを削除するとストレージも削除されます。この辺りはyamlで変更出来ると思います。確認は特段しておりませんけれども。。。
また、このタイミングではGCE、GKEのWebコンソールには何も変化ありません。
```
$ kubectl apply -f mysql-storageclass.yaml

$ kubectl get sc 
NAME                        PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
enterprise-multishare-rwx   filestore.csi.storage.gke.io   Delete          WaitForFirstConsumer   true                   36m
enterprise-rwx              filestore.csi.storage.gke.io   Delete          WaitForFirstConsumer   true                   36m
mysql-storage-class         kubernetes.io/gce-pd           Delete          Immediate              false                  10s
premium-rwo                 pd.csi.storage.gke.io          Delete          WaitForFirstConsumer   true                   36m
premium-rwx                 filestore.csi.storage.gke.io   Delete          WaitForFirstConsumer   true                   36m
standard                    kubernetes.io/gce-pd           Delete          Immediate              true                   36m
standard-rwo (default)      pd.csi.storage.gke.io          Delete          WaitForFirstConsumer   true                   36m
standard-rwx                filestore.csi.storage.gke.io   Delete          WaitForFirstConsumer   true                   36m

$ kubectl describe sc mysql-storage-class
Name:            mysql-storage-class
IsDefaultClass:  No
Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"mysql-storage-class"},"parameters":{"fstype":"ext4","replication-type":"none","type":"pd-standard"},"provisioner":"kubernetes.io/gce-pd"}

Provisioner:           kubernetes.io/gce-pd
Parameters:            fstype=ext4,replication-type=none,type=pd-standard
AllowVolumeExpansion:  <unset>
MountOptions:          <none>
ReclaimPolicy:         Delete
VolumeBindingMode:     Immediate
Events:                <none>
```

PVCをデプロイします。
```
$ kubectl apply -f mysql-pvc.yaml 
```

このタイミングでGCE及びGKE上で作成されたストレージ、PVCが確認出来るようになります。
PVCがデプロイされたことでStorageClassがキックされて、ストレージが作成されたということですね。
まずはGCEのストレージ
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/97624757-be1c-427a-a2ce-03df7ce5e723)
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/6402bd6b-98ce-4073-8740-d653e63d5bb4)
続いてGKEのPVC
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/6512705a-9802-4435-bc31-86f198dc5911)
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/d521c192-12c9-47f9-9b1c-a8ad19e4efc2)

CUIでも確認してみましょう。PVのyamlは用意しておらずデプロイもしておりませんがStorageClassが良い感じにやってくれているようですね。
```
$ kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                   STORAGECLASS          REASON   AGE
persistentvolume/pvc-c2a74a10-58eb-4356-ae54-b1316630d42d   50Gi       RWO            Delete           Bound    default/mysql-vol-pvc   mysql-storage-class            2m53s

NAME                                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/mysql-vol-pvc   Bound    pvc-c2a74a10-58eb-4356-ae54-b1316630d42d   50Gi       RWO            mysql-storage-class   2m58s
```

他のyamlファイルからもデプロイをして、Wordpressを立ち上げます。
今回用意したWordpressは"GKE-storageClass"というタイトルのものとします。
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/83471d6f-a212-4e80-8344-7dc9c2aaa01f)

MySQL podが削除されてもデータが残ることを確認します。
既存のMySQL podをデリートし新しいpodをデプロイします。
```
$ kubectl replace --force -f mysql-pod.yaml 
pod "mysql-pod" deleted
Warning: Autopilot set default resource requests for Pod default/mysql-pod, as resource requests were not specified. See http://g.co/gke/autopilot-defaults
pod/mysql-pod replaced
```

再度Webブラウザで接続しに行っても、同じ画面が表示されます。データは残っていると判断できますね。
StorageClassを有効的に活用すれば、ストレージ周りの管理コストが圧縮できそうだなと感じました。バインドについてもたぶんミスることは無いでしょうし、「なぜバインドされない？」的な感じで頭を抱えることも減りそうです。
![Image](https://github.com/ohtsuka-shota/ascii0-python-encrypt-decrypt/assets/127835743/83471d6f-a212-4e80-8344-7dc9c2aaa01f)