当前位置: 代码网 > 服务器>服务器>云虚拟主机 > Kubernetes存储系统数据持久化管理详解

Kubernetes存储系统数据持久化管理详解

2024年05月19日 云虚拟主机 我要评论
引言kubernetes为了能更好的支持有状态应用的数据存储问题,除了基本的hostpath和emptydir提供的数据持久化方案之外,还提供了pv,pvc和storageclass资源对象来对存储进

引言

kubernetes为了能更好的支持有状态应用的数据存储问题,除了基本的hostpath和emptydir提供的数据持久化方案之外,还提供了pv,pvc和storageclass资源对象来对存储进行管理。

pv的全称是persistent volume(持久化卷),是对底层数据存储的抽象,pv由管理员创建、维护以及配置,它和底层的数据存储实现方法有关,比如ceph,nfs,clusterfs等,都是通过插件机制完成和共享存储对接。

pvc的全称是persistent volume claim(持久化卷声明),我们可以将pv比喻为接口,里面封装了我们底层的数据存储,pvc就是调用接口实现数据存储操作,pvc消耗的是pv的资源。

storageclass是为了满足用于对存储设备的不同需求,比如快速存储,慢速存储等,通过对storageclass的定义,管理员就可以将存储设备定义为某种资源类型,用户根据storageclass的描述可以非常直观的知道各种存储资源的具体特性,这样就可以根据应用特性去申请合适的资源了。

安装存储系统

存储系统的选择有很多,常见的有nfs、ceph、glusterfs、fastdfs等,具体使用什么根据企业情况而定。在这里使用的是nfs,下面简单介绍一下如何安装。

(1)安装服务

$ yum install nfs-utils rpcbind -y

(2)创建共享目录

$ mkdir /data/k8s -p

(3)配置nfs配置文件

$ vim /etc/exports
/data/k8s *(rw,sync,no_root_squash)

(4)启动服务

$ systemctl start rpcbind
$ systemctl start nfs
$ systemctl enable rpcbind
$ systemctl enable nfs

(5)测试

$ showmount -e 192.168.205.128
export list for 192.168.205.128:
/data/k8s *

ps:所有节点都需要安装nfs客户端

pv

pv(persistent volume)作为kubernetes存储设备,可以由管理员提前配置,也可以通过storageclass来动态供应。

pv是集群资源,可以通过kubectl explain pv来查看如何配置,主要包括存储能力,访问模式,存储类型,回收信息等关键信息。例如:

apiversion: v1
kind: persistentvolume
metadata:
  name: my-pv01
  labels:
    storage: pv
spec:
  accessmodes:
  - readwriteonce
  capacity:
    storage: 1gi
  persistentvolumereclaimpolicy: recycle
  nfs:
    path: /data/k8s
    server: 192.168.205.128

参数说明:

(1)、accessmode:访问模式,有readwriteonce,readonlymany,readwritemany。其中:

  • readwriteonce:表示具有读写权限,但是只能被一个node挂载一次
  • readonlymany:表示具有只读权限,可以被多个node多次挂载
  • readwritemany:表示具有读写权限,可以被多个node多次挂载

(2)、capacity:持久卷资源和容量的描述,存储大小是唯一可设置或请求的资源。

(3)、persistentvolumereclaimpolicy:回收策略,也就是释放持久化卷时的策略,其有以下几种:

  • retain:保留数据,如果要清理需要手动清理数据,默认的策略;
  • delete:删除,将从kubernetes中删除pv对象,以及外部基础设施中相关的存储资产,比如aws ebs, gce pd, azure disk, 或cinder volume;
  • recycle:回收,清楚pv中的所有数据,相当于执行rm -rf /pv-volume/*;

创建过后,pv的状态如下:

$ kubectl get pv
name      capacity   access modes   reclaim policy   status      claim   storageclass   reason   age
my-pv01   1gi        rwo            recycle          available                                   5s
$ kubectl describe pv my-pv01 
name:            my-pv01
labels:          storage=pv
annotations:     <none>
finalizers:      [kubernetes.io/pv-protection]
storageclass:    
status:          available
claim:           
reclaim policy:  recycle
access modes:    rwo
volumemode:      filesystem
capacity:        1gi
node affinity:   <none>
message:         
source:
    type:      nfs (an nfs mount that lasts the lifetime of a pod)
    server:    192.168.205.128
    path:      /data/k8s
    readonly:  false
events:        <none>

当前pv的状态是available,表示处于随时可用状态。pv总共有以下四种状态:

  • available(可用):表示可用状态,还未被任何 pvc 绑定
  • bound(已绑定):表示 pvc 已经被 pvc 绑定
  • released(已释放):pvc 被删除,但是资源还未被集群重新声明
  • failed(失败):表示该 pv 的自动回收失败

单纯的创建pv,我们并不能直接使用,需要使用pvc(persistent volume claim)来进行声明。

pvc

pvc(persistent volume claim)用于表达用户对存储的需求,申请pvc会消耗掉pv的资源,可以通过kubectl explain pvc来查看帮助文档。

在上一节我们创建了pv,现在要申明pvc,如下:

apiversion: v1
kind: persistentvolumeclaim
metadata:
  name: pvc-test
spec:
  accessmodes:
  - readwriteonce
  resources:
    requests:
      storage: 1gi

spec参数说明:

(1)、accessmodes:主要定义卷所应该拥有的访问模式

(2)、resources:主要定义卷应该拥有的最小资源

(3)、datasource:定义如果提供者具有卷快照功能,就会创建卷,并将数据恢复到卷中,反之不创建

(4)、selector:定义绑定卷的标签查询

(5)、storageclassname:定义的storageclass的名字

(6)、volumemode:定义卷的类型

(7)、volumename:需要绑定的pv的名称链接

创建过后,查看pv和pvc的状态,如下:

$ kubectl get pvc
name       status   volume    capacity   access modes   storageclass   age
pvc-test   bound    my-pv01   1gi        rwo                           2s
$ kubectl get pv
name      capacity   access modes   reclaim policy   status   claim              storageclass   reason   age
my-pv01   1gi        rwo            recycle          bound    default/pvc-test                           20m

我们从上面可以看到pvc处于bound状态,bound的volume是my-pv01,我们再看pv的状态有available变为bound,其claim是default/pvc-test,其中default为namespace名称。

在上面我们创建了一个pvc,其绑定了我们创建的pv,如果此时我们再创建一个pvc,结果又会如何?我们copy以下上面的pvc文件,将其名称改一下,如下:

apiversion: v1
kind: persistentvolumeclaim
metadata:
  name: pvc-test2
spec:
  accessmodes:
  - readwriteonce
  resources:
    requests:
      storage: 1gi

然后查看pvc的状态,如下

$ kubectl get pvc
name        status    volume    capacity   access modes   storageclass   age
pvc-test    bound     my-pv01   1gi        rwo                           3m57s
pvc-test2   pending                                                      4s

我们可以看到我们刚创建的pvc-test2的status处于pending状态,这是由于集群里声明的pv都使用完了,pvc在申请的时候没有找到合适的pv,所以处于这个状态,这时候如果我们创建一个新的并满足要求的pv,则可以看到这个pvc会处于bound状态。如下:

$ kubectl get pv
name      capacity   access modes   reclaim policy   status      claim              storageclass   reason   age
my-pv01   1gi        rwo            recycle          bound       default/pvc-test                           27m
my-pv02   1gi        rwo            recycle          available                                              5s
$ kubectl get pvc
name        status   volume    capacity   access modes   storageclass   age
pvc-test    bound    my-pv01   1gi        rwo                           6m50s
pvc-test2   bound    my-pv02   1gi        rwo                           2m57s

pvc也在申领pv的时候也不是随意申领的,它需要符合以下要求:

(1)pvc申领的模式要和pv匹配上,假如pvc的模式是readwriteonce,而pv的模式是readwritemany,则申领部成功。

(2)pvc申领的容量要小于等于pv的容量,否则申请不成功。

(3)一个pv只能绑定一个pvc

另外,如果我们的pvc需求的容量小于pv的可用容量,绑定的容量是pv的可用容量。

storageclass

上面介绍的pv和pvc模式是需要运维人员先创建好pv,然后开发人员定义好pvc进行一对一的bond,但是如果pvc请求成千上万,那么就需要创建成千上万的pv,对于运维人员来说维护成本很高,kubernetes提供一种自动创建pv的机制,叫storageclass,它的作用就是创建pv的模板。

具体来说,storageclass会定义一下两部分:

  • pv的属性 ,比如存储的大小、类型等;
  • 创建这种pv需要使用到的存储插件,比如ceph等;

有了这两部分信息,kubernetes就能够根据用户提交的pvc,找到对应的storageclass,然后kubernetes就会调用 storageclass声明的存储插件,创建出需要的pv。

这里我们以nfs为例,要使用nfs,我们就需要一个nfs-client的自动装载程序,我们称之为provisioner,这个程序会使用我们已经配置好的nfs服务器自动创建持久卷,也就是自动帮我们创建pv。说明:

  • 自动创建的pv会以{pvcname}-${pvname}的目录格式放到nfs服务器上;
  • 如果这个pv被回收,则会以archieved-{pvcname}-${pvname}这样的格式存放到nfs服务器上;

安装nfs provisioner

(1)创建serviceaccount,为nfs provisioner授权

---
apiversion: v1
kind: serviceaccount
metadata:
  name: nfs-client-provisioner
---
apiversion: rbac.authorization.k8s.io/v1
kind: clusterrole
metadata:
  name: nfs-client-provisioner-clusterrole
rules:
  - apigroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apigroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apigroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apigroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apigroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
apiversion: rbac.authorization.k8s.io/v1
kind: clusterrolebinding
metadata:
  name: nfs-client-provisioner-clusterrolebinding
subjects:
- kind: serviceaccount
  name: nfs-client-provisioner
  namespace: default
roleref:
  kind: clusterrole
  name: nfs-client-provisioner-clusterrole
  apigroup: rbac.authorization.k8s.io

(2)创建nfs provisioner

---
apiversion: apps/v1 
kind: deployment
metadata:
  name: nfs-client-prosioner
spec:
  replicas: 1
  strategy:
    type: recreate
  selector:
    matchlabels:
      app: nfs-client-prosioner
  template:
    metadata:
      labels:
        app: nfs-client-prosioner
    spec:
      serviceaccountname: nfs-client-provisioner
      containers:
      - name: nfs-client-prosioner
        image: registry.cn-hangzhou.aliyuncs.com/rookieops/nfs-client-provisioner:4.0
        imagepullpolicy: ifnotpresent
        volumemounts:
        - name: nfs-client-root
          mountpath: /data/pv
        env:
        - name: provisioner_name
          value: rookieops/nfs
        - name: nfs_server
          value: 192.168.205.128
        - name: nfs_path
          value: /data/k8s
      volumes:
      - name: nfs-client-root
        nfs:
          server: 192.168.205.128
          path: /data/k8s

执行完成后,查看nfs provisioner的状态,如下:

$ kubectl get po
name                                    ready   status    restarts   age
nfs-client-prosioner-54d64dfc85-b4ht4   1/1     running   0          10s

使用storageclass

上面已经创建好nfs provisioner,现在我们可以直接创建stroageclass,如下:

apiversion: storage.k8s.io/v1
kind: storageclass
metadata:
  name: nfs
provisioner: rookieops/nfs

每个 storageclass 都包含 provisioner、parameters 和 reclaimpolicy 字段, 这些字段会在 storageclass 需要动态分配 persistentvolume 时会使用到。

在配置storageclass的时候,如果没有指定reclaimpolicy,则默认是delete,除此之外,还有retain。

storageclass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。当创建 storageclass 对象时,管理员设置 storageclass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。

使用kubectl apply -f sc.yaml创建storageclass,创建完成过后如下:

$ kubectl get sc
name   provisioner     reclaimpolicy   volumebindingmode   allowvolumeexpansion   age
nfs    rookieops/nfs   delete          immediate           false                  9m41s

现在,我们就可以使用动态存储申领pvc,如下:

apiversion: v1
kind: persistentvolumeclaim
metadata:
  name: pvc-from-sc
spec:
  accessmodes:
    - readwriteonce
  storageclassname: nfs
  resources:
    requests:
      storage: 1gi

使用kubectl apply -f pvc-from-sc.yaml,查看pvc创建情况,如下:

$ kubectl get pvc
name          status   volume                                     capacity   access modes   storageclass   age
pvc-from-sc   bound    pvc-a4a71b8c-5664-4d1a-b286-9e4adcf6f96a   1gi        rwo            nfs            8s
$ kubectl get pv
name                                       capacity   access modes   reclaim policy   status   claim                 storageclass   reason   age
pvc-a4a71b8c-5664-4d1a-b286-9e4adcf6f96a   1gi        rwo            delete           bound    default/pvc-from-sc   nfs                     86s

可以看到自动创建了一个pv,然后和pvc进行绑定。

为了方便使用,有时候会给集群默认设置一个storageclass,以便在需要使用动态存储,但是未声明的情况下使用默认的动态存储。设置方式如下:

$ kubectl patch storageclass nfs -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

通过向其添加 storageclass.kubernetes.io/is-default-class 注解来将特定的 storageclass 标记为默认。当集群中存在默认的 storageclass 并且用户创建了一个未指定 storageclassname 的 persistentvolumeclaim 时, defaultstorageclass 准入控制器会自动向其中添加指向默认存储类的 storageclassname 字段。

请注意,集群上最多只能有一个 默认 存储类,否则无法创建没有明确指定 storageclassname 的 persistentvolumeclaim。

如果要取消默认storageclass,只需要把注解设置为flase即可,如下:

$ kubectl patch storageclass nfs -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

如果我们要在pod中使用pvc,则直接如下声明:

apiversion: v1
kind: pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    imagepullpolicy: ifnotpresent
    volumemounts:
    - name: nfs-pvc
      mountpath: /mnt
  restartpolicy: never
  volumes:
  - name: nfs-pvc
    persistentvolumeclaim:
      claimname: pvc-from-sc

可以进入容器,到挂载目录输出,例如:

$ kubectl exec -it nginx -- /bin/bash
root@nginx:/mnt# echo "test" > /mnt/text.txt

然后到nfs对应的目录查看是否一致。

$ cd /data/k8s/default-pvc-from-sc-pvc-a4a71b8c-5664-4d1a-b286-9e4adcf6f96a
$ cat text.txt 
test

这表示pod使用持久化成功。

总结

在kubernetes中,虽然我们建议使用无状态应用,但是对于有些特殊应用,数据持久化还是必不可少的。数据持久化的难度不在于创建几个pv或者pvc,而是后端的存储系统,比如ceph,如果使用它作为后端存储,你必须对其非常熟悉,方便在出问题的时候好排查,如果你对这些存储系统都不熟悉,在使用的时候可能会出现很多问题。

以上就是kubernetes存储系统数据持久化管理详解的详细内容,更多关于kubernetes数据持久化管理的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com