原文地址:https://www.kubernetes.org.cn/4075.html

1、存储卷概述

由于容器本身是非持久化的,因此需要解决在容器中运行应用程序遇到的一些问题。首先,当容器崩溃时,kubelet将重新启动容器,但是写入容器的文件将会丢失,容器将会以镜像的初始状态重新开始;第二,在通过一个Pod中一起运行的容器,通常需要共享容器之间一些文件。Kubernetes通过存储卷解决上述的两个问题。

在Docker有存储卷的概念卷,但Docker中存储卷只是磁盘的或另一个容器中的目录,并没有对其生命周期进行管理。Kubernetes的存储卷有自己的生命周期,它的生命周期与使用的它Pod生命周期一致。因此,相比于在Pod中运行的容器来说,存储卷的存在时间会比的其中的任何容器都长,并且在容器重新启动时会保留数据。当然,当Pod停止存在时,存储卷也将不再存在。在Kubernetes支持多种类型的卷,而Pod可以同时使用各种类型和任意数量的存储卷。在Pod中通过指定下面的字段来使用存储卷:

  • spec.volumes:通过此字段提供指定的存储卷
  • spec.containers.volumeMounts:通过此字段将存储卷挂接到容器中

2、存储卷类型和示例

参考官网文档,当前Kubernetes支持如下所列这些存储卷类型,并以hostPath、nfs和persistentVolumeClaim类型的存储卷为例,介绍如何定义存储卷,以及如何在Pod中被使用。

  • awsElasticBlockStore
  • azureDisk
  • azureFile
  • cephfs
  • configMap
  • csi
  • downwardAPI
  • emptyDir
  • fc (fibre channel)
  • flocker
  • gcePersistentDisk
  • gitRepo
  • glusterfs
  • hostPath
  • iscsi
  • local
  • nfs
  • persistentVolumeClaim
  • projected
  • portworxVolume
  • quobyte
  • rbd
  • scaleIO
  • secret
  • storageos
  • vsphereVolume

常见存储类型大致有:
emptyDir(临时目录):Pod删除,数据也会被清除,这种存储成为emptyDir,用于数据的临时存储。 
hostPath(宿主机目录映射):
SAN(存储区域网络):iSCSI、FB、FC
NAS(网络附加存储):nfs、cifs、http
分布式存储:Glusterfs、ceph(rbd)、cephfs
云存储:EBS(弹性块存储)、Azure Disk

#emptyDir存储卷的示例:
vim  pod-volume.yaml
apiVersion:v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: “cluster admin”
spec:
  containers:
  - name: httpd
    image: busybox:latest
    imagePullPolicy: IfNotPresent   #设定镜像策略为即便本地没有镜像也不去下载.
    command: ["/bin/httpd","-f","-h", " /data/web/html"]
    ports:
    - name: http
      containerPort: 80
    volumeMounts:          #存储卷可被一个Pod中的多个容器挂载.谁需要就定义挂载即可.
    - name: html
      mountPath: /data/web/html/
  - name: busybox
    image: busybox: latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: html
      mountPath: /data/
    command:
    - “/bin/sh”
    - “-c”
    - "while true; do echo $(date) >> /data/index.html; sleep 2; done”
volumes:
- name: html
  emptyDir: {}

2.1 hostPath

hostPath类型的存储卷用于将宿主机的文件系统的文件或目录挂接到Pod中,除了需要指定path字段之外,在使用hostPath类型的存储卷时,也可以设置type,type支持的枚举值由下表。另外在使用hostPath时,需要注意下面的事项:

  • 具有相同配置的Pod(例如:从同一个podTemplate创建的),可能会由于Node的文件不同,而行为不同。
  • 在宿主机上创建的文件或目录,只有root用户具写入的权限。您要么在容器中以root身份运行进程,要么在主机上修改的文件或目录的权限,以便具备写入内容到hostPath的存储卷中。
行为
  空字符串(默认)是用于向后兼容,这意味着在挂接主机路径存储卷之前不执行任何检查。
