Kubernetes 存储系统

161 阅读9分钟

云原生 从docker、Jenkins、Kubernetes从入门到精通系列

Kubernetes 目前支持多达 28 种数据卷类型(其中大部分特定于具体的云环境如 GCE/AWS/Azure 等),如需查阅所有的数据卷类型,请查阅 Kubernetes 官方文档 Volumes 。如:

  • 非持久性存储
    • emptyDir
    • HostPath
  • 网络连接性存储
    • SAN:iSCSI、ScaleIO Volumes、FC (Fibre Channel)
    • NFS:nfs,cfs
  • 分布式存储
    • Glusterfs
    • RBD (Ceph Block Device)
    • CephFS
    • Portworx Volumes
    • Quobyte Volumes
  • 云端存储
    • GCEPersistentDisk
    • AWSElasticBlockStore
    • AzureFile
    • AzureDisk
    • Cinder (OpenStack block storage)
    • VsphereVolume
    • StorageOS
  • 自定义存储
    • FlexVolume

使用命令 kubectl explain pod.spec.containers.volumeMounts 查看挂载的相关解释。

1、临时存储

1、几种临时存储

Kubernetes 为了不同的目的,支持几种不同类型的临时卷:

2、emptyDir

使用命令kubectl explain pod.spec.volumes.emptyDir查看命令

  • 当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建
  • 在 Pod 在该节点上运行期间,卷一直存在。
  • 卷最初是空的。
  • 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。
  • 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
  • 存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
apiVersion: v1
kind: Pod
metadata:
  name: "multi-container-pod"
  namespace: default
  labels:
    app: "multi-container-pod"
spec:
  volumes:    ### 以后见到的所有名字 都应该是一个合法的域名方式
  - name: nginx-vol
    emptyDir: {}  ### docker匿名挂载,外部创建一个位置  /abc
  containers:  ## kubectl exec -it podName  -c nginx-container(容器名)-- /bin/sh
  - name: nginx-container
    image: "nginx"
    volumeMounts:  #声明卷挂载  -v
      - name: nginx-vol
        mountPath: /usr/share/nginx/html
  - name: content-container
    image: "alpine"
    command: ["/bin/sh","-c","while true;do sleep 1; date > /app/index.html;done;"]
    volumeMounts: 
      - name: nginx-vol
        mountPath: /app

Pod里面是容器,容器无论怎样重启,不会导致卷丢失。
Pod被真正删除,会导致卷丢失,或者Pod被重新拉起(Pod超出资源限制,kubelet就会杀死Pod,如果保证副本就重新拉起,此时临时卷就没有)。

3、扩展:hostPath

image.png

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:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: Directory
apiVersion: v1
kind: Pod
metadata:
  name: test-webserver
spec:
  containers:
  - name: test-webserver
    image: k8s.gcr.io/test-webserver:latest
    volumeMounts:
    - mountPath: /var/local/aaa
      name: mydir
    - mountPath: /var/local/aaa/1.txt
      name: myfile
  volumes:
  - name: mydir
    hostPath:
      # 确保文件所在目录成功创建。
      path: /var/local/aaa
      type: DirectoryOrCreate
  - name: myfile
    hostPath:
      path: /var/local/aaa/1.txt
      type: FileOrCreate

典型应用: 解决容器时间问题

apiVersion: v1
kind: Pod
metadata:
  name: busy-box-test
  namespace: default
spec:
  restartPolicy: OnFailure #重启策略
  containers:
  - name: busy-box-test
    image: busybox
    imagePullPolicy: IfNotPresent
    volumeMounts: #描述容器想把自己的哪个路径进行挂载
    - name: localtime
      mountPath: /etc/localtime #容器内的时间路径,挂到容器的这个位置
    command: ["sleep", "60000"]
  volumes: #描述每个volumeMounts到底该怎么挂载
  - name: localtime
    hostPath:
      path: /usr/share/zoneinfo/Asia/Shanghai #上海时区

2、持久化

1、VOLUME

1、基础

image.png

  • Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型
  • 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长
  • 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;
  • Kubernetes 不会销毁 持久卷。
  • 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
  • 使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。

支持的卷类型:点击这里

2、使用subPath

有时,在单个 Pod 中共享卷以供多方使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。

3、使用NFS

image.png

1、安装NFS
# 在任意机器
yum install -y nfs-utils

# 执行以下命令,启动 nfs 服务;创建共享目录
mkdir -p /nfs/data

#执行命令 vi /etc/exports,创建 exports 文件,文件内容如下:
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
#/nfs/data  172.26.248.0/20(rw,no_root_squash)

systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server
exportfs -r
#检查配置是否生效
exportfs
# 输出结果如下所示
/nfs/data /nfs/data
2、VOLUME进行挂载测试
#测试Pod直接挂载NFS了
apiVersion: v1
kind: Pod
metadata:
  name: vol-nfs
  namespace: default
spec:
  containers:
  - name: myapp
    image: nginx
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    nfs:
      path: /nfs/data   #1000G
      server: 自己的nfs服务器地址
3、扩展-NFS文件同步
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。
#安装客户端工具
yum install -y nfs-utils

#执行以下命令检查 nfs 服务器端是否有设置共享目录
# showmount -e $(nfs服务器的IP)
showmount -e 192.168.219.130
# 输出结果如下所示

image.png

