在 k8s 中当我们需要持久化存储一些数据的使用,会使用到的就是 PV 和 PVC,但 PV 和 PVC 都是需要手动创建的话会很麻烦,特别是当有 StatefulSet 应用存在的时候,如果你需要手动对每个 pod 都创建一个 PVC 和 PV 就非常麻烦,于是 StorageClass 就是来解决这个问题的。
准备
首先你需要一个 nfs 或其他存储,这里我以 nfs 为例进行部署
我们先来梳理一下思路和几个需要的东西:
- nfs 是我们最终的存储
- nfs-client 是用来动态创建 pv 和 pvc 的,我们称为 provisioner
- StorageClass 关联到对应的 provisioner 就可以使用
- statefulset(或别的资源)需要配置 storageClassName 进行使用
部署
创建 ServiceAccount
创建对应需要使用的 ServiceAccount,因为需要操作 pv 和 pvc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner namespace: my-system
--- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner namespace: my-system rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["list", "watch", "create", "update", "patch"] - apiGroups: [""] resources: ["endpoints"] verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
--- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: my-system roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io
|
部署 nfs-client
创建一个 deployment 用于部署 nfs-client 来分配想对应所需资源,注意其中 NFS_SERVER
和 NFS_PATH
需要修改为你自己的地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| kind: Deployment apiVersion: apps/v1 metadata: name: nfs-client-provisioner namespace: my-system spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: linkinstars.com/nfs - name: NFS_SERVER value: 172.16.1.1 - name: NFS_PATH value: /kubernetes/test resources: requests: cpu: 100m memory: 256Mi limits: cpu: 200m memory: 512Mi volumes: - name: nfs-client-root nfs: server: 172.16.1.1 path: /kubernetes/test
|
创建StorageClass
最后创建我们需要的 StorageClass 就可以了
1 2 3 4 5 6
| apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: my-nfs-storage namespace: my-system provisioner: linkinstars.com/nfs
|
测试一下
我们可以创建一个 pvc 来实际测试一下,如果创建之后没有出现错误,并且正常创建了 pv 的话那么证明你的部署就成功了
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc namespace: my-system spec: accessModes: - ReadWriteMany resources: requests: storage: 1Mi storageClassName: my-nfs-storage
|
statefulset 使用
StorageClass 经常会使用在 statefulset 的情况下,因为通常它需要配置 volumeClaimTemplates
动态根据模板创建对应需要使用的 pvc
1 2 3 4 5 6 7 8 9 10
| volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 32Mi storageClassName: my-nfs-storage
|
配置也非常简单,只需要配置 storageClassName 就可以了
这里我使用 statefulset 部署 consul
可以看到这些 pv 和 pvc 都是自动创建的,非常方便,这样 consul 的 data-dir 就可以做到持久化了
总结
StorageClass 真的是一个非常方便的设计,不需要运维每次吭叽吭叽去创建 pv 真的很麻烦
参考链接:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/#nfs