k8s之存储
1.k8s-volumes1)为什么要用volumes?k8s中容器中的磁盘的生命周期是短暂的, 这就带来了一些列的问题:当一个容器损坏之后, kubelet会重启这个容器, 但是容器中的文件将丢失----容器以干净的状态 重新启动当很多容器运行在同一个pod中时, 很多时候需要数据文件的共享在 k8s 中,由于 pod 分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共 享,并且,在
1.k8s-volumes
1)为什么要用volumes?
k8s中容器中的磁盘的生命周期是短暂的, 这就带来了一些列的问题:
- 当一个容器损坏之后, kubelet会重启这个容器, 但是容器中的文件将丢失----容器以干净的状态 重新启动
- 当很多容器运行在同一个pod中时, 很多时候需要数据文件的共享
- 在 k8s 中,由于 pod 分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共 享,并且,在节点故障时,可能会导致数据的永久性丢失。
volumes就是用来解决以上问题的,Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。注意:docker磁盘映射的数据将会被保留,和kubernetes有一些不一样
2)什么是volume?
volume用来对容器的数据进行挂载,存储容器运行时所需的一些数据。当容器被重新创建时,实 际上我们发现volume挂载卷并没有发生变化。
kubernetes中的卷有明确的寿命————与封装它的pod相同。所以,卷的生命比pod中的所有容 器都长,当这个容器重启时数据仍然得以保存。
当然,当pod不再存在时,卷也不复存在,也许更重要的是kubernetes支持多种类型的卷,pod可 以同时使用任意数量的卷3)卷的类型
kubenetes卷的类型:
第一种就是本地卷:
像hostPath类型与docker里面的bind mount类型,就是直接挂载到宿主机文件的类型 像 emptyDir是这样本地卷,也就是类似于volume类型 这两点都是绑定node节点的。
第二种就是网络数据卷:
比如Nfs、ClusterFs、Ceph,这些都是外部的存储都可以挂载到k8s上
第三种就是云盘:
比如AWS、微软(azuredisk)
第四种就是k8s自身的资源:
比如secret、configmap、downwardAPI
4)emptyDir
先来看一下本地卷 像emptyDir类似与docker的volume,而docker删除容器,数据卷还会存在, 而emptyDir删除容器,数据卷也会丢失,一般这个只做临时数据卷来使用。
创建一个空卷,挂载到Pod中的容器。Pod删除该卷也会被删除。
应用场景:Pod中容器之间数据共享。
当pod被分配给节点时,首先创建emptyDir卷,并且只要该pod在该节点上运行,该卷就会存在。 正如卷的名字所述,它最初是空的,pod中的容器可以读取和写入emptyDir卷中的相同文件,
尽管该卷 可以挂载到每个容器中的相同或者不同路径上。当处于任何原因从节点删除pod时,emptyDir中的数据 将被永久删除 。注意:容器崩溃不会从节点中移除pod,因此emptyDir卷中的数据在容器崩溃时是安全的。
emptyDir的用法:
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时候的检查点
- web服务器容器提供数据时,保存内容管理器容器提取的文件
4.1)empty挂载案例
在/opt/pv目录下创建my-volumn.yaml文件
内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是Pod kind: Pod metadata: #这个里面定义的是Pod中我们创建的对象信息 #对象名称 name: test-pod spec: #这个是对Pod详细的定义 containers: #基于下面的镜像去创建pod - image: hub.harbor.com/library/myapp:v1 #容器名称是test-container name: test-container volumeMounts: #这里就是在容器中引用下面的定义的volumes挂载项 #容器中挂载的位置是/cache - mountPath: /cache #引用名称为cache-volume的挂载卷,和下面名称保持一致 name: cache-volume volumes: #表示我们定义了一个挂在卷 #挂载卷的名称是cache-volume - name: cache-volume #挂载卷的类型是emptyDir emptyDir: {}
下面执行脚本:
下面我们进入容器内部查看是否存在/cache空目录
在一个pod里面定义两个容器并且都挂载在同一个volumn上,将my-volumn.yaml的内容换成下面的:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是Pod kind: Pod metadata: #这个里面定义的是Pod中我们创建的对象信息 #对象名称 name: test-pod spec: #这个是对Pod详细的定义 containers: #基于下面的镜像去创建pod - image: hub.harbor.com/library/myapp:v1 #容器名称是test-container name: test-container volumeMounts: #这里就是在容器中引用下面的定义的volumes挂载项 #容器中挂载的位置是/cache - mountPath: /cache #引用名称为cache-volume的挂载卷,和下面名称保持一致 name: cache-volume #基于下面的镜像去创建pod - image: hub.harbor.com/library/myapp:v1 #容器名称是test-container2 name: test-container2 command: ["/bin/sh","-c","sleep 6000s"] imagePullPolicy: IfNotPresent volumeMounts: #这里就是在容器中引用下面的定义的volumes挂载项 #容器中挂载的位置是/cache - mountPath: /cache #引用名称为cache-volume的挂载卷,和下面名称保持一致 name: cache-volume volumes: #表示我们定义了一个挂在卷 #挂载卷的名称是cache-volume - name: cache-volume #挂载卷的类型是emptyDir emptyDir: {}
执行效果:
5)HostPath
挂载Node文件系统上文件或者目录到Pod中的容器。
应用场景:Pod中容器需要访问宿主机文件
案例:在centos002(宿主机)的/opt/pv目录下创建一个my-volumn.yaml文件,内容如下
#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是Pod kind: Pod metadata: #这个里面定义的是Pod中我们创建的对象信息 #对象名称 name: test-pod spec: #这个是对Pod详细的定义 containers: #基于下面的镜像去创建pod - image: hub.harbor.com/library/myapp:v1 #容器名称是test-container name: test-container volumeMounts: #这里就是在容器中引用下面的定义的volumes挂载项 #容器中挂载的位置是/cache - mountPath: /cache #引用名称为cache-volume的挂载卷,和下面名称保持一致 name: cache-volume volumes: #表示我们定义了一个挂在卷 #挂载卷的名称是cache-volume - name: cache-volume #挂载卷的类型是hostPath,这个是将pod中容器的目录和宿主机进行同步 hostPath: #这个是对应宿主机同步的位置,注意这个我们需要提前在Node节点建好目录 path: /opt/pv/data #类型是文件夹 type: Directory
我们提前在centos003和centos004两台node节点创建好/opt/pv/data目录
执行上面的脚本:
我们进入容器内部的/cache目录并且创建一个文件
我们再去centos003节点的/opt/pv/data目录看一下是否同步了6)NFS网络存储
NFS是一种很早的技术,单机的存储在服务器方面还是非常主流的,但nfs唯一的就是缺点比较大就 是没有集群版,做集群化还是比较费劲的,文件系统做不了,这是一个很大的弊端,大规模的还是需要 选择一些分布式的存储,nfs就是一个网络文件存储服务器,装完nfs之后,共享一个目录,其他的服务 器就可以通过这个目录挂载到本地了,在本地写到这个目录的文件,就会同步到远程服务器上,实现一 个共享存储的功能,一般都是做数据的共享存储,比如多台web服务器,肯定需要保证这些web服务器 的数据一致性,那就会用到这个共享存储了,要是将nfs挂载到多台的web服务器上,网站根目录下, 网站程序就放在nfs服务器上,这样的话。每个网站,每个web程序都能读取到这个目录,一致性的数 据,这样的话就能保证多个节点,提供一致性的程序了。
6.1) 单独拿一台服务器做nfs服务器,我们这里先使用centos005搭建一台NFS服务器
命令:yum install nfs-utils -y6.2)暴露目录,让是让其他服务器能挂载这个目录
命令:
首先创建一个目录: mkdir /opt/k8s
为这个机器加上权限让其他机器可以读写:vim /etc/exports,内容如下:
/opt/k8s 192.168.56.14/24(rw,no_root_squash)6.3)启动nfs
命令:systemctl start nfs
6.4)其他节点也需要安装nfs并且使用命令将目录挂载到centos005上面
这里我们以centos002为例,其他的centos003,centos004都一样
安装命令:yum install nfs-utils -y
将本地的/mnt目录挂载到centos005的/opt/k8s目录下:
命令:mount -t nfs 192.168.56.14:/opt/k8s /mnt
使用df -h查看挂载的情况:
我们测试一下在centos002的/mnt目录下创建一个文件,看看是否同步到centos005的/opt/k8s目录下
查看centos005
6.5)下面我们开始编写my-nfs.yaml文件,并且将文件上传到/opt/pv目录下
内容如下:#这个是我们的版本信息 apiVersion: apps/v1beta1 #这个表示资源类型我们创建的是Deployment kind: Deployment metadata: #这个里面定义的是Deployment中我们创建的对象信息 #对象名称 name: nfs spec: #这个是对Deployment详细的定义 # 告知副本控制器ReplicaSet维护3个副本 replicas: 3 template: #template下面是用来描述pod的 #定义pod元数据信息 metadata: labels: app: nginx spec: #对pod进行详细的定义 containers: #在这里定义容器信息 #容器的名称 - name: nginx #定义我们要用到的镜像名称 image: hub.harbor.com/library/myapp:v1 #定义镜像的拉取策略 imagePullPolicy: IfNotPresent volumeMounts: #这里就是在容器中引用下面的定义的nfs挂载项 - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot nfs: server: 192.168.56.14 #这个目录我们需要提前在nfs服务器上建好 path: /opt/k8s/wwwroot --- #这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是service kind: Service metadata: #这个里面定义的是deployment中我们创建的对象信息 #对象名称 name: nginx-service labels: app: nginx spec: #这个是对详细对象的定义 ports: #指定容器需要用到的端口列表 - port: 80 targetPort: 80 selector: app: nginx type: NodePort
6.6)执行文件
命令:kubectl create -f my-nfs.yaml
6.7)测试我们在centos005服务器的/opt/k8s/wwwroot目录下创建一个index.html
我们在外网访问其中k8s集群中的nginx:
上面的效果说明我们成功了
2.PV&PVC
1)简介
管理 存储 和管理 计算 有着明显的不同。 PersistentVolume 给用户和管理员提供了一套API,抽象 出 存储 是如何 提供和消耗的细节 。在这里,我们介绍两种新的API资源: PersistentVolume(简称PV) 和 PersistentVolumeClaim(简称PVC) 。
- PersistentVolume(持久卷,简称PV)是集群内,由管理员提供的网络存储的一部分。就像 集群中的节点一样,PV也是集群中的一种资源。它也像Volume一样,是一种volume插件, 但是它的生命周期却是和使用它的Pod相互独立的。PV这个API对象,捕获了诸如NFS、 ISCSI、或其他云存储系统的实现细节。
- PersistentVolumeClaim(持久卷声明,简称PVC)是用户的一种存储请求。它和Pod类似, Pod消耗Node资源,而PVC消耗PV资源。Pod能够请求特定的资源(如CPU和内存)。PVC能 够请求指定的大小和访问的模式(可以被映射为一次读写或者多次只读)。
PVC允许用户消耗抽象的存储资源,用户也经常需要各种属性(如性能)的PV。集群管理员需要提 供各种各样、不同大小、不同访问模式的PV,而不用向用户暴露这些volume如何实现的细节。因为这 种需求,就催生出一种 StorageClass 资源。
StorageClass 提供了一种方式,使得管理员能够描述他提供的存储的等级。集群管理员可以将不 同的等级映射到不同的服务等级、不同的后端策略。
K8s为了做存储的编排 数据持久卷PersistentVolume 简称pv/pvc主要做容器存储的编排:
- PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理 pv 都是运维去考虑,用来管理外部存储的
- 静态 :提前创建好pv,比如创建一个100G的pv,200G的pv,让有需要的人拿去用,就是说pvc连接 pv,就是知道pv创建的是多少,空间大小是多少,创建的名字是多少,有一定的可匹配性
- PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节 使用多少个容量来 定义,比如开发要部署一个服务要使用10个G,那么就可以使用pvc这个资源对象来定义使用10个G, 其他的就不用考虑了
2)pv&pvc区别
PersistentVolume(持久卷) 和 PersistentVolumeClaim(持久卷申请) 是k8s提供的两种API资 源,用于抽象存储细节。
管理员关注如何通过pv提供存储功能而无需关注用户如何使用,同样的用户只需要挂载pvc到容器 中而不需要关注存储卷采用何种技术实现。
pvc和pv的关系与pod和node关系类似,前者消耗后者的资源。pvc可以向pv申请指定大小的存储 资源并设置访问模式,这就可以通过Provision -> Claim 的方式,来对存储资源进行控制。
3)生命周期
volume 和 claim 的生命周期,PV是集群中的资源,PVC是对这些资源的请求,同时也是这些资源 的“提取证”。PV和PVC的交互遵循以下生命周期:
- 供给
有两种PV提供的方式:静态和动态。- 静态
集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用 的。它们存在于Kubernetes API中,并可用于存储使用- 动态
当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。 这种供给基于StorageClass:PVC必须请求这样一个等级,而管理员必须已经创建和配置过这 样一个等级,以备发生这种动态供给的情况。请求等级配置为“”的PVC,有效地禁用了它自身 的动态供给功能。- 绑定
用户创建一个PVC(或者之前就已经就为动态供给创建了),指定要求存储的大小和访问模 式。master中有一个控制回路用于监控新的PVC,查找匹配的PV(如果有),并把PVC和PV 绑定在一起。如果一个PV曾经动态供给到了一个新的PVC,那么这个回路会一直绑定这个PV 和PVC。另外,用户总是至少能得到它们所要求的存储,但是volume可能超过它们的请求。 一旦绑定了,PVC绑定就是专属的,无论它们的绑定模式是什么。
如果没找到匹配的PV,那么PVC会无限期得处于unbound未绑定状态,一旦PV可用了,PVC 就会又变成绑定状态。比如,如果一个供给了很多50G的PV集群,不会匹配要求100G的 PVC。直到100G的PV添加到该集群时,PVC才会被绑定。- 使用
Pod使用PVC就像使用volume一样。集群检查PVC,查找绑定的PV,并映射PV给Pod。对于 支持多种访问模式的PV,用户可以指定想用的模式。一旦用户拥有了一个PVC,并且PVC被绑 定,那么只要用户还需要,PV就一直属于这个用户。用户调度Pod,通过在Pod的volume块 中包含PVC来访问PV。- 释放
当用户使用PV完毕后,他们可以通过API来删除PVC对象。当PVC被删除后,对应的PV就被认 为是已经是“released”了,但还不能再给另外一个PVC使用。前一个PVC的属于还存在于该PV 中,必须根据策略来处理掉。- 回收
PV的回收策略告诉集群,在PV被释放之后集群应该如何处理该PV。当前,PV可以被 Retained(保留)、 Recycled(再利用)或者Deleted(删除)。保留允许手动地再次声明 资源。对于支持删除操作的PV卷,删除操作会从Kubernetes中移除PV对象,还有对应的外部 存储(如AWS EBS,GCE PD,Azure Disk,或者Cinder volume)。动态供给的卷总是会被 删除。4)案例
4.1)首先创建一个my-pvc的yaml文件
内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是PVC kind: PersistentVolumeClaim metadata: #这个里面定义的是pvc中我们创建的对象信息 #对象名称 name: my-pvc spec: #这个是对PVC详细的定义 accessModes: #对权限的定义 #该Volume能被挂载在多个节点上,读写权限。 - ReadWriteMany resources: #对资源的描述 requests: #下面表示申请一个5G大小的空间 storage: 5Gi
执行my-pvc.yaml文件:
上面pvc处于pending状态的原因是因为pvc还没有找到合适的pv4.2)创建一个my-pv1.yaml和my-pv2.yaml文件
内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是PV kind: PersistentVolume metadata: #这个里面定义的是pvc中我们创建的对象信息 #对象名称 name: my-pv1 spec: #这个是对PVC详细的定义 capacity: #下面定义的空间大小是5G storage: 5Gi accessModes: #对权限的定义 #该Volume能被挂载在多个节点上,读写权限。 - ReadWriteMany nfs: #对资源的描述,将pv的地址挂载在nfs上,下面的地址需要提前创建好 path: /opt/k8s/demo1 server: 192.168.56.14
#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是PV kind: PersistentVolume metadata: #这个里面定义的是pvc中我们创建的对象信息 #对象名称 name: my-pv2 spec: #这个是对PVC详细的定义 capacity: #下面定义的空间大小是5G storage: 5Gi accessModes: #对权限的定义 #该Volume能被挂载在多个节点上,读写权限。 - ReadWriteMany nfs: #对资源的描述,将pv的地址挂载在nfs上,下面的地址需要提前创建好 path: /opt/k8s/demo2 server: 192.168.56.14
执行两个yaml文件:
4.3)下面我们再创建一个my-pod.yaml文件
内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是Pod kind: Pod metadata: #这个里面定义的是Pod中我们创建的对象信息 #对象名称 name: my-pod spec: #这个是对Deployment详细的定义 containers: #在这里定义容器信息 #容器的名称 - name: nginx #定义我们要用到的镜像名称 image: hub.harbor.com/library/myapp:v1 #定义镜像的拉取策略 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: #这里就是在容器中引用下面的定义的pvc挂载项 - name: www mountPath: /usr/share/nginx/html volumes: - name: www persistentVolumeClaim: #引用的pvc名称 claimName: my-pvc
执行yaml文件:
下面我们进入容器的内部,并且在绑定的目录创建一个index.html文件
因为这个pod绑定的是my-pvc,而且my-pvc和my-pv1绑定,并且my-pv1对应的nfs目录是/opt/k8s/demo1
我们找到/opt/k8s/demo1目录下:
3.StatefulSet
1)简介
用户通过yaml创建StatefulSet,StatefulSet找到StorageClass,StorageClass指定到nfsprovisioner为nfs的pv提供者,这是一个pod的服务,用来自动生成pv的,此pod来绑定到对应的nfs服 务。以此来通过nfs服务进行动态的pv生成,然后通过StatefulSet的pvc,与pod进行绑定,实现数据的 持久化存储。
2)创建两个pv,一个是st-pv1.yaml一个是st-pv2.yaml
st-pv1.yaml内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是PV kind: PersistentVolume metadata: #这个里面定义的是pv中我们创建的对象信息 #对象名称 name: nfspv1 spec: #这个是对PVC详细的定义 capacity: #下面定义的空间大小是5G storage: 10Gi accessModes: #对权限的定义 #该Volume只可被一个节点读写挂载 - ReadWriteOnce #定义垃圾回收策略为Retain persistentVolumeReclaimPolicy: Retain #定义storageClass的名称 storageClassName: nfs nfs: #对资源的描述,将pv的地址挂载在nfs上,下面的地址需要提前创建好 path: /opt/k8s/nfs server: 192.168.56.14
st-pv2.yaml内容如下:
#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是PV kind: PersistentVolume metadata: #这个里面定义的是pv中我们创建的对象信息 #对象名称 name: nfspv2 spec: #这个是对PVC详细的定义 capacity: #下面定义的空间大小是5G storage: 10Gi accessModes: #对权限的定义 #该Volume只可被一个节点读写挂载 - ReadWriteOnce #定义垃圾回收策略为Retain persistentVolumeReclaimPolicy: Retain #定义storageClass的名称 storageClassName: nfs nfs: #对资源的描述,将pv的地址挂载在nfs上,下面的地址需要提前创建好 path: /opt/k8s/nfs1 server: 192.168.56.14
3)执行两个脚本
4)创建一个my-st.yaml文件
内容如下:#这个是我们的版本信息 apiVersion: apps/v1 #这个表示资源类型我们创建的是StatefulSet kind: StatefulSet metadata: #这个里面定义的是StatefulSet中我们创建的对象信息 #对象名称 name: web spec: #这个是对StatefulSet详细的定义 selector: matchLabels: app: nginx serviceName: nginx replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx #定义我们要用到的镜像名称 image: hub.harbor.com/library/myapp:v1 ports: - containerPort: 80 name: web volumeMounts: #这里就是在容器中引用下面的定义的pvc挂载项 - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: #对象名称 name: www spec: accessModes: [ "ReadWriteOnce" ] #定义storageClass的名称 storageClassName: nfs resources: requests: storage: 1Gi
执行my-st.yaml文件:
由上面我们可以看出,我们创建了两个statefulSet,因为我们之前创建了nfspv1和nfspv2两个pv,所以statefulSet自动为我们创建了两个pvc,并且和pv做了绑定。5)下面我们在创建一个my-svc.yaml文件
内容如下:#这个是我们的版本信息 apiVersion: v1 #这个表示资源类型我们创建的是Service kind: Service metadata: #这个里面定义的是Pod中我们创建的对象信息 #对象名称 name: nginx labels: app: nginx spec: #这个是对Service详细的定义 ports: - port: 80 name: web clusterIP: None selector: app: nginx
执行:
下面我们在nfs服务器上的/opt/k8s/nfs目录下创建一个文件看看有没有同步到pod中即可:
更多推荐
所有评论(0)