0
点赞
收藏
分享

微信扫一扫

深入剖析Kubernetes--第六章: 深入理解本地持久化数据卷

老罗话编程 2022-03-16 阅读 66
kubernetes

深入理解本地持久化数据卷

使用 Local Persistent Volume 的应用必须具备数据备份和恢复的能力,允许把这些数据定时备份在其他位置。

Local Persistent Volume 的设计,主要面临两个难点

第一、把本地磁盘抽象成 PV:

一个 Local Persistent Volume 对应的存储介质,一定是一块额外挂载在宿主机的磁盘或者块设备(“额外”的意思是,它不应该是宿主机根目录所使用的主硬盘)。

第二、保证 Pod 始终能被正确地调度到它所请求的 Local Persistent Volume 所在的节点上

对于常规的 PV 来说,Kubernetes 都是先调度 Pod 到某个节点上,然后,再通过“两阶段处理”来“持久化”这台机器上的 Volume 目录,进而完成 Volume 目录与容器的绑定挂载。

在调度的时候考虑 Volume 分布

对于 Local PV 来说,,节点上可以使用的磁盘是提前准备好的,因此调度器必须知道所有节点与 Local Persistent Volume 对应的磁盘的关联关系,然后根据这个信息来调度 Pod。(VolumeBindingChecker 的过滤条件专门负责这个事情)

在自己部署的私有环境中,有两种办法来完成在集群里提前配置好磁盘。

  • 第一种,给宿主机挂载并格式化一个可用的本地磁盘
  • 第二种,对于实验环境,可以在宿主机上挂载几个 RAM Disk(内存盘)来模拟本地磁盘

展开第二种:

在名叫 node2 的宿主机上创建一个挂载点,比如 /mnt/disks;然后,用几个 RAM Disk 来模拟本地磁盘

tmpfs:

临时性:由于tmpfs是构建在内存中的,存放在 tmpfs 中的所有数据在卸载或断电后都会丢失
快速读写能力:内存的访问速度要远快于磁盘I/O操作,即使使用了swap,性能仍然非常卓越

# 在 node2 上执行
$ mkdir /mnt/disks
$ for vol in vol1 vol2 vol3; do
    mkdir /mnt/disks/$vol
    mount -t tmpfs $vol /mnt/disks/$vol
done

接下来,为这些本地磁盘定义对应的 PV :

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/vol1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node2

local 字段,指定了它是一个 Local Persistent Volume

path 字段,指定的正是这个 PV 对应的本地磁盘的路径,即:/mnt/disks/vol1

如果 Pod 要想使用这个 PV,那它就必须运行在 node2 上。所以,在这个 PV 的定义里,需要有一个 nodeAffinity 字段指定 node2 这个节点的名字。这样,调度器在调度 Pod 的时候,就能够知道一个 PV 与节点的对应关系,从而做出正确的选择。这正是 Kubernetes 实现“在调度的时候就考虑 Volume 分布”的主要方法

创建PV:

$ kubectl create -f local-pv.yaml 
persistentvolume/example-pv created

$ kubectl get pv

NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM         STORAGECLASS    REASON   AGE
example-pv   1Gi        RWO            Delete           Available             local-storage            8s

使用 PV 和 PVC 的最佳实践,要创建一个 StorageClass 来描述这个 PV,如下所示:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

这个 StorageClass 的名字,叫作 local-storage

它的 provisioner 字段,我们指定的是 no-provisioner(Local Persistent Volume 目前尚不支持 Dynamic)

volumeBindingMode=WaitForFirstConsumer 的属性:延迟绑定

延迟绑定

等到第一个声明使用该 PVC 的 Pod 出现在调度器之后,调度器再综合考虑所有的调度规则,当然也包括每个 PV 所在的节点位置,来统一决定,这个 Pod 声明的 PVC,到底应该跟哪个 PV 进行绑定

通过这个延迟绑定机制,原本实时发生的 PVC 和 PV 的绑定过程,就被延迟到了 Pod 第一次调度的时候在调度器中进行,从而保证了这个绑定结果不会影响 Pod 的正常调度

创建 StorageClass ,如下所示:

$ kubectl create -f local-sc.yaml 
storageclass.storage.k8s.io/local-storage created

接下来,定义一个PVC,就可以让 Pod 使用到上面定义好的 Local Persistent Volume 了,如下所示:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: example-local-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-storage

它声明的 storageClassName 是 local-storage。Kubernetes 的 Volume Controller 看到这个 PVC 的时候,不会为它进行绑定操作。

创建这个 PVC:

$ kubectl create -f local-pvc.yaml 
persistentvolumeclaim/example-local-claim created

$ kubectl get pvc
NAME                  STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
example-local-claim   Pending                                      local-storage   10s

可以看到,此时Kubernetes 里已经存在了一个可以与 PVC 匹配的 PV,但这个 PVC 依然处于 Pending 状态,也就是等待绑定的状态

然后,我们编写一个 Pod 来声明使用这个 PVC,如下所示:

kind: Pod
apiVersion: v1
metadata:
  name: example-pv-pod
spec:
  volumes:
    - name: example-pv-storage
      persistentVolumeClaim:
       claimName: example-local-claim
  containers:
    - name: example-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: example-pv-storage

这个 Pod 没有任何特别的地方,你只需要注意,它的 volumes 字段声明要使用前面定义的、名叫 example-local-claim 的 PVC 即可。

而我们一旦使用 kubectl create 创建这个 Pod,就会发现,我们前面定义的 PVC,会立刻变成 Bound 状态,与前面定义的 PV 绑定在了一起,如下所示:

$ kubectl create -f local-pod.yaml 
pod/example-pv-pod created

$ kubectl get pvc
NAME                  STATUS    VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS    AGE
example-local-claim   Bound     example-pv   1Gi        RWO            local-storage   2m15s

也就是说,在我们创建的 Pod 进入调度器之后,“绑定”操作才开始进行。

需要注意的是,我们上面手动创建 PV 的方式,即 Static 的 PV 管理方式,在删除 PV 时需要按如下流程执行操作:

  1. 删除使用这个 PV 的 Pod;
  2. 从宿主机移除本地磁盘(比如,umount 它);
  3. 删除 PVC;
  4. 删除 PV。

如果不按照这个流程的话,这个 PV 的删除就会失败。

当然,由于上面这些创建 PV 和删除 PV 的操作比较繁琐,Kubernetes 其实提供了一个 Static Provisioner 来帮助你管理这些 PV。

思考题

正是由于需要使用“延迟绑定”这个特性,Local Persistent Volume 目前还不能支持 Dynamic Provisioning。你是否能说出,为什么“延迟绑定”会跟 Dynamic Provisioning 有冲突呢?

举报

相关推荐

深入理解JVM第六章笔记

第六章 容器

第六章:接口

第六章总结

PTA第六章

第六章 BOM

0 条评论