第二十三章 kubernetes 核心技术Volume

一、Volume概述

Volume 是 Pod 中能够被多个容器访问的共享目录。Kubernetes 的 Volume 定义在 Pod 上, 它被一个 Pod 中的多个容器挂载到具体的文件目录下。Volume 与 Pod 的生命周期相同, 但与容器的生命周期不相关,当容器终止或重启时,Volume 中的数据也不会丢失。要使用volume,pod 需要指定 volume 的类型和内容( 字段),和映射到容器的位置( 字段)。

Kubernetes 支持多种类型的 Volume,包括:emptyDir、hostPath、gcePersistentDisk、awsElasticBlockStore、nfs、iscsi、flocker、glusterfs、rbd、cephfs、gitRepo、secret、persistentVolumeClaim、downwardAPI、azureFileVolume、azureDisk、vsphereVolume、Quobyte、PortworxVolume、ScaleIO。

我们知道,Pod是由容器组成的,而容器宕机或停止之后,数据就随之丢了,那么这也就意味着我们在做Kubernetes集群的时候就不得不考虑存储的问题,而存储卷就是为了Pod保存数据而生的。存储卷的类型有很多,我们常用到一般有四种:emptyDir,hostPath,NFS以及云存储(ceph, glasterfs...)等。

二、EmptyDir

emptyDir类型的volume在pod分配到node上时被创建,kubernetes会在node上自动分配一个目录,因此无需指定宿主机node上对应的目录文件。这个目录的初始内容为空,一旦这个 pod 离开了这个宿主机,EmptyDir 中的数据就会被永久删除。所以目前 EmptyDir 类型的 volume 主要用作临时空间,比如 Web 服务器写日志或者 tmp 文件需要的临时目录。
[root@kubernetes-master-001 ~]# vi emptydir.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-volume-deployment
  namespace: default
  labels:
    app: test-volume-deployment
spec:
  selector:
    matchLabels:
      app: test-volume-pod
  template:
    metadata:
      labels:
        app: test-volume-pod
    spec:
      containers:
        - name: nginx
          image: busybox
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              name: http
            - containerPort: 443
              name: https
          volumeMounts:
            - mountPath: /data/
              name: empty
          command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
        - name: os
          imagePullPolicy: IfNotPresent
          image: busybox
          volumeMounts:
            - mountPath: /data/
              name: empty
          command: ['/bin/sh','-c','while true;do echo "budybox" >> /data/index.html;sleep 2;done']
      volumes:
        - name: empty
          emptyDir: {}

三、HostPath

hostPath类型则是映射node文件系统中的文件或者目录到pod里。在使用hostPath类型的存储卷时,也可以设置type字段,支持的类型有文件、目录、File、Socket、CharDevice和BlockDevice。

HostPath 属性的 volume 使得对应的容器能够访问当前宿主机上的指定目录。例如,需要运行一个访问 Docker 系统目录的容器,那么就使用/var/lib/docker 目录作为一个HostDir 类型的 volume;或者要在一个容器内部运行 CAdvisor,那么就使用/dev/cgroups 目录作为一个 HostDir 类型的 volume。一旦这个 pod 离开了这个宿主机,HostDir 中的数据虽然不会被永久删除,但数据也不会随 pod 迁移到其他宿主机上。因此,需要注意的是, 由于各个宿主机上的文件系统结构和内容并不一定完全相同,所以相同 pod 的 HostDir 可能会在不同的宿主机上表现出不同的行为。
#1.编写yaml文件
[root@kubernetes-master-001 ~]# vi hostpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: vol-hostpath
  namespace: default
spec:
# 指定所提供的存储卷
  volumes:
  - name: html
    hostPath:
      path: /data/pod/volume1/
      type: DirectoryOrCreate
  containers:
  - name: myapp
    image: nginx
# 指定所提供的存储卷
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
 
#2.部署应用
[root@kubernetes-master-001 ~]# kubectl  apply  -f hostpath.yaml 
pod/vol-hostpath created

#3.验证
[root@kubernetes-node-002 ~]# ll /data/pod/volume1/
total 0

四、NFS持久化存储

NFS使得我们可以挂载已经存在的共享到我们的Pod中,和emptyDir不同的是,当Pod被删除时,emptyDir也会被删除。但是nfs不会被删除,仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递,并且nfs可以同时被多个pod挂在并进行读写。

1.所有节点上安装NFS

yum install nfs-utils.x86_64 -y

2.配置NFS

