当前位置 : 主页 > 操作系统 > centos >

K8S-数据持久化PV、PVC、StorageClass的关系

来源:互联网 收集:自由互联 发布时间:2022-06-30
一、引言 在使用K8S时总绕不开的话题就是K8S持久化存储,要实现持久化数据,就要把数据存储到硬盘上。在K8S持久化的过程中会有许多的概念PV、PVC、StorageClass、Provisioner等等。我只想

一、引言

在使用K8S时总绕不开的话题就是K8S持久化存储,要实现持久化数据,就要把数据存储到硬盘上。在K8S持久化的过程中会有许多的概念PV、PVC、StorageClass、Provisioner等等。我只想存储一个文件有么有简单的方式呢?答案是有的。

K8S环境下,Container 中的文件在磁盘上是临时存放的,当容器崩溃时文件丢失。kubelet 会重新启动容器, 但容器会以干净的状态重启。所以我们要使用 Volume 来持久化数据。

Docker 也有 卷(Volume) 的概念,但对它只有少量且松散的管理。 Docker 卷是磁盘上或者另外一个容器内的一个目录 Docker 提供卷驱动程序,但是其功能非常有限。

Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。

临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁 持久卷。对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。

卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放 的内容。


使用卷时,在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。 各个卷则挂载在镜像内的指定路径上。 卷不能挂载到其他卷之上,也不能与其他卷有硬链接。Pod 配置中的每个容器必须独立指定各个卷的挂载位置。

二、K8S存储的分类

2.1、Emptydir---临时存储

当pod的存储方案设定为emptydir的时候,pod启动时,就会在pod所在节点的磁盘空间开辟出一块空卷,最开始里面是什么都没有的,pod启动后容器产生的数据会存放到那个空卷中。空卷变成了一个临时卷供pod内的容器读取和写入数据,一旦pod容器消失,节点上开辟出的这个临时卷就会随着pod的销毁而销毁。

