怎么让修改的html持久化_Part7:聊聊Kubernetes存储与数据持久化

一、存储卷概述

Kubernetes提供的存储卷隶属于Pod资源,Pod内的所有容器共享存储卷。存储卷是定义在Pod资源之上、可以被其内部所有容器挂载的共享目录,它关联至某外部的存储设备之上的存储空间,从而独立于容器自身的文件系统,而数据是否具有持久化能力则取决于存储卷本身是否支持持久机制。

33f585db46f432d3a4741814efa4f8d4.png
图1-1 Pod、容器与存储卷

Kubernetes支持本地存储(节点)和网路存储,以及SecretConfigMap等特殊存储资源。

  • 本地存储:包括emptyDirhostPath,属于节点级别的存储卷。emptyDir的生命周期与Pod一致,使用hostPath卷的Pod一旦被调度至别的节点也将无法再使用之前的数据;所以这两种类型都不具有持久性
  • 网络存储卷:集群级别的存储卷,使用外部存储系统比如NFS、Ceph、GlusterFS等。这种类型都具有持久化
  • Secret和ConfigMap:Secret用于向Pod传递敏感数据,而ConfigMap则用于非敏感数据。

二、临时存储卷emptyDir的使用

emptyDir的生命周期和Pod的生命周期一致,也就是说一旦Pod被回收,该存储卷的数据就会丢失。所以emptyDir一般用于数据缓存或者同一个Pod内的多个容器间文件的共享。

emptyDir示例:定义了一个名为html的存储卷,挂载于容器nginx的/usr/share/nginx/html目录以及容器pagegen的/html目录。容器pagegen每隔30秒向存储卷上的index.html文件中追加一行信息,为nginx容器中的nginx进程则以其为站点主页。

apiVersion: v1
kind: Pod
metadata:
 name: vol-emptydir-pod
spec:
 nodeSelector:
  enough: "true"
 volumes:
  - name: html
    emptyDir: {}
 containers:
 - name: nginx
   image: nginx:1.12-alpine
   volumeMounts:
   - name: html
     mountPath: /usr/share/nginx/html
 - name: pagegen
   image: alpine
   env:
   - name: hostname
     value: test
   - name: date
     value: 2019-10-28
   volumeMounts:
   - name: html
     mountPath: /html
   command: ["/bin/sh", "-c"]
   args:
   - while true; do
      echo ${hostname} ${date} >> /html/index.html;
      sleep 30;
     done

emptyDir下有两个可配字段:

  • medium:可取值为默认的defaultMemory。default表示使用节点的默认存储介质。而Memory则使用基于RAM的临时文件系统tmpfs,空间受限于内存,但性能好,适用于为容器中的应用提供缓存空间。
  • sizeLimit:当前存储卷的空间限制,默认是nil,即不做限制。但是在medium为Memory时建议务必设置。

三、节点存储卷hostPath的使用

hostPath类型的存储卷是指将工作节点上某文件系统的目录或文件挂载于Pod中。hostPath存储卷虽然能持久保存数据,但对于被调度器按需调度的应用来说并不适用。因为,如果一个Pod因自身重建或者节点崩溃而重新被调度至其他节点后将不能再使用之前节点保存的数据。

hostPath示例:

apiVersion: v1
kind: Pod
metadata:
 name: vol-host-path-pod
spec:
 volumes:
 - name: data
   hostPath:
    path: /home/test
    type: DirectoryOrCreate
 containers:
 - name: hostpath
   image: busybox
   command: ["sleep","3600"]
   volumeMounts:
   - name: data
     mountPath: /test
 nodeSelector:
  enough: "true"

hostPath主要有两个配置字段:

  • path:指定工作节点上的目录路径
  • type:类型,可取值如下
    • DirectoryOrCreate:指定的路径不存在时自动创建权限为0755的空目录
    • Directory:必须是存在的目录路径
    • FileOrCreate:路径不存在时自动创建权限为0644的空文件,属主和属组都是kubelet
    • File:必须是存在的文件路径
    • Socket:必须是存在的Socker文件路径
    • CharDevice:必须是存在的字符设备文件路径
    • BlockDevice:必须是存在的块设备文件路径

四、网络存储卷的使用(以NFS网络文件系统为例)

