上节课咱们学习了 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 的时候必定要注意这些细节,否则一不当心就把数据搞丢了。