在这里插入图片描述
之前的文章中我们介绍了在k8s中hostPath的使用场景及用法,接下来我们来学习了解k8s中另外一种pv的使用场景及配置方法,首先hostPath相较于Local PV在真实的使用场景中存在一定的局限。

Pod不能随便漂移,需要固定到一个节点上,因为一旦漂移到其他节点的宿主机上就没有对应的数据了,所以在使用hostPath的时候会搭配使用nodeSelector来使用。

使用hostPath的这些节点一旦宕机,数据可能丢失。

好处是hostPath使用的是本地磁盘,读写性能相较于大多数存储来说要好的多。

所以在hostPath的基础上,Kubernetes依靠PV、PVC实现了一个新特性:Local Persistent Volume.
其实Local PV实现的功能非常类似于hostPath加上节点亲和性nodeAffinity,同时Local PV和普通的PV有一个很大的不同在于Local PV可以保证pod始终能够被正确的调度到它所请求的Local PV所在的节点上面。但值得注意的是:

对于普通的PV来说,Kubernetes都是先调度pod到某个节点上,然后再持久化节点上的Volume目录,进而完成Volume目录与容器的绑定挂载。
对于Local
PV来说,节点上可供使用的磁盘必事先准备好,因为它们在不同节点上的挂载情况可能不同,有的节点可能没这种磁盘,所以,这时候,调度器就必须能够知道所有节点与
Local PV 对应的磁盘的关联关系,然后根据这个信息来调度Pod,实际上就是在调度podde 的时候先考虑 Volume的分布情况。

如果文章对您有帮助,还想了解更过关于k8s相关的实战经验,请微信关注“IT运维图谱”公众号或着通过微信搜一搜关注公众号。

下面我们通过创建一个普通的pv和pvc来进行演示:

# cat pv-local.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-local
spec :
  capacity:
    storage: 2Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /data/localpv # k8s-node-03节点上的目录
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values :
                - k8s-node-03

# cat pvc-local.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-local
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: local-storage  #指定sc,集群中没有这个sc不影响pvc与pv的绑定

使用kubectl创建上面的资源对象:

[root@k8s-master-01 Loacl-pv]# kubectl apply -f .
persistentvolume/pv-local created
persistentvolumeclaim/pvc-local created
[root@k8s-master-01 Loacl-pv]# 
[root@k8s-master-01 Loacl-pv]# 
[root@k8s-master-01 Loacl-pv]# kubectl get pv,pvc
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS    REASON   AGE
persistentvolume/pv-local   2Gi        RWO            Delete           Bound    default/pvc-local   local-storage            7s

NAME                              STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
persistentvolumeclaim/pvc-local   Bound    pv-local   2Gi        RWO            local-storage   7s

在这里插入图片描述
可以看到现在PVC 和 PV 已经处于Bound 绑定状态了。但这不符合我们的需求的,比如现在我们的 Pod声明使用这个pvc-local,并且我们也明确规定这个 Pod 只能运行在 k8s-node-01这个节点上,如果按照上面我们这里的操作,这个pvc-Local就和pv-Local就绑定在一起了,但是这 PV的存储卷又在k8s-node-03 这节点上,显然就会pod和pv就存在冲突了,那么这个Pod的调度就会败,处于pinding状态。

我们编写一个nginx的pod部署清单进行验证:

# cat hostpath-nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-nginx-pod
  labels:
    app: hostpath-nginx-pod
spec:
  volumes:
  - name: pv-hostpath
    persistentVolumeClaim:
      claimName: pvc-local  # 声明要使用的pvc
  nodeSelector:
    kubernetes.io/hostname: k8s-node-01  指定只能运行在k8s-node-01节点上
  containers:
  - name: nginx-pod
    image: nginx:1.7.5
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
      name: pv-hostpath

使用kubectl创建上面的pod部署清单并查看pod状态:

[root@k8s-master-01 Loacl-pv]# kubectl apply -f hostpath-nginx-pod.yaml 
pod/hostpath-nginx-pod created
[root@k8s-master-01 Loacl-pv]# kubectl get pod -l app=hostpath-nginx-pod
NAME                 READY   STATUS    RESTARTS   AGE
hostpath-nginx-pod   0/1     Pending   0          6s

在这里插入图片描述
可以看到pod处于pinding状态,使用describe查看pod事件信息提示:Warning FailedScheduling 3m20s default-scheduler 0/4 nodes are available: 1 node(s) didn’t match Pod’s node affinity/selector. preemption: 0/4 nodes are available: 1 Preemption is not helpful for scheduling, 3 No preemption victims found for incoming pod。
查看pod事件信息,提示没有可供调度的节点。
在这里插入图片描述
所以我们在使用LocaL PV 的时候,得想办法延迟这个绑定操作。