Emptydir的用途

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
  • emptyDir配置示例

    Go
    [root@k8s-master emptydir]# cat emptydir.yaml
    apiVersion: v1
    kind: Pod
    metadata:
    name: test-pd
    spec:
    containers:
    - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /usr/share/nginx/html
    name: cache-volume
    volumes:
    - name: cache-volume
    emptyDir: {}

    创建和验证

    Go
    [root@k8s-master emptydir]# kubectl apply -f emptydir.yaml
    pod/test-pd created
    [root@k8s-master emptydir]# kubectl get pod -owide |grep test-pd
    test-pd 1/1 Running 0 29s 10.244.2.172 k8s-node2 <none> <none>

    #1、在K8S-node2上进行操作
    [root@k8s-node2 cache-volume]# docker ps -a|grep test-pd
    ec7a0faec6bb nginx "/docker-entrypoint.…" 3 minutes ago Up 3 minutes k8s_test-container_test-pd_default_0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae_0

    #2、查看容器的详细信息
    [root@k8s-node2 ~]# docker inspect f87f032bbaf8
    ....
    "Mounts": [
    {
    "Type": "bind",
    "Source": "/home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume",
    "Destination": "/usr/share/nginx/html",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
    },
    ......
    ###Source是宿主机的地址
    ###Destination是挂载到容器的地址

    #3、进入宿主机的目录并创建文件
    [root@k8s-node2 cache-volume]# ls /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume
    [root@k8s-node2 cache-volume]# cd /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume
    [root@k8s-node2 cache-volume]# echo date > index.html
    [root@k8s-node2 cache-volume]# cat index.html
    date
    ##访问该pod的IP地址
    [root@k8s-node2 cache-volume]# curl 10.244.2.173
    date
    [root@k8s-node2 cache-volume]# date > index.html
    [root@k8s-node2 cache-volume]# curl 10.244.2.173
    Sun Jun 5 17:02:30 CST 2022
    ###创建其他的访问文件
    [root@k8s-node2 cache-volume]# echo 2022-06-05 > test.html
    [root@k8s-node2 cache-volume]# curl 10.244.2.173/test.html
    2022-06-05

    #4、删除对应的pod清除实验。
    [root@k8s-master emptydir]# kubectl delete -f emptydir.yaml
    pod "test-pd" deleted
    ###再次在node2计算节点上查看
    [root@k8s-node2 cache-volume]# ls /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume
    ls: cannot access /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume: No such file or directory
    #emptydir是随pod创建而创建,然后再随pod删除而删除

    2.2、hostPath

    hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中, 虽然这不是大多数 Pod 需要的,但是它为一些应用程序提供了强大的逃生舱。

    hostPath的用途

  • 运行一个需要访问 Docker 内部机制的容器;可使用 hostPath 挂载/var/lib/docker 路径。
  • 在容器中运行 cAdvisor 时,以 hostPath 方式挂载/sys
  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。
  • Type的值

    除了必需的path 属性之外,用户可以选择性地为hostPath 卷指定type

    支持的type 值如下:

    取值

    行为

    空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。

    DirectoryOrCreate

    如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。

    Directory

    在给定路径上必须存在的目录。

    FileOrCreate

    如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。

    File

    在给定路径上必须存在的文件。

    Socket

    在给定路径上必须存在的 UNIX 套接字。

    CharDevice

    在给定路径上必须存在的字符设备。

    BlockDevice

    在给定路径上必须存在的块设备。

    hostPath配置示例

    Go
    [root@k8s-master hostpath]# cat hostpath.yaml
    apiVersion: v1
    kind: Pod
    metadata:
    name: test-pd
    spec:
    containers:
    - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /usr/share/nginx/html
    name: test-hostpath
    volumes:
    - name: test-hostpath
    hostPath:
    path: /data
    type: DirectoryOrCreate

    创建和配置示例

    Go
    #1、创建pod
    [root@k8s-master hostpath]# kubectl apply -f hostpath.yaml
    pod/test-pd created
    [root@k8s-master hostpath]# kubectl get pod -owide|grep test-pd
    test-pd 1/1 Running 0 6m54s 10.244.2.174 k8s-node2 <none> <none>
    #2、在K8S-node2节点上查看内部
    [root@k8s-node2 data]# docker ps -a|grep test-container
    b4ff1de7e371 nginx "/docker-entrypoint.…" 8 minutes ago Up 8 minutes k8s_test-container_test-pd_default_e48b2791-54d6-40d6-bc77-56328ca4c038_0
    [root@k8s-node2 data]# docker inspect b4ff1de7e371
    [
    ....
    "Mounts": [
    {
    "Type": "bind",
    "Source": "/data",
    "Destination": "/usr/share/nginx/html",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
    },

    ....
    ]
    ##"Source": "/data", # 宿主机的目录
    ## "Destination": "/usr/share/nginx/html", # 容器中的目录

    #3、在master节点上进入pod
    [root@k8s-master hostpath]# kubectl exec -it pod/test-pd /bin/bash
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    root@test-pd:/# cd /usr/share/nginx/html
    root@test-pd:/usr/share/nginx/html# ls
    index.html

    root@test-pd:/usr/share/nginx/html# echo date >> index.html
    root@test-pd:/usr/share/nginx/html# cat index.html
    Sun Jun 5 17:23:17 CST 2022 test hostpath
    date
    [root@k8s-master hostpath]# curl 10.244.2.174
    Sun Jun 5 17:23:17 CST 2022 test hostpath
    date

    #4、删除pod
    [root@k8s-master hostpath]# kubectl delete -f hostpath.yaml
    pod "test-pd" deleted
    [root@k8s-master hostpath]# kubectl delete -f hostpath.yaml
    Error from server (NotFound): error when deleting "hostpath.yaml": pods "test-pd" not found

    #5、重启创建pod
    [root@k8s-master hostpath]# kubectl apply -f hostpath.yaml
    pod/test-pd created
    [root@k8s-master hostpath]# kubectl get pod -owide|grep test-pd
    test-pd 1/1 Running 0 63s 10.244.2.175 k8s-node2 <none> <none>
    [root@k8s-master hostpath]# curl 10.244.2.175
    Sun Jun 5 17:23:17 CST 2022 test hostpath
    date

    ###这种方式如果宿主机一直在的话,或者该pod一直被调度到该节点的话,可以实现pod的存储,如果该node停机维护或其他
    问题,该数据就无法保持了。

    2.3、pv、pvc

    既然Host类型的持久化存储无法解决节点宕机或者pod在另外的机器上拉起导致数据无法恢复的Bug,那我们就应该思考一个问题:既然我无法在宿主机持久化,那我在集群之外的服务器上存储数据,让我的Pod关联到这个数据存储服务器上,同时我对这个数据存储服务器做高可用,岂不美哉? 想法很好,那我们来介绍一下K8S给我们的解决方案: PersistentVolumes 简称PV

  • PV(PersistentVolume): 持久化卷。PV 是对底层共享存储的一种抽象,由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS、hostPath 等,都是通过插件机制完成与共享存储的对接。
  • PVC(PersistentVolumeClaim): 持久化卷声明。PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
  • hostpath创建pv、pvc

    Go
    #1、创建pv
    [root@k8s-master volumes]# cat pv.yaml
    apiVersion: v1
    kind: PersistentVolume
    metadata:
    name: nginx-pv-volume
    labels:
    type: local
    spec:
    storageClassName: manual-nginx
    capacity:
    storage: 5Gi
    accessModes:
    - ReadWriteOnce
    hostPath:
    path: "/home/nfs"

    [root@k8s-master volumes]# kubectl apply -f pv.yaml
    persistentvolume/nginx-pv-volume created
    [root@k8s-master ~]# kubectl get pv -owide
    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
    nginx-pv-volume 5Gi RWO Retain Available manual-nginx 10s Filesystem

    ##可以看到这个PV为10G,访问模式为RWO,卸载后保留,目前的STATUS为可用状态。

    #2、创建pvc
    [root@k8s-master volumes]# kubectl apply -f pvc.yaml
    persistentvolumeclaim/nginx-pv-claim created
    [root@k8s-master volumes]# cat pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: nginx-pv-claim
    spec:
    storageClassName: manual-nginx
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: 3Gi
    [root@k8s-master volumes]# kubectl get pv,pvc -owide|grep pv-claim
    persistentvolume/nginx-pv-volume 5Gi RWO Retain Bound default/nginx-pv-claim manual-nginx 5m54s Filesystem
    persistentvolumeclaim/nginx-pv-claim Bound nginx-pv-volume 5Gi RWO manual-nginx 97s Filesystem

    3、创建pod
    [root@k8s-master volumes]# cat pvc-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
    name: task-pv-pod
    spec:
    volumes:
    - name: nginx-pv-volume
    persistentVolumeClaim:
    claimName: nginx-pv-claim
    containers:
    - name: task-pv-container
    image: nginx:1.7.9
    ports:
    - containerPort: 80
    name: "http-server"
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
    name: nginx-pv-volume
    nodeSelector:
    kubernetes.io/hostname: k8s-node6
    [root@k8s-master volumes]# kubectl apply -f pvc-pod.yaml
    pod/task-pv-pod created
    [root@k8s-master volumes]# kubectl get pod -owide|grep task-pv-pod
    task-pv-pod 1/1 Running 0 20s 10.244.4.117 k8s-node6 <none> <none>

    #3、在k8s-node3中执行
    [root@k8s-node6 ~]# hostname > /home/nfs/index.html
    [root@k8s-node6 ~]# curl 10.244.4.117
    k8s-node6

    NFS创建pv pvc

    大多数情况下,持久化 Volume 的实现,往往依赖于一个远程存储服务,比如:远程文件存储(比如,NFS、GlusterFS)、远程块存储(比如,公有云提供的远程磁盘)等等。

    Go
    1、搭建nfs服务器
    yum -y install nfs-utils rpcbind
    [root@k8s-master ~]# vim /etc/exports
    /data/k8s *(rw,sync,no_root_squash)
    [root@k8s-master ~]# systemctl enable rpcbind
    [root@k8s-master ~]# systemctl start rpcbind
    [root@k8s-master ~]# systemctl status rpcbind
    ####在启动nfs
    [root@k8s-master ~]# systemctl enable nfs
    Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
    [root@k8s-master ~]# systemctl start nfs
    [root@k8s-master ~]# systemctl status nfs

    客户端挂在
    [root@k8s-node1 ~]# mkdir /data/k8s/ -p
    [root@k8s-node1 ~]# mount -t nfs 172.16.4.169:/data/k8s /data/k8s

    2、创建pv和pvc
    [root@k8s-master volumes]# kubectl apply -f nfs-pv.yaml
    persistentvolume/nginx-nfs-pv created
    [root@k8s-master volumes]# cat nfs-pv.yaml
    apiVersion: v1
    kind: PersistentVolume # 类型为PV
    metadata:
    name: nginx-nfs-pv # pv的名称
    spec:
    accessModes: # 访问模式
    - ReadWriteMany # PV以read-write挂载到多个节点
    capacity: # 容量
    storage: 2Gi # pv可用的大小
    nfs:
    path: /home/k8s/nfs # NFS的路径
    server: 172.16.4.169 # NFS服务器地址


    ##创建pvc
    [root@k8s-master volumes]# cat nfs-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim # 类型
    metadata:
    name: nginx-nfs-pvc # PVC的名称
    spec:
    accessModes: # 访问模式
    - ReadWriteMany # PVC以read-write挂载到多个节点
    resources:
    requests:
    storage: 2Gi # PVC允许申请的大小
    [root@k8s-master volumes]# kubectl apply -f nfs-pvc.yaml
    persistentvolumeclaim/nginx-nfs-pvc created
    [root@k8s-master ~]# kubectl get pv,pvc -owide|grep nfs
    persistentvolume/nginx-nfs-pv 2Gi RWX Retain Bound default/nginx-nfs-pvc 4m37s Filesystem
    persistentvolumeclaim/nginx-nfs-pvc Bound nginx-nfs-pv 2Gi RWX 53s Filesystem


    ##c创建pod
    [root@k8s-master volumes]# cat nfs-pod.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: nginx-nfs-pvc
    spec:
    selector:
    matchLabels:
    app: nginx-pvc
    template:
    metadata:
    labels:
    app: nginx-pvc
    spec:
    containers:
    - name: nginx-test-pvc
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: web-port
    containerPort: 80
    protocol: TCP
    volumeMounts:
    - name: nginx-persistent-storage # 取个名字,与下面的volumes的名字要一致
    mountPath: /usr/share/nginx/html # 容器中的路径
    volumes:
    - name: nginx-persistent-storage
    persistentVolumeClaim:
    claimName: nginx-nfs-pvc # 引用前面声明的PVC


    [root@k8s-master volumes]# kubectl apply -f nfs-pod.yaml
    deployment.apps/nginx-nfs-pvc created
    [root@k8s-master volumes]# kubectl get pod -owide|grep nfs
    nginx-nfs-pvc-577dbd6d5-jsjqf 1/1 Running 0 2m32s 10.244.2.183 k8s-node2 <none> <none>
    [root@k8s-master volumes]# curl 10.244.2.183
    Thu May 12 19:26:48 CST 2022
    this is mater


    4、回收的顺序为:先删除pod,在删除pvc,查看pv的时候pv的状态为:Released ,如果变为avaiable,
    则需要删除claimRef:字段下的所有配置。

    2.4、StorageClass

    创建PV有两种方式:一种是人工管理 PV 的方式就叫作 Static Provisioning;另一种是Dynamic Provisioning动态创建存储卷,动态供给的关键就是StorageClass,它的作用就是创建PV模板,Provision意为”提供者。


    创建StorageClass里面需要定义PV属性比如存储类型、大小等;另外创建这种PV需要用到存储插件。最终效果是,用户提交PVC,里面指定存储类型,如果符合我们定义的StorageClass,则会为其自动创建PV并进行绑定。

    什么是StorageClass

    StorageClass 为管理员提供了描述存储 "class(类)" 的方法。 不同的 class 可能会映射到不同的服务质量等级或备份策略,或由群集管理员确定的任意策略。

    Kubernetes提供了一套可以自动创建PV的机制,即:Dynamic Provisioning。而这个机制的核心在于StorageClass这个API对象。

    StorageClass对象会定义下面两部分内容:

  • PV的属性。比如,存储类型,Volume的大小等。
  • 创建这种PV需要用到的存储插件,即存储制备器,比如,Ceph 等等。
  • 有了这两个信息之后,Kubernetes就能够根据用户提交的PVC,找到一个对应的StorageClass,之后Kubernetes就会调用该StorageClass声明的存储插件,进而创建出需要的PV。

    StorageClass 为管理员提供了描述存储 “类” 的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为 “配置文件”。

    StorageClass的功能

    StorageClass 的作用,则是充当 PV 的模板。并且,只有同属于一个 StorageClass 的 PV 和 PVC,才可以绑定在一起。StorageClass 的另一个重要作用,是指定 PV 的 Provisioner(存储插件)。这时候,如果你的存储插件支持 Dynamic Provisioning 的话,Kubernetes 就可以自动为你创建 PV 了。

    通过StorageClass创建pv和pvc例子

    Go
    1、创建pvc和storageclass的yaml文件
    [root@k8s-master storageclass]# cat storageclass-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: storageclass-claim1
    spec:
    accessModes:
    - ReadWriteOnce
    # 指定所使用的存储类,此存储类将会自动创建符合要求的 PV
    storageClassName: fast
    resources:
    requests:
    storage: 30Gi

    ---
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
    name: fast
    provisioner: kubernetes.io/gce-pd
    parameters:
    type: pd-ssd

    [root@k8s-master storageclass]# kubectl apply -f storageclass-pvc.yaml
    persistentvolumeclaim/storageclass-claim1 created
    storageclass.storage.k8s.io/fast created

    2、查看该pvc处于pending原因,由于没有没有gce插件
    [root@k8s-master storageclass]# kubectl describe persistentvolumeclaim/storageclass-claim1
    Name: storageclass-claim1
    Namespace: default
    StorageClass: fast
    Status: Pending
    Volume:
    Labels: <none>
    Annotations: volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/gce-pd
    Finalizers: [kubernetes.io/pvc-protection]
    Capacity:
    Access Modes:
    VolumeMode: Filesystem
    Used By: <none>
    Events:
    Type Reason Age From Message
    ---- ------ ---- ---- -------
    Warning ProvisioningFailed 14m persistentvolume-controller storageclass.storage.k8s.io "fast" not found
    Warning ProvisioningFailed 68s (x10 over 13m) persistentvolume-controller Failed to provision volume with StorageClass "fast": failed to get GCE GCECloudProvider with error <nil>

    StorageClass 的作用,则是充当 PV 的模板。并且,只有同属于一个 StorageClass 的 PV 和 PVC,才可以绑定在一起。StorageClass 的另一个重要作用,是指定 PV 的 Provisioner(存储插件)。这时候,如果你的存储插件支持 Dynamic Provisioning 的话,Kubernetes 就可以自动为你创建 PV 了。

    2.5、Local PV(local-volume-provisioner)

    Kubernetes 依靠 PV、PVC 实现了一个新的特性,这个特性的名字叫作:Local Persistent Volume,也就是 Local PV。

    Local PV 实现的功能就非常类似于 hostPath 加上 nodeAffinity,比如,一个 Pod 可以声明使用类型为 Local 的 PV,而这个 PV 其实就是一个 hostPath 类型的 Volume。如果这个 hostPath 对应的目录,已经在节点 A 上被事先创建好了,那么,我只需要再给这个 Pod 加上一个 nodeAffinity=nodeA,不就可以使用这个 Volume 了吗?理论上确实是可行的,但是事实上,我们绝不应该把一个宿主机上的目录当作 PV 来使用,因为本地目录的存储行为是完全不可控,它所在的磁盘随时都可能被应用写满,甚至造成整个宿主机宕机。所以,一般来说 Local PV 对应的存储介质是一块额外在挂载在宿主机的磁盘或者块设备,我们可以认为就是“一个 PV 一块盘”

    local-volume-provisioner创建local PV

    3.1、准备本地存储

    Go
    ##依次在K8S的各个计算节点依次执行
    1、创建对应的目录
    mkdir /home/data/{data1,data2,data3}
    2、依次挂载对应的节点
    mount --bind /home/data/data1/ /home/data/data1/
    mount --bind /home/data/data2/ /home/data/data2/
    mount --bind /home/data/data3/ /home/data/data3/
    3、把相关的配置信息写道/etc/fstab
    echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data1 ext4 defaults 0 2 | sudo tee -a /etc/fstab
    echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data2 ext4 defaults 0 2 | sudo tee -a /etc/fstab
    echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data3 ext4 defaults 0 2 | sudo tee -a /etc/fstab
    ###
    上述的/home/data/data1、/home/data/data2、/home/data/data13是 local-volume-provisioner
    使用的发现目录(discovery directory),local-volume-provisioner 会为发现目录下的每一个
    子目录创建对应的 PV

    3.2、下载和配置 local-volume-provisioner

    Go
    1、下载
    wget https://raw.githubusercontent.com/pingcap/tidb-operator/master/examples/local-pv/local-volume-provisioner.yaml

    2、修改不同的路径。如果你使用与上一步中不同路径的发现目录,需要修改 ConfigMap 和 DaemonSet 定义。
    #cat local-volume-provisioner.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
    name: "local-storage"
    provisioner: "kubernetes.io/no-provisioner"
    volumeBindingMode: "WaitForFirstConsumer"
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: local-provisioner-config
    namespace: kube-system
    data:
    setPVOwnerRef: "true"
    nodeLabelsForPV: |
    - kubernetes.io/hostname
    storageClassMap: |
    local-storage:
    hostDir: /home/data
    mountDir: /data
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
    name: local-volume-provisioner
    namespace: kube-system
    labels:
    app: local-volume-provisioner
    spec:
    selector:
    matchLabels:
    app: local-volume-provisioner
    template:
    metadata:
    labels:
    app: local-volume-provisioner
    spec:
    serviceAccountName: local-storage-admin
    containers:
    - image: "quay.io/external_storage/local-volume-provisioner:v2.3.4"
    name: provisioner
    securityContext:
    privileged: true
    env:
    - name: MY_NODE_NAME
    valueFrom:
    fieldRef:
    fieldPath: spec.nodeName
    - name: MY_NAMESPACE
    valueFrom:
    fieldRef:
    fieldPath: metadata.namespace
    - name: JOB_CONTAINER_IMAGE
    value: "quay.io/external_storage/local-volume-provisioner:v2.3.4"
    resources:
    requests:
    cpu: 100m
    memory: 100Mi
    limits:
    cpu: 100m
    memory: 100Mi
    volumeMounts:
    - mountPath: /etc/provisioner/config
    name: provisioner-config
    readOnly: true
    - mountPath: /data
    name: local-disks
    mountPropagation: "HostToContainer"
    volumes:
    - name: provisioner-config
    configMap:
    name: local-provisioner-config
    - name: local-disks
    hostPath:
    path: /home/data
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: local-storage-admin
    namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: local-storage-provisioner-pv-binding
    namespace: kube-system
    subjects:
    - kind: ServiceAccount
    name: local-storage-admin
    namespace: kube-system
    roleRef:
    kind: ClusterRole
    name: system:persistent-volume-provisioner
    apiGroup: rbac.authorization.k8s.io
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    name: local-storage-provisioner-node-clusterrole
    namespace: kube-system
    rules:
    - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: local-storage-provisioner-node-binding
    namespace: kube-system
    subjects:
    - kind: ServiceAccount
    name: local-storage-admin
    namespace: kube-system
    roleRef:
    kind: ClusterRole
    name: local-storage-provisioner-node-clusterrole
    apiGroup: rbac.authorization.k8s.io

    如果你使用与上一步中不同路径的发现目录,需要修改 ConfigMap 和 DaemonSet 定义。

    3.3、部署和检查 local-volume-provisioner 程序

    Go
    1、部署
    [root@k8s-master tidb]# kubectl apply -f local-volume-provisioner.yaml
    storageclass.storage.k8s.io/local-storage unchanged
    configmap/local-provisioner-config unchanged
    daemonset.apps/local-volume-provisioner unchanged
    serviceaccount/local-storage-admin unchanged
    clusterrolebinding.rbac.authorization.k8s.io/local-storage-provisioner-pv-binding unchanged
    clusterrole.rbac.authorization.k8s.io/local-storage-provisioner-node-clusterrole unchanged
    clusterrolebinding.rbac.authorization.k8s.io/local-storage-provisioner-node-binding unchanged

    2、检查pv和pod状态
    [root@k8s-master tidb]# kubectl get po -n kube-system -l app=local-volume-provisioner && kubectl get pv
    NAME READY STATUS RESTARTS AGE
    local-volume-provisioner-9gp9x 1/1 Running 0 29h
    local-volume-provisioner-kghc7 1/1 Running 0 29h
    local-volume-provisioner-v2vvt 1/1 Running 0 29h
    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    local-pv-264b0ff0 446Gi RWO Delete Available local-storage 62m
    local-pv-27bc7b00 446Gi RWO Delete Available local-storage 62m
    local-pv-4653df42 446Gi RWO Delete Available local-storage 62m
    local-pv-993f4e47 446Gi RWO Delete Available local-storage 62m
    local-pv-ad7b1fa4 446Gi RWO Delete Available local-storage 62m
    local-pv-b9e5d531 446Gi RWO Delete Available local-storage 62m
    local-pv-bfe87b7 446Gi RWO Delete Available local-storage 62m
    local-pv-dc8fa7ee 446Gi RWO Delete Available local-storage 62m
    local-pv-f12d96bb 446Gi RWO Delete Available local-storage 62m


    三、总结

    本文讨论了 k8s 存储的几种常见的存储类型类型,有临时存储如:hostPath、emptyDir。也有真正的持久化存储,还讨论了相关的概念,如:PVC、PV、StorageClass等,下图是对这些概念的一个概括:

    K8S-数据持久化PV、PVC、StorageClass的关系_html


    K8S-数据持久化PV、PVC、StorageClass的关系_docker_02

    K8S-数据持久化PV、PVC、StorageClass的关系_html_03


    上一篇:##Kibana+ELK集群日志处理
    下一篇:没有了
    网友评论