[root@kubernetes-master-001 nfs]# mkdir -p /nfs/v{1..5}
[root@kubernetes-master-001 nfs]# cat > /etc/exports <<EOF
/nfs/v1  172.16.0.0/16(rw,no_root_squash)
/nfs/v2  172.16.0.0/16(rw,no_root_squash)
/nfs/v3  172.16.0.0/16(rw,no_root_squash)
/nfs/v4  172.16.0.0/16(rw,no_root_squash)
/nfs/v5  172.16.0.0/16(rw,no_root_squash)
EOF
[root@kubernetes-master-001 nfs]# exportfs -arv
exporting 172.16.0.0/16:/nfs/v5
exporting 172.16.0.0/16:/nfs/v4
exporting 172.16.0.0/16:/nfs/v3
exporting 172.16.0.0/16:/nfs/v2
exporting 172.16.0.0/16:/nfs/v1
[root@kubernetes-master-001 nfs]# showmount -e
Export list for kubernetes-master-001:
/nfs/v5 172.16.0.0/16
/nfs/v4 172.16.0.0/16
/nfs/v3 172.16.0.0/16
/nfs/v2 172.16.0.0/16
/nfs/v1 172.16.0.0/16

3.创建POD使用Nfs

[root@kubernetes-master-001 ~]# vi nfs.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs 
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - mountPath: /usr/share/nginx/html/
              name: nfs
      volumes:
        - name: nfs
          nfs:
            path: /nfs/v1
            server: 192.168.12.71

[root@kubernetes-master-01 ~]# kubectl get pods -l app=nfs
NAME                   READY   STATUS    RESTARTS   AGE
nfs-5f56db5995-9shkg   1/1     Running   0          24s
nfs-5f56db5995-ht7ww   1/1     Running   0          24s

[root@kubernetes-master-01 ~]# echo "index" > /nfs/v1/index.html

[root@kubernetes-master-01 ~]# kubectl exec -it nfs-5f56db5995-ht7ww -- bash
root@nfs-5f56db5995-ht7ww:/# cd /usr/share/nginx/html/
root@nfs-5f56db5995-ht7ww:/usr/share/nginx/html# ls
index.html

五、PV和PVC

1.基本概念

管理存储是管理计算的一个明显问题。该 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 是一一对应的。

2.生命周期

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

#1.供应准备 Provisioning 通过集群外的存储系统或者云平台来提供存储持久化支持。
- 静态提供 Static:集群管理员创建多个 PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于 Kubernetes API 中,可用于消费
- 动态提供 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)。
- 保留策略:允许人工处理保留的数据。
- 删除策略:将删除 pv 和外部关联的存储资源,需要插件支持。
- 回收策略:将执行清除操作,之后可以被新的 pvc 使用,需要插件支持

3.PV的访问模式(accessModes)

模式 解释
ReadWriteOnce(RWO) 可读可写,但只支持被单个节点挂载。
ReadOnlyMany(ROX) 只读,可以被多个节点挂载。
ReadWriteMany(RWX) 多路可读可写。这种存储可以以读写的方式被多个节点共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。

4.PV 的回收策略(persistentVolumeReclaimPolicy)

策略 解释
Retain 不清理, 保留 Volume(需要手动清理)
Recycle 删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持)
Delete 删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)

5.PV的状态

状态 解释
Available 可用。
Bound 已经分配给 PVC。
Released PVC 解绑但还未执行回收策略。
Failed 发生错误。

6.PV类型

GCEPersistentDisk
AWSElasticBlockStore AzureFile
AzureDisk
FC (Fibre Channel)
Flexvolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
Portworx Volumes
ScaleIO Volumes
StorageOS

7.PV 卷阶段状态

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

8.创建PV

#1.编写 yaml 文件,创建 5 个 pv,存储大小各不相同,是否可读也不相同
[root@kubernetes-master-001 ~]# vi pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:
    path: /data/volumes/v1
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi

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

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

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

---
apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5 
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 15G
#2.创建PV
[root@kubernetes-master-001 ~]# kubectl  apply -f pv.yaml 
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created

#3.查询验证
[root@kubernetes-master-001 ~]# kubectl  get  pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   2Gi        RWO,RWX        Retain           Available                                   3m12s
pv002   5Gi        RWO            Retain           Available                                   3m11s
pv003   20Gi       RWO,RWX        Retain           Available                                   3m11s
pv004   10Gi       RWO,RWX        Retain           Available                                   3m11s
pv005   15G        RWO,RWX        Retain           Available                                   3m10s

9.创建PVC

#1.编写 yaml 文件,创建一个 pvc,需要 6G 存储;所以不会匹配 pv001、pv002、pv003
[root@kubernetes-master-001 ~]# vi pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc 
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests: 
      storage: 6Gi

---
apiVersion: v1
kind: Pod
metadata:
  name: vol-pvc 
  namespace: default
