在 K8s
中 StorageClass
對象的目的,就是不去創建 PV
而是透過 PVC
需求去建立 PV
,這表示不必要再去管理 PV
資源,相較於 PVC
請求 PV
方式帶來更高的靈活性。
在創建 StorageClass
對象時,name
的定義一樣是重要的,PVC
在調用時會使用 storageClassName
去對應該 StorageClass
對象的 name
,創建時還需定義以下通用字段
provisioner
的不同而有不同的參數PV
回收策略,預設是 Delete
否則可定義 Retain
PVC
完成提供和綁定資源我們以 Nginx 為例,為它建立一個 StorageClass
。我們會定義以下的 yaml
。volumeBindingMode
字段可參考官方。
apiVersion: storage.k8s.io/v1
kind: StorageClass # 定義 StorageClass
metadata:
name: standard-us-centrall-a-b-c
provisioner: kubernetes.io/gce-pd # 提供儲存的地方
parameters:
type: pd-standard # 使用一般類型硬碟
reclaimPolicy: Delete # 刪除後自動清除相關資源
volumeBindingMode: WaitForFirstConsumer
allowedTopologies: # 這邊是設定儲存建立的區域
- matchLabelExpressions:
- key: failure-domain.beta.kubernetes.io/zone
values: # 建立區域有以下
- us-central1-a
- us-central1-b
- us-central1-c
apiVersion: v1
kind: PersistentVolumeClaim # 建立 PVC
metadata:
name: nginx-pvc # 名稱
namespace: default
labels:
app: nginx
role: backend
spec: # 下面字段都說明過
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 8Gi
storageClassName: standard-us-centrall-a-b-c # 這邊要對應 StorageClass 對象定義的 name
定義 Nginx 的 POD
,控制器使用 Deployment
。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.18
name: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- name: nginx-persistent-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-persistent-storage
persistentVolumeClaim: # PVC
claimName: nginx-pvc # PVC 的 name 字段
當上面檔案都建立後,使用 apply
方式布署。布署完後先查看 StorageClass
是否被建立,結果如下有被建立。
$ kubectl get storageclass
NAME PROVISIONER AGE
standard (default) kubernetes.io/gce-pd 20d
standard-us-centrall-a-b-c kubernetes.io/gce-pd 88s
接著查看 PVC
是否有綁定到 StorageClass
所建立的 PV
,從下面結果看是有的,STATUS
為 Bound
,用 describe
觀察 Events
也是可以觀察到成功的綁定。
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Bound pvc-dfb99470-421f-44ca-aa2c-7f47806f0037 8Gi ROX standard-us-centrall-a-b-c 109s
$ kubectl describe pvc nginx-pvc
Name: nginx-pvc
Namespace: default
StorageClass: standard-us-centrall-a-b-c
Status: Bound
Volume: pvc-dfb99470-421f-44ca-aa2c-7f47806f0037
Labels: app=nginx
role=backend
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/gce-pd
volume.kubernetes.io/selected-node: gke-cluster-1-default-pool-7dc8b11b-r7rg
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 8Gi
Access Modes: ROX
VolumeMode: Filesystem
Mounted By: nginx-deploy-56fc578995-xhf52 # 由我們建立的 POD 綁定
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning ProvisioningFailed 2m15s persistentvolume-controller storageclass.storage.k8s.io "standard-us-centrall-a-b-c" not found
Normal WaitForFirstConsumer 73s (x5 over 2m13s) persistentvolume-controller waiting for first consumer to be created before binding
Normal ProvisioningSucceeded 65s persistentvolume-controller Successfully provisioned volume pvc-dfb99470-421f-44ca-aa2c-7f47806f0037 using kubernetes.io/gce-pd
這邊是觀察 POD
部分,使用 describe
觀察 Volumes
部分在 ClaimName
下確實有綁定到 PVC
,在觀察 Events
同樣有成功綁定訊息。
$ kubectl describe pods nginx-deploy-56fc578995-xhf52
Name: nginx-deploy-56fc578995-xhf52
Namespace: default
...
Ready: True
Restart Count: 0
Requests:
cpu: 100m
Environment: <none>
Mounts:
/usr/share/nginx/html from nginx-persistent-storage (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-nnghk (ro)
...
Volumes:
nginx-persistent-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: nginx-pvc
ReadOnly: false
default-token-nnghk:
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m24s default-scheduler Successfully assigned default/nginx-deploy-56fc578995-xhf52 to gke-cluster-1-default-pool-7dc8b11b-r7rg
Normal SuccessfulAttachVolume 2m19s attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-dfb99470-421f-44ca-aa2c-7f47806f0037"
...
查看 StroageClass
所建立的 PV
,建立 CAPACITY
為設定的 8Gi,表示說這樣的使用方式可以避免空間浪費的可能。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-dfb99470-421f-44ca-aa2c-7f47806f0037 8Gi ROX Delete Bound default/nginx-pvc standard-us-centrall-a-b-c 4m4s
$ kubectl describe pv pvc-dfb99470-421f-44ca-aa2c-7f47806f0037
Name: pvc-dfb99470-421f-44ca-aa2c-7f47806f0037
Labels: failure-domain.beta.kubernetes.io/region=us-central1
failure-domain.beta.kubernetes.io/zone=us-central1-c
Annotations: kubernetes.io/createdby: gce-pd-dynamic-provisioner
pv.kubernetes.io/bound-by-controller: yes
pv.kubernetes.io/provisioned-by: kubernetes.io/gce-pd
Finalizers: [kubernetes.io/pv-protection]
StorageClass: standard-us-centrall-a-b-c
Status: Bound
Claim: default/nginx-pvc
Reclaim Policy: Delete
Access Modes: ROX
VolumeMode: Filesystem
Capacity: 8Gi
Node Affinity:
Required Terms:
Term 0: failure-domain.beta.kubernetes.io/zone in [us-central1-c]
failure-domain.beta.kubernetes.io/region in [us-central1]
Message:
Source:
Type: GCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)
PDName: gke-cluster-1-1d54e52c-pvc-dfb99470-421f-44ca-aa2c-7f47806f0037
FSType: ext4
Partition: 0
ReadOnly: false
Events: <none>
下面兩張圖是在 GKE
上的呈現。Google 有一個qwiklab 也是針對於 StorageClass
進行實驗,有興趣的可以參考。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nginx-deploy-56fc578995-bsr8b 0/1 ContainerCreating 0 3m54s
nginx-deploy-56fc578995-svwc5 0/1 ContainerCreating 0 3m54s
nginx-deploy-56fc578995-xhf52 1/1 Running 0 11m
...
$ kubectl describe pod nginx-deploy-56fc578995-bsr8b
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 117s default-scheduler Successfully assigned default/nginx-deploy-56fc578995-bsr8b to gke-cluster-1-default-pool-7dc8b11b-cxs1
Warning FailedAttachVolume 13s (x8 over 111s) attachdetach-controller AttachVolume.Attach failed for volume "pvc-dfb99470-421f-44ca-aa2c-7f47806f0037" : googleapi: Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE - The disk resource 'projects/sunny-catwalk-286908/zones/us-central1-c/disks/gke-cluster-1-1d54e52c-pvc-dfb99470-421f-44ca-aa2c-7f47806f0037' is already being used by 'projects/sunny-catwalk-286908/zones/us-central1-c/instances/gke-cluster-1-default-pool-7dc8b11b-r7rg'
以 ReplicaSet
來看在定義 POD
時需要讓它關聯至一個 PVC
,而有多個副本時都會共享這個 PVC
,因此都會綁定到相同的 PV
。從結果來看不能針對每個 POD
去建立獨立的 PV
,也就是說不能用 ReplicaSet
來分配每個 POD
一個獨立 PV
,上面的錯誤就是這種情況。但是,透過手動創建 POD
、一個 POD
對應一個 ReplicaSet
然後定義每個 POD
的 PVC
或是將共享的 PV
中利用目錄方式去建立每個 POD
的存取目錄,不過這些方式有點繁瑣,加上重新調度問題,這些還會再延伸出問題。在 K8s
中有一個 StatefulSet
的控制器可以將每個應用程式都分配一個專屬資源,這在後面章節在提。
如果上面的 ReplicaSet
資源要共享 PV
時,在 POD
中 containers
的 VolumeMounts
字段中將 readOnly
設置為 true。
readOnly 設置結果:Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
$ kubectl edit deploy nginx-deploy # 修改 replicas 個數
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-6f4c7bf454-58xtd 0/1 ContainerCreating 0 11m
nginx-deploy-6f4c7bf454-6l7vs 1/1 Running 0 23m
nginx-deploy-6f4c7bf454-8blj5 1/1 Running 0 23m
nginx-deploy-6f4c7bf454-9wdzp 1/1 Running 0 23m
nginx-deploy-6f4c7bf454-c24p9 0/1 ContainerCreating 0 11m
nginx-deploy-6f4c7bf454-j8dcb 0/1 ContainerCreating 0 11m
nginx-deploy-6f4c7bf454-ksdxh 1/1 Running 0 11m # 成功
nginx-deploy-6f4c7bf454-ps7ps 0/1 ContainerCreating 0 11m
nginx-deploy-6f4c7bf454-wzd64 0/1 ContainerCreating 0 11m
nginx-deploy-6f4c7bf454-ztgnr 0/1 ContainerCreating 0 11m
以下從檔案更新個數在 apply
也是相同錯誤結果。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9m55s default-scheduler Successfully assigned default/nginx-deploy-6f4c7bf454-c24p9 to gke-cluster-1-default-pool-7dc8b11b-8kvr
Warning FailedMount 66s (x4 over 7m52s) kubelet, gke-cluster-1-default-pool-7dc8b11b-8kvr Unable to mount volumes for pod "nginx-deploy-6f4c7bf454-c24p9_default(618dce42-0312-481c-a2ad-17edf2c9a9fd)": timeout expired waiting for volumes to attach or mount for pod "default"/"nginx-deploy-6f4c7bf454-c24p9". list of unmounted volumes=[nginx-persistent-storage]. list of unattached volumes=[nginx-persistent-storage default-token-nnghk]
Warning FailedAttachVolume 43s (x12 over 9m50s) attachdetach-controller AttachVolume.Attach failed for volume "pvc-451989b4-ecc8-4571-89ba-2de8c76181c5" : googleapi: Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE - The disk resource 'projects/sunny-catwalk-286908/zones/us-central1-c/disks/gke-cluster-1-1d54e52c-pvc-451989b4-ecc8-4571-89ba-2de8c76181c5' is already being used by 'projects/sunny-catwalk-286908/zones/us-central1-c/instances/gke-cluster-1-default-pool-7dc8b11b-r7rg'
這邊的錯誤結果有待在釐清一下。
PV
,並由 PVC
匹配PVC
去建立 PV
PVC
找到符合的 PV
後建立關聯。當 PVC
無法有符合 PV
時,會等待到有符合的 PV
為止,只不過狀態並非是綁定。這邊提到說一個正在使用的 PVC
被刪除的話,並非是立即的,會直到無任何資源使用時才會刪除。
就是前面說的 Retained
、Recycled
和 Deleted
。
簡單來說是擴充容量大小,這功能並非所有儲存方案都有,詳細可看官方