DirectoryOrCreate 如果path指定目录不存在,则会在宿主机上创建一个新的目录,并设置目录权限为0755,此目录与kubelet拥有一样的组和拥有者。
Directory path指定的目标必需存在
FileOrCreate 如果path指定的文件不存在,则会在宿主机上创建一个空的文件,设置权限为0644,此文件与kubelet拥有一样的组和拥有者。
File path指定的文件必需存在
Socket path指定的UNIX socket必需存在
CharDevice path指定的字符设备必需存在
BlockDevice 在path给定路径上必须存在块设备。

下面是使用hostPath作为存储卷的YAML文件,此YAML文件定义了一个名称为test-pd的Pod资源。它通过hostPath类型的存储卷,将Pod宿主机上的/data挂接到容器中的/teset-pd目录。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    # 指定在容器中挂接路径
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  # 指定所提供的存储卷
  volumes:
  - name: test-volume
    hostPath:
      # 宿主机上的目录,需要先创建好,否则type可修改为 DirectoryOrCreate
      path: /data
      # this field is optional
      type: Directory

gitRepo类型的存储卷:
 gitRepo:这种类型的存储卷是在容器启动时,将远程git仓库中的数据(如网站代码)给克隆一份到本地,然后启动容器使用该克隆的数据来提供服务,这份克隆的数据在容器运行过程中不会将更新的数据同步到git仓库中,同时git仓库中的更新也不会同步到该容器中,若要实现当git仓库发生改变时,能同步到容器的存储卷中,还要借助于辅助容器,每隔一段时间就去克隆一份git仓库中的数据,当本地数据改变时,再同步到git仓库中。

2.2 NFS

在Kubernetes中,可以通过nfs类型的存储卷将现有的NFS(网络文件系统)到的挂接到Pod中。在移除Pod时,NFS存储卷中的内容被不会被删除,只是将存储卷卸载而已。这意味着在NFS存储卷总可以预先填充数据,并且可以在Pod之间共享数据。NFS可以被同时挂接到多个Pod中,并能同时进行写入。需要注意的是:在使用nfs存储卷之前,必须已正确部署和运行NFS服务器,并已经设置了共享目录。

准备工作:
选择一台服务器,如192.168.8.150,部署nfs服务,提供网络共享存储:
yum install -y nfs nfs-utils
编辑 /etc/exports,内容为 /nfs-data/redis 192.168.10.0/24(rw,no_root_squash)
创建目录 mkdir -p /nfs-data/redis
启动nfs服务 systemctl start nfs
在集群中测试挂载,所有主机上能挂载,则pod也能挂载
yum install -y nfs-utils
mount -t nfs 192.168.8.150:/nfs-data/redis /nfs

下面是一个redis部署的YAML配置文件,redis在容器中的持久化数据保存在/data目录下;存储卷使用nfs,nfs的服务地址为:192.168.8.150,存储路径为:/k8s-nfs/redis/data。容器通过volumeMounts.name的值确定所使用的存储卷。

apiVersion: apps/v1  # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  revisionHistoryLimit: 2
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      # 应用的镜像
      - image: redis
        name: redis
        imagePullPolicy: IfNotPresent
        # 应用的内部端口
        ports:
        - containerPort: 6379
          name: redis6379
        env:
        - name: ALLOW_EMPTY_PASSWORD
          value: "yes"
        - name: REDIS_PASSWORD
          value: "redis"   
        # 持久化挂接位置,在docker中 
        volumeMounts:
        - name: redis-persistent-storage
          mountPath: /data
      volumes:
      # 宿主机上的目录
      - name: redis-persistent-storage
        nfs:
          path: /nfs-data/redis
          server: 192.168.8.150

2.3 persistentVolumeClaim,即PVC

persistentVolumeClaim类型存储卷将PersistentVolume挂接到Pod中作为存储卷。使用此类型的存储卷,用户并不知道存储卷的详细信息。

PVC 它是K8s中的标准资源,它存储在API Server的etcd(集群状态存储)存储数据库中,即便Pod因为故障被删除了,依然不影响PVC的存在,下次Pod启动后,依然可以使用PVC。

准备工作:
创建nfs共享目录
mkdir -p /nfs-data/{pv1,pv2}
修改nfs服务配置/etc/exports,添加以下行:
/nfs-data/pv1 192.168.10.0/24(rw,no_root_squash)
/nfs-data/pv2 192.168.10.0/24(rw,no_root_squash)
重启服务:
exportfs -arv
显示挂载目录:
showmount -e