#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir /root/nfsmount
# mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount
#高可用备份的方式
mount -t nfs 192.168.219.130:/nfs/data /root/nfsmount
# 写入一个测试文件
echo "hello nfs server" > /root/nfsmount/test.txt

#在 nfs 服务器上执行以下命令,验证文件写入成功
cat /root/nfsmount/test.txt

2、PV、PVC、StorageClass

使用命令 kubectl explain pv 查看pv的相关解释。

image.png

1、基础概念
  • 存储的管理是一个与计算实例的管理完全不同的问题。
  • PersistentVolume 子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。
  • 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。

持久卷(PersistentVolume ):

  • 持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。
  • 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于使用他们的Pod的生命周期。
  • 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申请(PersistentVolumeClaim,PVC):

  • 表达的是用户对存储的请求
  • 概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。
  • Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。

存储类(Storage Class) :

  • 尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的 问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。
  • 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不 仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。
  • 为了满足这类需求,就有了 存储类(StorageClass) 资源。

image.png

image.png

image.png

2、实战

实战官网演示地址:点这里

提前创好空间haha,就是在data文件夹下创建一个文件夹名为haha
创建yaml文件vi pv-10m.yaml
执行下面的yaml,并查看pv: kubectl get pv

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume-10m
  labels:
    type: local
spec:
  storageClassName: my-nfs-storage
  capacity:
    storage: 10m
  accessModes:
    - ReadWriteOnce
  nfs:  ## 使用nfs存储系统
    server: 192.168.219.130  # 没type
    path: /nfs/data/haha  # abc文件夹提前创建

image.png

使用PVC申请:

申请: 创建yaml文件vi pod-pvc.yaml

apiVersion: v1
kind: Pod
metadata:
  name: "nginx-pvc"
  namespace: default
  labels:
    app: "nginx-pvc"
spec:
  containers:
  - name: nginx-pvc
    image: "nginx"
    ports:
    - containerPort:  80
      name:  http
    volumeMounts:
    - name: localtime
      mountPath: /etc/localtime
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
    - name: localtime
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: html
      persistentVolumeClaim:
         claimName:  nginx-pvc  # 你的申请书的名字
  restartPolicy: Always

编写申请书:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
  namespace: default
  labels:
    app: nginx-pvc
spec:
  storageClassName: my-nfs-storage  ## 存储类的名字
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5m

上面两个文件写在一个文件中,使用---分割。

image.png 已使用的pv,状态会更改为bound。

Pod删除,申请书与PV的绑定还在。即使PVC删除了,PV的状态会变为释放Released,默认别人也不能绑定。修改回收策略可以让别人挂载。

  • 如果申请空间一直没有,则会一直pending状态。
  • PV被创建以后(可用的),PVC自动绑定到这个PV卷。
  • 以后Pod只需要关联PVC即可。
  • Pod删除,PVC还在吗?
    • pvc并不会影响。手动删除pvc。
      • 按照以前原则。同一个资源的所有关联东西都应该写在一个文件中,方便管理。
    • PVC删除会不会影响PV?
      • 要看PV的回收策略。比如nfs。回收策略是Recycle。PV不会删除,内容会被清空,PV重新变为Available。

Pod-->PVC-->PV

3、细节
1、访问模式

访问模式:这里是官网

2、回收策略

回收策略:这里是官网

目前的回收策略有:

  • Retain -- 手动回收:PV相关的内容,自己删除。默认规则。
  • Recycle -- 基本擦除 (rm -rf /thevolume/*):清除卷里面的内容
  • Delete -- 诸如 AWS EBS 或 GCE PD 卷这类关联存储资产也被删除:PV自己也跟着删除。

目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS 和 GCE PD 卷支持删除(Delete)。

测试Delete回收策略

PV创建pv-delete.yaml,并执行:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume-10m-delete
  labels:
    type: local
spec:
  persistentVolumeReclaimPolicy: Delete #删除
  storageClassName: my-nfs-storage
  capacity:
    storage: 10m
  accessModes:
    - ReadWriteOnce
  nfs:  ## 使用nfs存储系统
    server: 192.168.219.130  # 没type
    path: /nfs/data/delete  # abc文件夹提前创建

PVC创建pvc-10m-delete.yaml,并执行:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-10-delete
  namespace: default
  labels:
    app: pv-10-delete
spec:
  storageClassName: my-nfs-storage  ## 存储类的名字
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5m

image.png 执行删除命令kubectl delete pvc pv-10-delete,再次查看:

image.png failed代表回收失败。

image.png 说是需要安装删除插件。官网说:仅 NFS 和 HostPath 支持回收(Recycle)。所以,NFS只能使用回收策略。
如果使用回收策略,删除过后,就是重新可用。

3、阶段

各个阶段描述:官网

每个持久卷会处于以下阶段(Phase)之一:

  • Available 卷是一个空闲资源,尚未绑定到任何申领
    • PV可用。可以和任意PVC绑定。
  • Bound 该卷已经绑定到某申领
  • Released 所绑定的申领已被删除,但是关联存储资源尚未被集群回收
    • PV释放。释放了和PVC的关联关系,绑定不存在。新的不同PVC不能重新绑定上来。
  • Failed 卷的自动回收操作失败

你可以使用 kubectl describe persistentvolume <name> 查看已绑定到 PV 的 PVC 的名称。