1. 簡介
StorageClass 為管理員提供了描述儲存 "類" 的方法。
通過StorageClass的定義,管理員可以將儲存資源定義為某種類別(Class),正如儲存裝置對於自身的配置描述(Profile),例如 "快速儲存" "慢速儲存" "有資料冗餘" "無資料冗餘"等。使用者根據StorageClass的描述就能夠直觀得知各種儲存資源的特性,就可以根據應用對儲存資源的需求去申請儲存資源了。
StorageClass作為對儲存資源的抽象定義,對使用者設定的PVC申請遮蔽後端的細節,一方面減輕使用者對於儲存資源細節的關注,另一方面也減輕了管理員手工管理PV的工作,由系統自動完成PV的建立和繫結,實現了動態的資源供應。
每個 StorageClass 都包含 provisioner
、parameters
和 reclaimPolicy
欄位, 這些欄位會在 StorageClass 需要動態分配 PersistentVolume 時會使用到。
StorageClass 物件的命名很重要,使用者使用這個命名來請求生成一個特定的類。 當建立 StorageClass 物件時,管理員設定 StorageClass 物件的命名和其他引數,一旦建立了物件就不能再對其更新。
2. 建立Provisioner
如果需要使用StorageClass,我們就需要安裝對應的自動配置程式,比如我們這裡後端採用的是nfs,那麼我們就需要使用到一個nfs-client的自動配置程式,我們也叫它Provisioner,這個程式使用我們已經配置好的nfs伺服器,來自動建立持久卷,也就是自動幫我們建立PV。
這裡也可以直接參考nfs-client的官方文件
https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy
自動建立的PV以
{namespace}-${pvcname}-${pvname}
進行命名到伺服器上
如果開啟了
archiveOnDelete
功能,則當pv被回收後會以archieved-${namespace}-${pvcname}-${pvname}
格式存在伺服器上
2.1 建立deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
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: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
# nfs server 地址
value: 192.168.0.201
- name: NFS_PATH
# nfs 掛載點
value: /nfs/data
volumes:
- name: nfs-client-root
nfs:
# nfs server 地址
server: 192.168.0.201
# nfs 掛載點
path: /nfs/data
2.2 rbac
接下來我們還需要建立一個serveraccount,用於將nfs-client-provisioner中的ServiceAccount繫結到一個nfs-client-provisioner-runner的ClusterRole。而該ClusterRole宣告瞭一些許可權,其中就包括了對persistentvolumes的增刪改查,所以我們就可以利用ServiceAccount來自動建立PV
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
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: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
2.3 storage-class
provisioner值可以自定義但需要和deployment的 template.spec.containers.env PROVISIONER_NAME 保持一致
這裡我們宣告瞭一個名為managed-nfs-storage的Storageclass物件
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
# 設定為default StorageClass,如果建立pvc時不指定StorageClass,則會使用當前的StorageClass
storageclass.kubernetes.io/is-default-class: "true"
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
# 刪除PVC時不會保留資料
archiveOnDelete: "false"
# 回收策略:刪除
reclaimPolicy: Delete
#允許pvc建立後擴容
allowVolumeExpansion: true
回收策略
由 StorageClass 動態建立的 PersistentVolume 會在類的 reclaimPolicy
欄位中指定回收策略,可以是 Delete
或者 Retain
。如果 StorageClass 物件被建立時沒有指定 reclaimPolicy
,它將預設為 Delete
。
通過 StorageClass 手動建立並管理的 PersistentVolume 會使用它們被建立時指定的回收政策。
卷繫結模式
volumeBindingMode
欄位控制了卷繫結和動態製備
應該發生在什麼時候。
預設情況下,Immediate
模式表示一旦建立了 PersistentVolumeClaim 也就完成了卷繫結和動態製備。 對於由於拓撲限制而非叢集所有節點可達的儲存後端,PersistentVolume 會在不知道 Pod 排程要求的情況下繫結或者製備。
叢集管理員可以通過指定 WaitForFirstConsumer
模式來解決此問題。 該模式將延遲 PersistentVolume 的繫結和製備,直到使用該 PersistentVolumeClaim 的 Pod 被建立。 PersistentVolume 會根據 Pod 排程約束指定的拓撲來選擇或製備。這些包括但不限於 資源需求
、 節點篩選器
、 pod 親和性和互斥性
、 以及汙點和容忍度
。
說明:
如果選擇使用 WaitForFirstConsumer
,請不要在 Pod 規約中使用 nodeName
來指定節點親和性。 如果在這種情況下使用 nodeName
,Pod 將會繞過排程程式,PVC 將停留在 pending
狀態。
相反,在這種情況下,可以使用節點選擇器作為主機名,如下所示
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
nodeSelector:
kubernetes.io/hostname: kube-01
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
2.4 建立資源
建立資訊如下
資源資訊如下
3. 驗證動態建立pv
首先建立個pvc,看下是否會動態的建立pv
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
#storageclass 名稱
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
#訪問模式
accessModes:
- ReadWriteMany
resources:
requests:
#請求資料大小
storage: 1024Mi
從圖中可以看出,我們不需要的手動建立pv,只需要建立一個pvc,storageclass會自動將pv給建立並且關聯,就很nice
使用pvc
我們這裡建立一個deployment,使用下剛建立的pvc: test-claim
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: test-claim
測試演示步驟如下: