kubernetes-8-持久化pv/pvc/StorageClass

1 认识PV/PVC/StorageClass

管理存储是管理计算的一个明显问题。该PersistentVolume子系统为用户和管理员提供了一个API,用于抽象如何根据消费方式提供存储的详细信息。为此,我们引入了两个新的API资源:PersistentVolume和PersistentVolumeClaim。

PersistentVolume(PV)是集群中由管理员配置的一段网络存储。它是集群中的资源,就像节点是集群资源一样。PV是容量插件,如Volumes,但其生命周期独立于使用PV的任何单个pod。此API对象捕获存储实现的详细信息,包括NFS,iSCSI或特定于云提供程序的存储系统。

PersistentVolumeClaim(PVC)是由用户进行存储的请求。它类似于pod。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以一次读/写或多次只读)。

虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是PersistentVolumes对于不同的问题,用户通常需要具有不同属性(例如性能)。集群管理员需要能够提供各种PersistentVolumes不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有StorageClass资源

StorageClass为管理员提供了一种描述他们提供的存储的“类”的方法。不同的类可能映射到服务质量级别,或备份策略,或者由集群管理员确定的任意策略。Kubernetes本身对于什么类别代表是不言而喻的。这个概念有时在其他存储系统中称为“配置文件”。

PVC和PV是一一对应的。

1.1 生命周期

PV是群集中的资源。PVC是对这些资源的请求,并且还充当对资源的检查。PV和PVC之间的相互作用遵循以下生命周期:

Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling

(1)供应准备Provisioning
通过集群外的存储系统或者云平台来提供存储持久化支持。
(1-1)静态提供Static:集群管理员创建多个PV。它们携带可供集群用户使用的真实存储的详细信息。它们存在于Kubernetes API中,可用于消费。

(1-2)动态提供Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。要求该类的声明有效地为自己禁用动态配置。
(2)绑定Binding
用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。
(3)使用Using
用户可在pod中像volume一样使用pvc。
(4)释放Releasing
用户删除pvc来回收存储资源,pv将变成“released”状态。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。
(5)回收Recycling
pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
(5-1)保留策略:允许人工处理保留的数据。
(5-2)删除策略:将删除pv和外部关联的存储资源,需要插件支持。
(5-3)回收策略:将执行清除操作,之后可以被新的pvc使用,需要插件支持。

注:目前只有NFS和HostPath类型卷支持回收策略,AWS EBS,GCE PD,Azure Disk和Cinder支持删除(Delete)策略。

1.2 PV类型

在这里插入图片描述

1.3 PV卷阶段状态

(1)Available
资源尚未被claim使用
(2)Bound
卷已经被绑定到claim了
(3)Released
claim被删除,卷处于释放状态,但未被集群回收。
(4)Failed
卷自动回收失败

1.4 pv三种访问方式

https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes。
在Kubenetes体系内,针对每一个持久化存储卷,都有三种访问方式: ReadWriteOnce(RWO), ReadOnlyMany(ROX), ReadWriteMany(RWX)。

在当前的定义中,这三种方式都是针对节点级别的,也就是说,对于一个Persistent Volume, 如果是RWO, 那么只能被挂载在某一个Kubernetes的工作节点(以下简称节点)上,当再次尝试在其他节点挂载的时候,系统会报Multi-Attach的错误(当然,在只有一台可调度节点的情况,即使RWO也是能够被多个Pod同时使用)。

如果是RWX, 那么可以同时在多个节点上挂载并被不同的Pod使用。

在这里插入图片描述
三种访问方式。
在这里插入图片描述

2 演示:创建PV静态提供

(1)在nfs服务器上先建立存储卷对应的目录

cd /data/volumes
mkdir v{1,2,3,4,5}
echo "<h1>static stor 01</h1>" > v1/index.html
echo "<h1>static stor 02</h1>" > v2/index.html
echo "<h1>static stor 03</h1>" > v3/index.html
echo "<h1>static stor 04</h1>" > v4/index.html
echo "<h1>static stor 05</h1>" > v5/index.html

(2)修改nfs的配置
#vim /etc/exports

/data/volumes/v1        *(rw,no_root_squash)
/data/volumes/v2        *(rw,no_root_squash)
/data/volumes/v3        *(rw,no_root_squash)
/data/volumes/v4        *(rw,no_root_squash)
/data/volumes/v5        *(rw,no_root_squash)

其中,rw:读/写权限,只读权限的参数为ro;
其中,no_root_squash:NFS 服务器共享目录用户的属性,如果用户是 root,那么对于这个共享目录来说就具有 root 的权限。
(3)查看nfs的配置
#exportfs -arv
在这里插入图片描述

(4)使配置生效
#showmount -e

2.1 创建持久卷pv

创建5个pv,存储大小各不相同,是否可读也不相同。pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:
    path: /data/volumes/v1
    server: myuse1
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  storageClassName: slow
  capacity:
    storage: 5Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2
    server: myuse2
  accessModes: ["ReadWriteOnce"]
  storageClassName: slow
  capacity:
    storage: 5Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: myuse3
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  storageClassName: slow
  capacity:
    storage: 5Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4
    server: myuse4
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  storageClassName: slow
  capacity:
    storage: 10Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5
    server: myuse5
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  storageClassName: slow
  capacity:
    storage: 15Gi

#kubectl apply -f pv.yaml
#kubectl get pv
在这里插入图片描述

