之前學(xué)習(xí)了 PV 和 PVC 的使用方法,但是前面的 PV 都是靜態(tài)的晕粪,什么意思倡缠?就是我要使用的一個(gè) PVC 的話就必須手動(dòng)去創(chuàng)建一個(gè) PV,我們也說過這種方式在很大程度上并不能滿足我們的需求亚情,比如有一個(gè)應(yīng)用需要對(duì)存儲(chǔ)的并發(fā)度要求比較高,而另外一個(gè)應(yīng)用對(duì)讀寫速度又要求比較高蕾久,特別是對(duì)于 StatefulSet 類型的應(yīng)用簡(jiǎn)單的來使用靜態(tài)的 PV 就很不合適了势似,這種情況下就需要用到動(dòng)態(tài) PV拌夏,也就是今天要學(xué)習(xí)的 StorageClass僧著。
創(chuàng)建
要使用 StorageClass,就得安裝對(duì)應(yīng)的自動(dòng)配置程序障簿,比如這里存儲(chǔ)后端使用的是 nfs盹愚,那么就需要使用到一個(gè) nfs-client 的自動(dòng)配置程序,也叫它 Provisioner站故,這個(gè)程序使用我們已經(jīng)配置好的 nfs 服務(wù)器皆怕,來自動(dòng)創(chuàng)建持久卷毅舆,也就是自動(dòng)創(chuàng)建 PV。
- 自動(dòng)創(chuàng)建的 PV 以
${namespace}-${pvcName}-${pvName}
這樣的命名格式創(chuàng)建在 NFS 服務(wù)器上的共享數(shù)據(jù)目錄中 - 而當(dāng)這個(gè) PV 被回收后會(huì)以
archieved-${namespace}-${pvcName}-${pvName}
這樣的命名格式存在 NFS 服務(wù)器上愈腾。
當(dāng)然在部署nfs-client
之前憋活,需要先成功安裝上 nfs 服務(wù)器,服務(wù)地址是10.11.1.220虱黄,共享數(shù)據(jù)目錄是/data/cmp/悦即,然后接下來我們部署 nfs-client 即可,也可以直接參考 nfs-client 的文檔:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client橱乱,進(jìn)行安裝即可辜梳。
第一步:配置 Deployment,將里面的對(duì)應(yīng)的參數(shù)替換成我們自己的 nfs 配置(nfs-client.yaml)
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
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
value: 10.11.1.220
- name: NFS_PATH
value: /data/cmp/storageclass
volumes:
- name: nfs-client-root
nfs:
server: 10.11.1.220
path: /data/cmp/storageclass
第二步:將環(huán)境變量 NFS_SERVER 和 NFS_PATH 替換泳叠,當(dāng)然也包括下面的 nfs 配置作瞄,我們可以看到這里使用了一個(gè)名為 nfs-client-provisioner 的serviceAccount,所以需要?jiǎng)?chuàng)建一個(gè) sa危纫,然后綁定上對(duì)應(yīng)的權(quán)限:(nfs-client-sa.yaml)
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
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: ["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: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
這里新建的一個(gè)名為 nfs-client-provisioner 的ServiceAccount宗挥,然后綁定了一個(gè)名為 nfs-client-provisioner-runner 的ClusterRole,而該ClusterRole聲明了一些權(quán)限种蝶,其中就包括對(duì)persistentvolumes的增属韧、刪、改蛤吓、查等權(quán)限宵喂,所以可以利用該ServiceAccount來自動(dòng)創(chuàng)建 PV。
第三步:nfs-client 的 Deployment 聲明完成后会傲,就可以來創(chuàng)建一個(gè)StorageClass對(duì)象了:(nfs-client-class.yaml)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: course-nfs-storage
provisioner: fuseim.pri/ifs
聲明了一個(gè)名為 course-nfs-storage 的StorageClass對(duì)象锅棕,注意下面的provisioner對(duì)應(yīng)的值一定要和上面的Deployment下面的 PROVISIONER_NAME 這個(gè)環(huán)境變量的值一樣。
現(xiàn)在創(chuàng)建這些資源對(duì)象:
$ kubectl create -f nfs-client.yaml
$ kubectl create -f nfs-client-sa.yaml
$ kubectl create -f nfs-client-class.yaml
創(chuàng)建完成后查看下資源狀態(tài):
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nfs-client-provisioner-7648b664bc-7f9pk 1/1 Running 0 7h
...
$ kubectl get storageclass
NAME PROVISIONER AGE
course-nfs-storage fuseim.pri/ifs 11s
新建
上面把StorageClass資源對(duì)象創(chuàng)建成功了淌山,接下來通過一個(gè)示例測(cè)試下動(dòng)態(tài) PV裸燎,首先創(chuàng)建一個(gè) PVC 對(duì)象:(test-pvc.yaml)
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
這里聲明了一個(gè) PVC 對(duì)象,采用 ReadWriteMany 的訪問模式泼疑,請(qǐng)求 1Mi 的空間德绿,但是可以看到上面的 PVC 文件沒有標(biāo)識(shí)出任何和 StorageClass 相關(guān)聯(lián)的信息,那么如果現(xiàn)在直接創(chuàng)建這個(gè) PVC 對(duì)象能夠自動(dòng)綁定上合適的 PV 對(duì)象嗎退渗?顯然是不能的(前提是沒有合適的 PV)移稳,這里有兩種方法可以來利用上面我們創(chuàng)建的 StorageClass 對(duì)象來自動(dòng)創(chuàng)建一個(gè)合適的 PV:
第一種方法:在這個(gè) PVC 對(duì)象中添加一個(gè)聲明 StorageClass 對(duì)象的標(biāo)識(shí),這里可以利用一個(gè) annotations 屬性來標(biāo)識(shí)会油,如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
annotations:
volume.beta.kubernetes.io/storage-class: "course-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
第二種方法:可以設(shè)置這個(gè) course-nfs-storage 的 StorageClass 為 Kubernetes 的默認(rèn)存儲(chǔ)后端个粱,可以用 kubectl patch 命令來更新:
$ kubectl patch storageclass course-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
上面這兩種方法都是可以的,當(dāng)然為了不影響系統(tǒng)的默認(rèn)行為翻翩,這里還是采用第一種方法都许,直接創(chuàng)建即可:
$ kubectl create -f test-pvc.yaml
persistentvolumeclaim "test-pvc" created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
test-pvc Bound pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7 1Mi RWX course-nfs-storage 2m
...
可以看到一個(gè)名為 test-pvc 的 PVC 對(duì)象創(chuàng)建成功了稻薇,狀態(tài)已經(jīng)是 Bound 了,是不是也產(chǎn)生了一個(gè)對(duì)應(yīng)的 VOLUME 對(duì)象胶征,最重要的一欄是 STORAGECLASS塞椎,現(xiàn)在是不是也有值了,就是我們剛剛創(chuàng)建的 StorageClass 對(duì)象 course-nfs-storage睛低。
然后查看下 PV 對(duì)象呢:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
...
pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7 1Mi RWX Delete Bound default/test-pvc course-nfs-storage 8m
...
可以看到是不是自動(dòng)生成了一個(gè)關(guān)聯(lián)的 PV 對(duì)象忱屑,訪問模式是 RWX,回收策略是 Delete暇昂,這個(gè) PV 對(duì)象并不是我們手動(dòng)創(chuàng)建的吧莺戒,這是通過上面的 StorageClass 對(duì)象自動(dòng)創(chuàng)建的。這就是 StorageClass 的創(chuàng)建方法急波。
測(cè)試
接下來還是用一個(gè)簡(jiǎn)單的示例來測(cè)試下我們上面用 StorageClass 方式聲明的 PVC 對(duì)象吧:(test-pod.yaml)
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox
imagePullPolicy: IfNotPresent
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-pvc
上面這個(gè) Pod 非常簡(jiǎn)單从铲,就是用一個(gè) busybox 容器,在 /mnt 目錄下面新建一個(gè) SUCCESS 的文件澄暮,然后把 /mnt 目錄掛載到上面我們新建的 test-pvc 這個(gè)資源對(duì)象上面了名段,要驗(yàn)證很簡(jiǎn)單,只需要去查看下 nfs 服務(wù)器上面的共享數(shù)據(jù)目錄下面是否有 SUCCESS 這個(gè)文件即可:
$ kubectl create -f test-pod.yaml
pod "test-pod" created
然后可以在 nfs 服務(wù)器的共享數(shù)據(jù)目錄下面查看下數(shù)據(jù):
$ ls /data/k8s/
default-test-pvc-pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7
可以看到下面有名字很長(zhǎng)的文件夾泣懊,這個(gè)文件夾的命名方式是不是和我們上面的規(guī)則:{pvcName}-${pvName}是一樣的伸辟,再看下這個(gè)文件夾下面是否有其他文件:
$ ls /data/k8s/default-test-pvc-pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7
SUCCESS
看到下面有一個(gè) SUCCESS 的文件,就證明我們上面的驗(yàn)證是成功的馍刮。
另外可以看到這里是手動(dòng)創(chuàng)建的一個(gè) PVC 對(duì)象信夫,在實(shí)際工作中,使用 StorageClass 更多的是 StatefulSet 類型的服務(wù)卡啰,StatefulSet 類型的服務(wù)也可以通過一個(gè) volumeClaimTemplates 屬性來直接使用 StorageClass静稻,如下:(test-statefulset-nfs.yaml)
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: nfs-web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nfs-web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: course-nfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
實(shí)際上 volumeClaimTemplates 下面就是一個(gè) PVC 對(duì)象的模板,就類似于這里 StatefulSet 下面的 template匈辱,實(shí)際上就是一個(gè) Pod 的模板振湾,不單獨(dú)創(chuàng)建成 PVC 對(duì)象,而用這種模板就可以動(dòng)態(tài)的去創(chuàng)建了對(duì)象了亡脸,這種方式在 StatefulSet 類型的服務(wù)下面使用得非常多押搪。
直接創(chuàng)建上面的對(duì)象:
$ kubectl create -f test-statefulset-nfs.yaml
statefulset.apps "nfs-web" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nfs-web-0 1/1 Running 0 1m
nfs-web-1 1/1 Running 0 1m
nfs-web-2 1/1 Running 0 33s
...
創(chuàng)建完成后可以看到上面的3個(gè) Pod 已經(jīng)運(yùn)行成功,然后查看下 PVC 對(duì)象:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
www-nfs-web-0 Bound pvc-cc36b3ce-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 2m
www-nfs-web-1 Bound pvc-d38285f9-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 2m
www-nfs-web-2 Bound pvc-e348250b-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 1m
...
可以看到是不是也生成了3個(gè) PVC 對(duì)象浅碾,名稱由模板名稱 name 加上 Pod 的名稱組合而成大州,這3個(gè) PVC 對(duì)象也都是 綁定狀態(tài)了,很顯然查看 PV 也可以看到對(duì)應(yīng)的3個(gè) PV 對(duì)象:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
... 1d
pvc-cc36b3ce-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-0 course-nfs-storage 4m
pvc-d38285f9-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-1 course-nfs-storage 4m
pvc-e348250b-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-2 course-nfs-storage 4m
...
查看 nfs 服務(wù)器上面的共享數(shù)據(jù)目錄:
$ ls /data/k8s/
...
default-www-nfs-web-0-pvc-cc36b3ce-8b50-11e8-b585-525400db4df7
default-www-nfs-web-1-pvc-d38285f9-8b50-11e8-b585-525400db4df7
default-www-nfs-web-2-pvc-e348250b-8b50-11e8-b585-525400db4df7
...
是不是也有對(duì)應(yīng)的3個(gè)數(shù)據(jù)目錄及穗,這就是 StorageClass 的使用方法摧茴,對(duì)于 StorageClass 多用于 StatefulSet 類型的服務(wù)绵载。