spec:
  volumes:
    - name: html
      persistentVolumeClaim:
        claimName: mypvc
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
#2.创建PVC
[root@kubernetes-master-001 ~]# kubectl  apply  -f pvc.yaml 
persistentvolumeclaim/mypvc created
pod/vol-pvc created

#3.查询验证
[root@kubernetes-master-001 ~]# kubectl  get  pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv004    10Gi       RWO,RWX                       91s
[root@kubernetes-master-001 ~]# kubectl  get  pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON   AGE
pv001   2Gi        RWO,RWX        Retain           Available                                           20m
pv002   5Gi        RWO            Retain           Available                                           20m
pv003   20Gi       RWO,RWX        Retain           Available                                           20m
pv004   10Gi       RWO,RWX        Retain           Bound       default/mypvc                           20m
pv005   15G        RWO,RWX        Retain           Available                                           20m

[root@kubernetes-master-001 ~]# kubectl  get  pod 
NAME                                            READY   STATUS              RESTARTS   AGE
vol-pvc                                         1/1     running   0          11m

[root@kubernetes-master-001 ~]# curl 10.244.2.117
<h1>NFS stor 04</h1>

六、StorageClass

在一个大规模的Kubernetes集群里,可能有成千上万个PVC,这就意味着运维人员必须实现创建出这个多个PV,此外,随着项目的需要,会有新的PVC不断被提交,那么运维人员就需要不断的添加新的,满足要求的PV,否则新的Pod就会因为PVC绑定不到PV而导致创建失败。而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求,而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,Kubernetes 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,kubernetes根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。

1.定义StorageClass

每一个存储类都包含provisioner、parameters和reclaimPolicy这三个参数域,当一个属于某个类的PersistentVolume需要被动态提供时,将会使用上述的参数域。

# 下载helm
wget https://get.helm.sh/helm-v3.3.4-linux-amd64.tar.gz

# 解压
tar xf helm-v3.3.4-linux-amd64.tar.gz
# 安装
mv linux-amd64/helm /usr/local/bin/

# 验证
helm version

# 添加阿里云镜像仓库
helm repo add ali-stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

# 添加官方仓库
helm repo add stable https://kubernetes-charts.storage.googleapis.com/

# 添加微软云helm仓库
helm repo add azure http://mirror.azure.cn/kubernetes/charts/

# 下载nfs
helm pull stable/nfs-client-provisioner

# 解压安装包
tar xf nfs-client-provisioner-1.2.11.tgz && cd nfs-client-provisioner/

# 修改配置文件values.yaml

# 安装nfs client
helm install nfs ./

# 运行案例
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  namespace: default
  name: test-nfs
  labels:
    app: test-nfs
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-client
  resources:
    requests:
      storage: 8Gi
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-nfs-storageclass
  namespace: default
  labels:
    app: test-nfs
spec:
  selector:
    matchLabels:
      app: test-nfs
  template:
    metadata:
      labels:
        app: test-nfs
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: test-nfs
      volumes:
        - name: test-nfs
          persistentVolumeClaim:
            claimName: test-nfs

# 测试
[root@kubernetes-master-001 helm]# vim test.yaml
[root@kubernetes-master-001 helm]# kubectl apply -f test.yaml
persistentvolumeclaim/test-nfs created
deployment.apps/test-nfs-storageclass created
[root@kubernetes-master-001 helm]# kubectl get pvc,pv
NAME                             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/test-nfs   Bound    pvc-cf0c8175-f145-438a-ba5c-35effc080231   8Gi        RWX            nfs-client     7s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
persistentvolume/pvc-cf0c8175-f145-438a-ba5c-35effc080231   8Gi        RWX            Delete           Bound    default/test-nfs   nfs-client              6s

[root@kubernetes-master-001 helm]# ll /nfs/v1
total 4
drwxrwxrwx 2 root root 4096 Oct 16 09:56 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231

# 编写一个index.html测试网络存储。
[root@kubernetes-master-001 helm]# cd /nfs/v1/default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231/

[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# echo "index" > index.html

[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# kubectl get pods -l app=test-nfs
NAME                                     READY   STATUS    RESTARTS   AGE
test-nfs-storageclass-68c8996847-lsxwn   1/1     Running   0          75s

[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# kubectl get pods -l app=test-nfs -o wide
NAME                                     READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test-nfs-storageclass-68c8996847-lsxwn   1/1     Running   0          80s   10.244.0.12   instance-gvpb80ao   <none>           <none>

[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# curl 10.244.0.12
index
原文地址:https://www.cnblogs.com/jhno1/p/15607765.html