上節課咱們學習了 PV 的使用,可是在咱們真正使用的時候是使用的 PVC,就相似於咱們的服務是經過 Pod 來運行的,而不是 Node,只是 Pod 跑在 Node 上而已,因此這節課咱們就來給你們講解下 PVC 的使用方法。html
在使用 PVC 以前,咱們還得把其餘節點上的 nfs 客戶端給安裝上,好比咱們這裏:node
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 61d v1.10.0
node01 Ready <none> 61d v1.10.0 node03 Ready <none> 41d v1.10.0
咱們須要在全部節點安裝 nfs 客戶端程序,安裝方法和上節課的安裝方法同樣的。必須在全部節點都安裝 nfs 客戶端,不然可能會致使 PV 掛載不上的問題nginx
一樣的,咱們來新建一個數據卷聲明,咱們來請求 1Gi 的存儲容量,訪問模式也是 ReadWriteOnce,YAML 文件以下:(pvc-nfs.yaml)web
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-nfs spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
咱們能夠看到咱們這裏的聲明方法幾乎和新建 PV 是同樣的,在新建 PVC 以前,咱們能夠看下以前建立的 PV 的狀態:shell
kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs 1Gi RWO Recycle Available 19m
咱們能夠看到當前 pv-nfs 是在 Available 的一個狀態,因此這個時候咱們的 PVC 能夠和這個 PV 進行綁定:後端
$ kubectl create -f pvc-nfs.yaml
persistentvolumeclaim "pvc-nfs" created $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs Bound pv-nfs 1Gi RWO 12s
咱們能夠看到 pvc-nfs 建立成功了,狀態是 Bound 狀態了,這個時候咱們再看下 PV 的狀態呢:api
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs 1Gi RWO Recycle Bound default/pvc-nfs 23m
一樣咱們能夠看到 PV 也是 Bound 狀態了,對應的聲明是 default/pvc-nfs,就是 default 命名空間下面的 pvc-nfs,證實咱們剛剛新建的 pvc-nfs 和咱們的 pv-nfs 綁定成功了。mvc
有的同窗可能會以爲很奇怪,咱們並無在 pvc-nfs 中指定關於 pv 的什麼標誌,它們之間是怎麼就關聯起來了的呢?其實這是系統自動幫咱們去匹配的,他會根據咱們的聲明要求去查找處於 Available 狀態的 PV,若是沒有找到的話那麼咱們的 PVC 就會一直處於 Pending 狀態,找到了的話固然就會把當前的 PVC 和目標 PV 進行綁定,這個時候狀態就會變成 Bound 狀態了。好比咱們新建一個 PVC,以下:(pvc2-nfs.yaml)app
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc2-nfs spec: accessModes: - ReadWriteOnce resources: requests: storage: 2Gi selector: matchLabels: app: nfs
咱們這裏聲明一個 PV 資源的請求,邀請訪問模式是 ReadWriteOnce,存儲容量是 2Gi,最後咱們還要求匹配具備標籤 app=nfs 的 PV,這樣要求的 PV 有嗎?咱們先查看下當前系統的全部 PV:學習
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs 1Gi RWO Recycle Bound default/pvc-nfs 43m pv001 1Gi RWO Recycle Bound default/www-web-0 13d pv002 1Gi RWO Recycle Bound default/www-web-1 13d
都是 Bound 狀態,並無 Available 狀態的 PV,因此咱們能夠想象到咱們上面新建的 PVC 是沒辦法選擇到合適的 PV 的,咱們建立一下看看:
$ kubectl create -f pvc2-nfs.yaml
persistentvolumeclaim "pvc2-nfs" created $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs Bound pv-nfs 1Gi RWO 23m pvc2-nfs Pending 14s
很顯然是 Pending 狀態,由於並無合適的 PV 給你使用,如今咱們來新建一個 PV,讓上面的 PVC 有合適的 PV 使用:(pv2-nfs.yaml)
apiVersion: v1 kind: PersistentVolume metadata: name: pv2-nfs labels: app: nfs spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: server: 10.151.30.57 path: /data/k8s
咱們這裏新建一個名爲 pv2-nfs 的 PV,具備標籤 app=nfs,容量也是 2Gi,訪問模式是 ReadWraiteOnce,看上去這一切都很適合上面的 PVC,新建試一試:
$ kubectl create -f pv2-nfs.yaml
persistentvolume "pv2-nfs" created $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs 1Gi RWO Recycle Bound default/pvc-nfs 51m pv2-nfs 2Gi RWO Recycle Bound default/pvc2-nfs 12s
建立完 pv2-nfs 後,是否是很快就發現該 PV 是 Bound 狀態了,對應的 PVC 是 default/pvc2-nfs,證實上面的 pvc2-nfs 終於找到合適的 PV 進行綁定上了:
$ kubectl get pvc kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs Bound pv-nfs 1Gi RWO 30m pvc2-nfs Bound pv2-nfs 2Gi RWO 7m
成功了,對吧!有的同窗可能又會說了,咱們的 pv2-nfs 聲明的容量是 2Gi,若是我 pvc2-nfs 這裏聲明的容量是 1Gi 的話呢?還能正常綁定嗎?若是能夠正常綁定的話,那剩下的 1Gi 容量還能使用嗎?其實我也不清楚,怎麼辦?咱們去實際測試下就知道了吧,先刪除上面的 pvc2-nfs,而後咱們把該 PVC 裏面的容量改爲 1Gi,再新建試一試呢:
$ kubectl delete pvc pvc2-nfs
persistentvolumeclaim "pvc2-nfs" deleted $ cat pvc2-nfs.yaml ... resources: requests: storage: 1Gi ... $ kubectl create -f pvc2-nfs.yaml persistentvolumeclaim "pvc2-nfs" created $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc2-nfs Bound pv2-nfs 2Gi RWO 7s
咱們能夠看到上面的 PVC 依然能夠正常的綁定,仔細看 CAPACITY 這一列的數據:2Gi,也就是說咱們聲明的 1Gi 是沒什麼用的,我 PV 是 2Gi,你這裏聲明 1Gi 是不行的,你必須得使用 2Gi。
若是咱們這裏容量聲明是 3Gi 呢?還能夠正常綁定嗎?你們能夠思考一下,若是聲明的容量大於了 PV 裏面的容量的話,是沒辦法進行綁定的,你們能夠下去本身測試一下。
上面咱們已經知道怎麼建立 PV 和 PVC 了,如今咱們就來使用下咱們的 PVC,這裏咱們一樣使用以前的 nginx 的鏡像來測試下:(nfs-pvc-deploy.yaml)
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nfs-pvc spec: replicas: 3 template: metadata: labels: app: nfs-pvc spec: containers: - name: nginx image: nginx:1.7.9 imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumes: - name: www persistentVolumeClaim: claimName: pvc2-nfs --- apiVersion: v1 kind: Service metadata: name: nfs-pvc labels: app: nfs-pvc spec: type: NodePort ports: - port: 80 targetPort: web selector: app: nfs-pvc
咱們這裏使用 nginx 鏡像,將容器的 /usr/share/nginx/html 目錄經過 volume 掛載到名爲 pvc2-nfs 的 PVC 上面,而後建立一個 NodePort 類型的 Service 來暴露服務:
$ kubectl create -f nfs-pvc-deploy.yaml
deployment.extensions "nfs-pvc" created service "nfs-pvc" created $ kubectl get pods kubectl get pods NAME READY STATUS RESTARTS AGE ... nfs-pvc-57c9945bd9-5r4r6 1/1 Running 0 19s nfs-pvc-57c9945bd9-gz6p9 1/1 Running 0 19s nfs-pvc-57c9945bd9-x6mvc 1/1 Running 0 19s ... $ kubectl get svc kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ... nfs-pvc NodePort 10.98.246.155 <none> 80:30769/TCP 1m ...
而後咱們就能夠經過任意節點的 IP:30769 端口來訪問咱們這裏的 Nginx 服務了,可是這個時候咱們來訪問會出現403,這是爲何?咱們再去看看 nfs 共享數據目錄下面有沒有數據呢?
nginx 403
$ ls /data/k8s
咱們發現並無任何數據,這是由於咱們把容器目錄/user/share/nginx/html和掛載到了pvc2-nfs這個 PVC 上面,這個 PVC 就是對應着咱們上面的 nfs 的共享數據目錄的,該目錄下面尚未任何數據,因此咱們訪問就出現了403,如今咱們在/data/k8s這個目錄下面新建一個 index.html 的文件:
$ echo "<h1>Hello Kubernetes~</h1>" >> /data/k8s/index.html $ ls /data/k8s/ index.html
咱們能夠看到共享數據目錄中已經有一個 index.html 的文件了,因爲咱們掛載了 pvc2-nfs 到上面的 nginx 容器中去,是否是這個時候容器目錄/user/share/nginx/html下面也有index.html這個文件了啊?因此這個時候咱們再來訪問下服務,任一節點IP:30769:
nginx 200
如今是否是正常了啊,可是咱們能夠看到咱們容器中的數據是直接放到共享數據目錄根目錄下面的,若是之後咱們又有一個新的 nginx 容器也作了數據目錄的掛載,是否是就會有衝突了啊,因此這個時候就不太好區分了,這個時候咱們能夠在 Pod 中使用一個新的屬性:subPath,該屬性能夠來解決這個問題,咱們只須要更改上面的 Pod 的 YAML 文件便可:
... volumeMounts: - name: www subPath: nginxpvc-test mountPath: /usr/share/nginx/html ...
更改完 YAML 文件後,咱們從新更新便可:
$ kubectl apply -f nfs-pvc-deploy.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.extensions "nfs-pvc" configured Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply service "nfs-pvc" configured
更新完後,咱們再去看看 nfs 的數據共享目錄:
$ ls /data/k8s/ index.html nginxpvc-test $ ls /data/k8s/nginxpvc-test/
咱們能夠預想到如今咱們訪問上面的服務,是否是又會獲得403的結果啊,由於nginxpvc-test目錄下面尚未任何文件呢,咱們把根目錄下面的 index.html 文件移動到 nginxpvc-test 目錄下面去是否是又能夠訪問了:
$ mv /data/k8s/index.html /data/k8s/nginxpvc-test/
如今快去驗證下吧,看看能不能獲得正確結果。
到這裏咱們就算完整的使用了一次 PVC 了,如今咱們再來驗證下咱們的數據是否會丟失,怎麼驗證?首先咱們把上面的 Deployment 刪除掉,這樣是否是他下面管理的3個 Pod 也會被一塊兒刪除掉啊:
$ kubectl delete deployment nfs-pvc
deployment.extensions "nfs-pvc" deleted
Deployment 被刪除掉了,可是 nfs 的數據共享目錄下面的數據呢?
$ ls /data/k8s/nginxpvc-test/ index.html
還在吧?固然了若是不在了,咱們用他就沒有任何意義了吧,如今咱們再來從新建立上面的 Deployment,看看訪問服務還能獲得上面的正常輸出結果嗎:
$ kubectl create -f nfs-pvc-deploy.yaml
deployment.extensions "nfs-pvc" created Error from server (AlreadyExists): error when creating "nfs-pvc-deploy.yaml": services "nfs-pvc" already exists
能夠看到 nfs-pvc 這個 Deployment 建立成功了,因爲 Service 咱們以前沒有刪除掉,因此這裏提示已經存在,咱們忽略就能夠了,如今一樣咱們用任一節點 IP:30769 來訪問咱們這裏的服務,是否是依然能夠在頁面上看到Hello Kubernetes~這裏的輸出信息啊,這證實咱們的數據持久化是成功的吧!
上面咱們演示了數據持久化,若是這個時候咱們把 PV 給刪除了,上面持久化的數據還會存在嗎?若是是刪除的 PVC 呢?在實際使用的工程中,是頗有可能出現這種狀況的吧?下面咱們來實際驗證下。
咱們先刪除上面使用的 PV:
$ kubectl delete pv pv2-nfs persistentvolume "pv2-nfs" deleted
而後再看看以前建立的 PVC 還會存在嗎:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
... pvc2-nfs Bound pv2-nfs 2Gi RWO 1h ...
是否是以爲很奇怪,pvc2-nfs 仍然是 Bound 的狀態,也就意外着咱們還能夠正常使用這個 PVC,可是若是咱們有一個新的 Pod 來使用這個 PVC 會是怎樣的狀況呢?你們下去本身驗證下
若有 Pod 正在使用此 pvc2-nfs 這個 PVC 的話,那麼新建的 Pod 則仍可以使用,如無 Pod 使用,則建立 Pod 掛載此 PVC 時會出現失敗。你們本身去驗證下吧
如今咱們在恢復到最開始的狀態,把 PV 和 PVC 添加回來,若是如今咱們把使用 pvc2-nfs 關聯的 Pod 都刪除,而後再刪除該 PVC 的話,那麼咱們的持久化數據還存在嗎?
$ kubectl delete -f nfs-pvc-deploy.yaml
deployment.extensions "nfs-pvc" deleted service "nfs-pvc" deleted $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE ... pvc2-nfs Bound pv2-nfs 2Gi RWO 5m ... $ kubectl delete pvc pvc2-nfs persistentvolumeclaim "pvc2-nfs" deleted $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE ... pv2-nfs 2Gi RWO Recycle Released default/pvc2-nfs 6m ... $ ls /data/k8s/
咱們能夠看到 pv2-nfs 這個 PV 的狀態已經變成了 Released 狀態了,這個狀態是否是表示 PVC 已經被釋放了,如今能夠被從新綁定了,因爲咱們設置的 PV 的回收策略是 Recycle,因此咱們能夠很明顯的發現 nfs 的共享數據目錄下面已經沒有了數據了,這是由於咱們把 PVC 給刪除掉了,而後回收了數據。
不過你們要注意,並非全部的存儲後端的表現結果都是這樣的,咱們這裏使用的是 nfs,其餘存儲後端肯能會有不同的結果。
你們在使用 PV 和 PVC 的時候必定要注意這些細節,否則一不當心就把數據搞丟了。