PV的访问模型 accessModes:
  ReadWriteOnce【简写:RWO】: 单路读写,即仅能有一个节点挂载读写
  ReadOnlyMany【ROX】: 多路只读
   ReadWriteMany【RWX】:多路读写

创建pv卷,编辑pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01   #PV是集群级别的资源,因此它不能定义在名称空间中,它可以被任何名称空间使用.名称空间也不能嵌套,因为它也是集群级别的资源.
  labels:
    name: pv01
    rate: high    #添加一个速度标签,用于标明其存储效率更高,以便后期标签选择器选择.
spec:
  nfs:
    path: /data/pv1
    server: 192.168.8.150
  #对于访问模型,可定义为底层共享存储的子集,但不能是超集
  #即: NFS支持RWO,ROX,RWX,但我创建PV时,可只提供其中一个或多个.
  accessModes: ["ReadWriteMany", “ReadWriteOnce”]
  capacity:
    #对于存储能力,它的单位有:T,P,G,M,K或 Ti,Pi,Gi,Mi,Ki 区别:加i的是以1024为换算单位的。
    storage: 2Gi 
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02     
  labels:
    name: pv02
    rate: high       
spec:
  nfs:
    path: /data/pv2
    server: 192.168.8.150
  accessModes: ["ReadWriteMany","ReadOnlyMany"]
  capacity:
    storage: 5Gi

kubectl apply -f pv.yaml
kubectl get pv
RECLAIM POLICY:回收策略
Retain:保留,即若Pod绑定了一个PVC,PVC绑定了一个PV,后来Pod删除了,那么PV中的数据要怎么处理?
       Retain是默认回收策略,即这些数据保留着,以便Pod再次创建时还能使用。
Released:这种回收策略是,不保留数据,即Pod删除,则PV自动回收,清空里面的数据,并允许其他Pod绑定使用。
Delete:删除,即PVC和PV解除绑定后,PV自动删除,数据也就被清空了。

创建pvc,编辑pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
     name: nfs-pvc
     namespace: default
spec:
   #它必须是PV的子集,即PV必须能符合它的要求.
   accessModes: ["ReadWriteMany"]
   resources:
      requests:
        storage: 5Gi

kubectl apply -f pvc.yaml
kubectl get pvc
kubectl describe pvc nfs-pvc

# kubectl describe pvc nfs-pvc
        Name:          nfs-pvc
        Namespace:     default
        StorageClass:  
        Status:        Bound
        Volume:        pv02
        .......
        Capacity:      5Gi
        Access Modes:  ROX,RWX
        VolumeMode:    Filesystem
        Events:        <none>
        Mounted By:    xxxxx  #这里可查看此PVC当前挂载到那个容器里

kubectl describe pod xxxxx   # 可以查看容器挂载了哪个pvc

此处定义名为busybox-deployment的部署YAML配置文件,使用的镜像为busybox。基于busybox镜像的容器需要对/mnt目录下的数据进行持久化,在YAML文件指定使用名称为nfs的PersistenVolumeClaim对容器的数据进行持久化。

# This mounts the nfs volume claim into /mnt and continuously
# overwrites /mnt/index.html with the time and hostname of the pod.
apiVersion: v1
kind: Deployment
metadata:
  name: busybox-deployment
spec:
  replicas: 2
  selector:
    name: busybox-deployment
  template:
    metadata:
      labels:
        name: busybox-deployment
    spec:
      containers:
      - image: busybox
        command:
        - sh
        - -c
        - 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
        imagePullPolicy: IfNotPresent
        name: busybox
        volumeMounts:          
        # name must match the volume name below
        - name: nfs
          mountPath: "/mnt"
     volumes:
     - name: nfs
       persistentVolumeClaim:
         claimName: nfs-pvc

参考资料

1.《Volumes》地址:https://kubernetes.io/docs/concepts/storage/volumes/

2.《nfs》地址:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs

 

更多参考:

https://www.jianshu.com/p/56e87f83974b   Kubernetes 学习笔记(七)--- K8S存储卷、ConfigMap、Secrets
https://www.cnblogs.com/linuxk/p/9760363.html    Kubernetes学习之路(十六)之存储卷

posted on 2020-11-12 16:54  51core  阅读(241)  评论(0)    收藏  举报