#kubectl delete pv pv001删除指定pv
(1)回收策略:保留(Retain)
(2)Available资源尚未被claim使用

PV可以有一个类,通过将storageClassName属性设置为StorageClass的名称来指定。 特定类的PV只能绑定到请求该类的PVC。 没有storageClassName的PV没有类,只能绑定到不需要特定类的PVC。
在过去,使用了注释volume.beta.kubernetes.io/storage-class而不是storageClassName属性。 该注释仍然可以工作,但将来Kubernetes版本将不再适用。

2.2 创建持久卷声明PVC

2.2.1 指定selector和storageclass

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi
  storageClassName: slow
  selector:
    matchLabels:
      name: pv003

#kubectl get pvc
#kubectl get pv

2.2.2 仅指定storageclass

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 6Gi
  storageClassName: slow

#kubectl get pv
在这里插入图片描述创建一个pvc,需要6G存储;所以不会匹配pv001、pv002、pv003
#kubectl get pvc
在这里插入图片描述

2.2.3 删除处于terminiting状态的pv

#kubectl patch pvc  mypvc  -p '{"metadata":{"finalizers":null}}'

2.3 在pod中使用PVC

2.3 1 测试tomcat镜像

#docker pull tomcat
#docker run -id -p 8080:8080 --name=c_tomcat -v /data/volumes/:/usr/local/tomcat/webapps tomcat:latest
#docker exec -it c_tomcat /bin/bash

http://10.23.241.97:8080/v1/index.html
http://10.23.241.97:8080/v2/index.html
在这里插入图片描述#docker stop c_tomcat

2.3.2 文件deployment.yaml

apiVersion: v1
kind: Pod
metadata:
  name: vol-pvc
  namespace: default
  labels:
    app: myapp
spec:
  volumes:
  - name: html
    persistentVolumeClaim:
      claimName: mypvc
  containers:
  - name: myapp
    image: tomcat:latest
    volumeMounts:
    - name: html
      mountPath: /usr/local/tomcat/webapps

部署

#kubectl apply -f deployment.yaml
#kubectl exec -it vol-pvc -n default -- /bin/bash

在目录/data/volumes/v4中创建子目录
#mkdir aa
#cp index.html ./aa
进入pod中查看tomcat的运行情况
在这里插入图片描述

2.3.3 文件service.yaml

kind: Service
apiVersion: v1
metadata:
  name: mysvc
  namespace: default
spec:
  type: NodePort
  ports:
    - port: 8123
      nodePort: 32001
      targetPort: 8080
  selector:
    app: myapp

Service中主要涉及三种Port:
(1)port 这里的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供给集群内部访问kubernetes服务的入口。
(2)targetPort
也是containerPort,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。
(3)nodePort
nodeIP:nodePort 是提供给从集群外部访问kubernetes服务的入口。

总的来说,port和nodePort都是service的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端具体pod的targetPort,从而进入到pod上的容器内。

在这里插入图片描述

创建Service的type类型不同,可分成不同模式:
(1)ClusterIP默认方式。根据是否生成ClusterIP又可分为普通Service和Headless Service两类:
(1-1)普通Service:通过为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问。为最常见的方式。
(1-2)Headless Service:该服务不会分配Cluster IP,也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的网络ID来访问,DNS会将headless service的后端直接解析为podIP列表。主要供StatefulSet使用。

(2)NodePort:除了使用Cluster IP之外,还通过将service的port映射到集群内每个节点的相同一个端口,实现通过nodeIP:nodePort从集群外访问服务。
在这里插入图片描述查看网页
在这里插入图片描述

2.4 删除PVC

一般删除步骤为:先删pod再删pvc最后删pv
(1)删除pod
#kubectl delete pod volumeop-basic-csgvg-275778418 -n kubeflow
#kubectl delete pod volumeop-basic-csgvg-3408782246 -n kubeflow
(2)删除pvc
#kubectl delete pvc volumeop-basic-csgvg-my-pvc -n kubeflow
(3)删除pv
在删除pvc的时候pv会被自动删掉。

3 基于存储类实现PV动态提供

在k8s中部署有状态应用时,通常需要做数据持久化存储。
基于存储类,实现PV自动供给;
(创建存储类,在资源清单中指明地址和共享挂载卷目录即可实现持久化存储)
下载项目:

for file in class.yaml deployment.yaml rbac.yaml test-claim.yaml ; 
do wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/$file ;
done

3.1 class.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs
parameters:
  archiveOnDelete: "false"

provisioner: fuseim.pri/ifs # or choose another name, must match deployment’s env PROVISIONER_NAME’

3.2 rbac.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
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: ["create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

3.3 deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.0.165
            - name: NFS_PATH
              value: /some/path
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.0.165
            path: /some/path

创建存储类

#kubectl create -f class.yaml

#kubectl create -f rbac.yaml

#kubectl create -f deployment.yaml

3.4 修改一个storageclass为默认

default表示这个storageclass是默认的。

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

4 测试

部署一个pvc或者声明存储的应用,测试是否自动创建出PV而且自动绑定PVC,

4.1 test-claim.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

测试

#kubectl create -f test-claim.yaml

4.2 nginx-demo.yaml

StatefulSet方式部署的nginx应用

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
     app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
     name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi

猜你喜欢

转载自blog.csdn.net/qq_20466211/article/details/113251635