kubernetes适配众多专用存储系统的网络存储卷,包括传统的NAS或SAN设备(比如NFS)、分布式存储(比如GlusterFS)、云端存储(比如gcePersistentDisk)。下面就给出一个NFS存储卷的例子。

NFS(Network File System)即网络文件系统是一种分布式文件系统协议,其功能旨在允许客户端主机可以像访问本地存储一样通过网络访问服务器端文件。Kubernetes的NFS存储卷用于将事先存在的NFS服务器上导出的存储空间挂载到Pod中以供容器使用

首先需要搭建一个NFS服务器(为了方便,作者是从k8s集群中选了一台机器IP是10.179.252.77)

(1)修改k8s集群服务的hosts文件,使之能解析nfs服务器

vim /etc/hosts
//添加一行
10.179.252.77 nfs

(2)在10.179.252.77上安装nfs-utils工具

yum -y install nfs-utils

(3)创建文件夹

mkdir /data/volumes -p

(4)创建文件

vim /data/volumes/index.html

(5)导出存储空间

vim /etc/exports
//添加一行
/data/volumes 10.179.252.77/24(rw,no_root_squash)

(6)启动NFS服务

systemctl start nfs

然后编写资源文件:

apiVersion: v1
kind: Pod
metadata:
 name: vol-nfs-pod
spec:
 nodeSelector:
  enough: "true"
 containers:
 - name: myapp
   image: ikubernetes/myapp:v1
   volumeMounts:
   - name: html
     mountPath: /usr/share/nginx/html
 volumes:
 - name: html
   nfs:
    server: nfs
    path: /data/volumes
    readOnly: false

server:NFS服务器的IP地址或者主机名

path:NFS服务器导出(共享)的文件系统目录

readOnly:是否以只读方式挂载,默认false

五、PersistentVolume以及PersistentVolumeClaim

通过使用具有持久保存数据功能的存储卷比如NFS可知,用户必须要清晰了解所有用到的网络存储系统的配置细节才能完成存储卷相关配置。这与Kubernetes的向用户可开发隐藏底层架构的目标有所背离。为此,Kubernetes利用PersistentVolume在用户和管理员之间添加了一个抽象层,从而将存储系统的使用和管理职能解耦

12b8320dc4e68957bee863115a4fd80b.png
图5-1 Pod存储卷、PVC、PV及存储设备的调用关系
  • PersistentVolume(后面简称PV)是由集群管理员配置提供的某存储系统上的一段存储空间,它是对底层共享存储的抽象,将共享存储作为一种可由用户申请使用的资源,实现了“存储消费”机制。PV是集群级别的资源,不属于任何namespace。
  • PersistentVolumeClaim(后面简称PVC)是供用户提出存储使用申请完成绑定的,PVC是PV的消费者。它向PV申请特定大小的空间以及访问模式(rw或ro),从而创建出PVC存储卷。最后胡再由Pod资源通过PVC存储卷关联使用。

PV、PVC示例:

(1)创建PV

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"]
 persistentVolumeReclaimPolicy: Retain
 volumeMode: Filesystem
 mountOptions:
 - hard
 - nfsvers=4.1
 capacity:
  storage: 15Gi

创建了5个PV,配置项说明:

  • capacity.storage:当前PV的容量,目前仅支持空间大小设定
  • accessModes:访问模式,可用值如下:
    • ReadWriteOnce:仅可被单个节点读写挂载RWO
    • ReadOnlyMany:可被多个节点同时只读挂载ROX
    • ReadWriteMany:可被多个节点同时读写挂载RWX
  • persistentVolumeReclaimPolicy:PV空间被释放时的处理机制,可用值如下
    • Retain:保持不动,由管理员随后删除
    • Recycle:空间回收,即删除存储卷目录下的所有文件(目前仅支持NFS和hostPath)
    • Delete:删除存储卷,仅部分云端存储系统支持(比如AWS EBS等)
  • volumeMode:卷模型,指定此卷可被用作文件系统还是裸格式的块设备,默认Filesystem
  • storageClassName:当前PV所属的StorageClass的名称,默认为空值
  • mountOptions:挂载选项组成的列表,如ro、soft、hard等

创建后的PV状态描述:

  • Available:可用状态的自由资源,尚未被PVC绑定
  • Bound:已经绑定至某PVC
  • Released:绑定的PVC已经被删除,但资源尚未被集群回收
  • Failed:因自动回收资源失败而处于故障的状态

(2)创建PVC

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

可选配置项说明:

  • accessModes:访问模式,同PV
  • resources:当前PVC存储卷需要占用的资源的的最小值
  • selector:标签选择器,绑定时对PV应用的标签选择器或匹配条件表达式
  • storageClass:所依赖的存储类的名称
  • volumeMode:卷模型,同PV
  • volumeName:用于直接指定绑定的PV的名字

上述的PVC会绑定pv004,因为pv004的空间大于PVC需要的空间,且是最接近的。

(3)在Pod中使用PVC

apiVersion: v1
kind: Pod
metadata:
 name: vol-pvc
spec:
 nodeSelector:
  enough: "true"
 containers:
 - name: myapp
   image: ikubernetes/myapp:v1
   volumeMounts:
   - name: html
     mountPath: /usr/share/nginx/html
 volumes:
 - name: html
   persistentVolumeClaim:
    claimName: mypvc

直接通过指定persistentVolumeClaim.claimName来使用

(4)补充下存储类(StorageClass)的概念

存储类是由管理员为管理PV和PVC之便而按需创建的类别,例如按照存储系统的性能高低分类、或者根据综合服务质量级别进行分类等等。存储类的好处之一便是支持PV的动态创建。也就是说管理员无需事先手动创建一系列的PV,系统按PVC的需求标准动态创建适配的PV。

第一步:创建ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
 name: nfs-provisioner

第二步:创建ClusterRole

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-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: ["watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services", "endpoints"]
    verbs: ["get"]
  - apiGroups: ["extensions"]
    resources: ["podsecuritypolicies"]
    resourceNames: ["nfs-provisioner"]
    verbs: ["use"]

第三步:创建ClusterRoleBinding

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

第四步:创建NFS客户端Deployment

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: nfs-client-provisioner
spec:
 replicas: 1
 strategy:
  type: Recreate
 template:
  metadata:
   labels:
    app: nfs-client-provisioner
  spec:
   serviceAccount: nfs-provisioner
   nodeSelector:
    enough: "true"
   volumes:
   - name: nfs-client-root
     nfs:
      server: nfs
      path: /data/volumes
   containers:
   - name: nfs-client-provisioner
     image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
     volumeMounts:
     - name: nfs-client-root
       mountPath: /persistentvolumes
     env:
     - name: PROVISIONER_NAME
       value: lwh.cn/nfs
     - name: NFS_SERVER
       value: nfs
     - name: NFS_PATH
       value: /data/volumes

第五步:创建StorageClass

apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: standard
provisioner: lwh.cn/nfs

第六步:验证效果—创建PVC(不用创建任何PV)

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

第七步:验证效果—创建Pod引用PVC(动态创建PV)

kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
 nodeSelector:
  enough: "true"
 containers:
 - name: test-pod
   image: busybox
   command:
   - "/bin/sh"
   args:
   - "-c"
   - "touch /mnt/SUCCESS && exit 0 || exit 1"
   volumeMounts:
   - name: nfs-pvc
     mountPath: "/mnt"
 restartPolicy: "Never"
 volumes:
 - name: nfs-pvc
   persistentVolumeClaim:
    claimName: test-claim

六、PV和PVC的使命周期

1、存储供给:包括静态供给(事先手动创建一系列PV)和动态供给(不存在PV能匹配满足PVC时,kubernetes会尝试为PVC动态创建)

2、存储绑定:将PV和PVC绑定,若PVC未找到可匹配的PV,则PVC一直处于未绑定状态

  • 存储使用
  • PVC保护:万一用户删除了仍处于某Pod资源使用中的PVC时,kubernetes不会立即移除,而是推迟到不再被任何Pod资源使用后才执行删除操作

3、存储回收

  • 留存:删除PVC之后,kubernetes系统不会自动删除PV,而仅仅为释放状态。这种状态下的PV不能被其他PVC申请绑定。因此之前生成的数据仍然存在,需要由管理员手动决定后续处理方案。这就意味,如果想要再次使用此PV资源,需要做以下几步:
    • 删除PV
    • 手动清理存储系统上留存的数据
    • 手动删除存储系统的存储卷以释放空间,以便再次创建或者直接将其重新创建为PV
  • 回收:存储卷上数据被删除并且PV再次变为可申请状态
  • 删除:PVC被删除后直接移除PV对象。同时移除的还有PV相关的外部存储系统上的存储资产。动态创建的PV资源的回收策略取决去相关存储类上的定义。存储类默认是Delete

七、downwardAPI存储卷

很多时候,应用程序需要根据其所在的环境信息设定运行特性等,这类环境变量信息包括节点及集群的属性信息等。托管于Kubernetes的Pod对象中的容器化应用有时候也需要获取其所属Pod的IP、主机名、标签、注解、UID请求的CPU及内存资源等信息。容器可以通过环境变量或者downwardAPI存储卷访问此类信息。

第一种:环境变量式元数据注入

apiVersion: v1
kind: Pod
metadata:
 name: env-test-pod
 labels:
  app: env-test-pod
spec:
 nodeSelector:
  enough: "true"
 containers:
 - name: env-test-container
   image: busybox
   command: [ "/bin/sh", "-c", "env" ]
   resources:
    requests:
     memory: "32Mi"
     cpu: "125m"
    limits:
     memory: "64Mi"
     cpu: "250m"
   env:
   - name: MY_POD_NAME
     valueFrom:
      fieldRef:
       fieldPath: metadata.name
   - name: MY_POD_NAMESPACE
     valueFrom:
      fieldRef:
       fieldPath: metadata.namespace
   - name: MY_POD_LABEL
     valueFrom:
      fieldRef:
       fieldPath: metadata.labels['app']
   - name: MY_CPU_LIMIT
     valueFrom:
      resourceFieldRef:
       resource: limits.cpu
   - name: MY_MEMORY_REQUEST
     valueFrom:
      resourceFieldRef:
       resource: requests.memory
       divisor: 1Mi
 restartPolicy: Never

可通过fieldRef字段引用的信息有:

  • spec.nodeName:节点名称
  • status.hostIP:节点IP地址
  • metadata.namespace:Pod对象隶属的名称空间
  • metadata.name:Pod对象的名称
  • status.podIP:Pod地址
  • spec.serviceAccountName:Pod对象使用的ServiceAccount资源的名称
  • metadata.uid:Pod对象的uid
  • metadata.labels['key']:标签
  • metadata.annotations[''key]:注解

可通过resourceFieldRef字段引用的信息有:

  • requests.cpu:cpu请求值
  • requests.memory:内存请求值
  • limits.cpu:cup最大限制
  • limits.request:内存最大限制

最后divisor字段用于单位换算的

第二种:存储卷式元数据注入

apiVersion: v1
kind: Pod
metadata:
 name: dapi-vol-pod
 labels:
  zone: east-china
  rack: rack-101
  app: dapi-vol-pod
 annotations:
  annotation: "test-value-1"
spec:
 nodeSelector:
  enough: "true"
 containers:
 - name: volume-test-container
   image: busybox
   command: ["sh", "-c", "sleep 864000"]
   resources:
    requests:
     memory: "32Mi"
     cpu: "125m"
    limits:
     memory: "64Mi"
     cpu: "250m"
   volumeMounts:
   - name: podinfo
     mountPath: /etc/podinfo
     readOnly: false
 volumes:
 - name: podinfo
   downwardAPI:
    defaultMode: 420
    items:
    - fieldRef:
       fieldPath: metadata.namespace
      path: pod_namespace
    - fieldRef:
       fieldPath: metadata.labels
      path: pod_labels
    - fieldRef:
       fieldPath: metadata.annotations
      path: pod_annotations
    - resourceFieldRef:
       containerName: volume-test-container
       resource: limits.cpu
      path: cpu_limit
    - resourceFieldRef:
       containerName: volume-test-container
       resource: requests.memory
       divisor: "1Mi"

上面这个配置会在容器的/etc/podinfo目录下生成pod_namespace、pod_labels、pod_annotations、cpu_limit、requests.memory等文件用于存储Pod的各类信息。另外,标签和注解信息支持运行时修改,其改动结果会实时映射到downwardAPI生成的文件中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值