我们先删除上面创建的资源对象,然后可以通过创建 Storageclass来指定这个动作,在StorageClass中有一个volumeBindingMode=WaitForFirstConsumer 的属性,告诉 kubernetes 在发现这个StorageClass 关联的 PVC 与PV 可以绑定在一起时,不要立刻执行绑定操作,而是等到有声明使用该PVC 的 Pod 出现在调度器之后,调度器再综合考虑所有的调度规则,当然也包括每个 PV所在的节点位置,来统一决定这个Pod 声明的 PVC应该跟哪个 PV进行绑定。通过这个延迟绑定机制,原本实时发生的 PVC和PV的绑定过程,就被延迟到了 Pod第一次调度的时候在调度器中进行,从而保证了这个绑定结果不会影响Pod 的正常调度。

# cat local-sc.yml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer  #延迟绑定参数,很重要

创建上面的sc清单,定义一个具备延迟绑定功能的sc


[root@k8s-master-01 Loacl-pv]# kubectl apply -f local-sc.yml 
storageclass.storage.k8s.io/local-storage created
[root@k8s-master-01 Loacl-pv]# 
[root@k8s-master-01 Loacl-pv]# 
[root@k8s-master-01 Loacl-pv]# 
[root@k8s-master-01 Loacl-pv]# kubectl get sc
NAME                      PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
csi-cephfs-sc (default)   cephfs.csi.ceph.com            Delete          Immediate              true                   19d
csi-rbd-sc                rbd.csi.ceph.com               Delete          Immediate              true                   19d
local-storage             kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  8s

现在apply上面的pv和pvc资源清单,并查看pv与pvc的绑定状态


[root@k8s-master-01 Loacl-pv]# kubectl apply -f .
persistentvolume/pv-local created
persistentvolumeclaim/pvc-local created
[root@k8s-master-01 Loacl-pv]# kubectl get pv,pvc
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS    REASON   AGE
persistentvolume/pv-local   2Gi        RWO            Delete           Available           local-storage            5s

NAME                              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
persistentvolumeclaim/pvc-local   Pending                                      local-storage   5s


可以看到pv处于Available状态,pvc处于Pending状态,也就是等待绑定的状态,这就是因为上面我们配置的是延迟绑定,需要在有Pod 使用的时候才会来做绑定。

接下来我们创建一个测试的pod来进行验证


[root@k8s-master-01 Loacl-pv]# kubectl apply -f pod-demo.yaml 
pod/pod-demo created
[root@k8s-master-01 Loacl-pv]# kubectl get pod -l app=pod-demo
NAME       READY   STATUS    RESTARTS   AGE
pod-demo   1/1     Running   0          12s
[root@k8s-master-01 Loacl-pv]# kubectl get pv,pvc
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS    REASON   AGE
persistentvolume/pv-local   2Gi        RWO            Delete           Bound    default/pvc-local   local-storage            10m

NAME                              STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
persistentvolumeclaim/pvc-local   Bound    pv-local   2Gi        RWO            local-storage   10m

可以看到之前处于Pending状态的pvc和处于Available状态的pv都处于Bound状态了,并且pod也处于Running状态了。
我们可以进入pod中,手动生成一个测试的index.html文件,并访问测试页面


[root@k8s-master-01 Loacl-pv]# kubectl get pod -owide -l app=pod-demo
NAME       READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
pod-demo   1/1     Running   0          14m   10.244.3.51   k8s-node-03   <none>           <none>
# 进入容器常见测试页面
[root@k8s-master-01 Loacl-pv]# kubectl exec -it pod-demo -- bash
root@pod-demo:/# echo "Hello,this is a test pod for Loacl PV" > /usr/share/nginx/html/index.html
root@pod-demo:/#exit
# 在master节点上访问测试
[root@k8s-master-01 Loacl-pv]# curl 10.244.3.51
Hello,this is a test pod for Loacl PV

登录k8s-node-03节点,查看/data/localpv目录下面持久化下来的文件

[root@k8s-node-03 ~]# ll /data/localpv/index.html 
-rw-r--r-- 1 root root 38 Jun 27 19:24 /data/localpv/index.html
[root@k8s-node-03 ~]# cat /data/localpv/index.html 
Hello,this is a test pod for Loacl PV

通过上面的文字介绍加实践,相信大家已经对k8s中Local PV 资源对象有了全新的认识。

如果文章对您有帮助,还想了解更过关于k8s相关的实战经验,请微信关注“IT运维图谱”公众号或着通过微信搜一搜关注公众号。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