【K8S in Action】第六章 卷:将磁盘挂载到容器

1. 介绍卷

每个新容器都是通过在构建镜像时加入的详细配置文件来启动的。 将此与pod 中容器重新启动的现象结合起来。

存储卷是 pod 的一个组成部分。这意味着在 pod 启动时创建卷, 并在删除 pod时销毁卷。 因此, 在容器重新启动期间, 卷的内容将保持不变, 在重新启动容器之后, 新容器可以识别前一个容器写入卷的所有文件。

另外,如果一个 pod 包含多个容器, 那这个卷可以同时被所有的容器使用。

1.1 卷类型

• emptyDir 用于存储临时数据的简单空目录。
• hostPath 用于将目录从工作节点的文件系统挂载到pod中。
• gitRepo 通过检出Git仓库的内容来初始化的卷。
• nfs 挂载到pod中的NFS共享卷。

2. 通过卷在容器之间共享数据

2.1 使用 emptyDir

关注它是如何用于在 pod 的多个容器之间共享数据的。卷从一个 目录开始,运行在 pod 内的应用程序可以写入它需要 的任何文件。pod 含两个容器和 个挂载在两个容器中的共用的卷,但在不同的路径上。

apiVersion: vl 
kind: Pod 
metadata: 
	name : fortune 
spec: 
	containers: 
	-image: luksa/fortune 
		name: html generator
		volumeMounts: 
		- name: html 
		  mountPath: /var/htdocs   名为html的卷挂载在/var/htdocs
	- image: nginx:alpine 
		name: web-server 
		volumeMounts : 
		- name: html
		  mountPath: /usr/share/nginx/html
		  readOnly: true 
		ports: 
		- containerPort: 80 
		  protocol: TCP 
	volumes                     
	- name: html                叫html的emptyDir卷,挂载在上面的两个容器中
	emptyDir: {}

将端口从本地机器转发到 pod 来实现,计算机的 808 端口来访问服务
 kubectl port-forward fortune 8080:80

volumes: 
 - name: html 
   emptyDir
	  medium: Memory          # 存在内存上

2.2 使用 Git 仓库作为存储卷

gitRepo 卷基本上也是 emptyDir 卷,它通过克隆 Git 仓库并在 pod时(但在创建容器之前 检出特定版本来填充数据。

注意:

  • 在创建gitRepo 卷后,它并不能和对应 repo 保持同步。 当向库推送新增 的提交时,文件将不会被更新。
  • 然而,如果所用 pod 是由ReplicationController 管理的,删除这个 pod 将触发新建一个新的 pod ,而这个新 pod
    的卷中将包含最新的提交。
apiVersion : vl 
kind: Pod 
metadata: 
	name: gi trepo-volume-pod
	spec: 
		containers: 
		- image: nginx:alpine 
			name: web -server 
			volumeMounts : 
		- name : html 
			mountPath: / usr/share/nginx/ html 
			readOnly: true 
			ports: 
				containerPort: 80 
				protocol: TCP 
	volumes                     
		- name: html                
		gitRepo: https://githubo.com/...
		revision: master     github 库的mater分支下载
		directory: .         创建在根目录

如果想要将私有的 Git repo 克隆到容器中, 则应该使用 gitsync sidecar 或类似的方法, 而不是使用 gitRepo 卷。

3 访问工作节点文件系统上的文件(hostPath卷)

大多数 pod 应该忽略它们的主机节点, 因此它们不应该访问节点文件系统上的任何文件。

hostPath 卷指向节点文件系统上的特定文件或目录。 在同一个节点上运行并在其 hostPath 卷中使用相同路径的 pod 可以看到相同的文件。

hostPath 卷是我们介绍的第 一种类型的持久性存储。切勿使用它们来持久化跨 pod的数据。

kubect1 get pod s --namespace kube-system

查看hostpaht 的使用, 切勿使用它们来持久化跨 pod的数据
kubectl describe po fluentd-kubia-4ebc2fle-9a3e --namespace kube-system

4 使用持久化存储

当运行在一个 pod 中的应用程序需要将数据保存到磁盘上, 并且即使该 pod 重新调度到另 一个节点时也要求具有相同的数据可用。此必须将其存储在某种类型的网络存储 (NAS) 中。

4.1 使用 GCE 持久磁盘作为底层存储机制。

同 一区域的 Kubemetes 集群中创建
gcloud container clusters list
NAME   ZONE          MASTER VERSION  MASTER_IP 
kubia europe-westl-b 1.2.5  		104.155.84.137


在europe-westl-b 区域中创建了集群 创建GCE 持久磁盘。创建了一个 1GiB 容量并命名为 mongodb的GCE 待久磁盘。
gcloud compute disks create --size=lGiB --zone=europe-west-b mongodb


创建—个使用GCE持久磁盘卷的pod。  Pod 直接使用了持久磁盘卷。
apiVersion: vl 
kind: Pod 
metadata:
	name: mongodb 
spec: 
	volumes: 
	- name: mongodb-data   卷名, 与挂载卷一致
	gcePersistentDisk:     类型是GCE持久磁盘
		pdName: mongodb    名称需要与创建的PD一致
		fsType: ext4       文件系统类型
	containers: 
	- image: mongo
		name: mongodb      
		volumeMountS:
		- name: mongodb-data    挂载卷
		  mountPath: /data/db
	  ports: 
		- containerPort: 27017
		  protocol: TCP

4.2 通过底层持久化存储使用其他类型的卷

如果集群是运行在自有的一组服务器上,那么就有大量其他可移植的选项在卷内挂载外部存储。例如,要挂载一个简单的NFS 共享,只需指定NFS 服务器和共享路径,如下面的代码清单所示

mongodb-pod-aws.yaml

volumes: 
- name: mongodb-data
	nfs:                    这个卷受NFS共享支持
	server: 1.2.3.4         NFS 服务IP
	path: /some/path        服务器提供的路径

要了解每个卷类型设置需要哪些属性的详细信息,可以转到KubemetesAPI引用中的KubernetesAPI定义,或者通过第三章展示的通过kubectl explain查找信息。

通过pod的卷来隐藏真实的底层基础设施,不就是Kubernetes存在的意义吗。研发人员来指定NFS 服务器的主机名会是一件感觉很糟糕的事情。

5 从底层存储技术解耦pod

Kubernetes 的基本理念, 这个理念旨在向应用程序及其开发人员隐藏真实的基础设施, 使他们不必担心基础设施的具体状态, 并使应用程序可在大量云服务商和数据企业之间进行功能迁移。 (每当有这种想法,就会创造出新的岗位,专门管理基础设施与集群配置。)

5.1 介绍持久卷和持久卷声明

由集群管理员设置底层存储, 然后通过Kubernetes API 服务器创建持久卷并注册。
持久卷声明可以当作 pod 中的一个卷来使用, 其他用户不能使用相同的持久卷。

创建持久卷
apiVersion: vl 
kind: PersistentVolume 
metadata:
	name: mongodb-pv 
spec: 
	capacity: 
		storage: lGi          对应的容量需求
	accessModes: 
	- ReadWriteOnce           可以被单个客户端挂载为读写模
	- ReadOnlyMany            可以被多个客户端挂载为只读
	persistentVolumeReclaimPolicy: Retain             声明被释放后被保留(不清理和删除)
	gcePersistentDisk:          PV 指定为之前创建的GCE持久磁盘.
		pdName: mongodb         持久卷支持的实际存储类型、 位置和其他属性。
		fsType: ext4            与直接Pod 直接使用GCE 的配置一样

create 创建后,  查看所有的持久卷, 持久卷不属于任何命名空间,集群层面的资源。
kubectl get pv
NAME    CAPACITY RECLAIMPOLICY    ACCESSMODES      STATUS 
mongodb-pv lGi   Retain          RWO,ROX           Available
创建持久卷声明

需要部署持久化存储的 pod ,将要用到之前创建的持久卷,但是不能直接在 pod 内使用,需要先声明一个。

创建好声明,k8s就会找到适当的持久卷并将其绑定到声明 :

  • 持久卷的容量必须足够大以满足声明的需求,
  • 并且卷的模式必须包含声明中指定的访模式 必须包含声明中的访问模式。

在该示例中,声明请求 1GiB 的存储空间和 ReadWriteOnce 访问模式。之前创建的持久卷符合刚刚声明中 的这两个条件,所以它被绑定到对应的声明中。

持久卷声明又只在特定的命名空间创建,所以持久卷和持久卷声明只能被同命名空间内的 pod 创建使用。

apiVersion: vl 
kind: PersistentVolumeClaim 
metadata:
	name: mongodb-pvc		 声明的名称,给pod 使用时需要用到
spec: 
	resources: 
		request:
		  storage: lGi      申请1G空间
	accessModes: 
	- ReadWriteOnce           可以被单个客户端挂载为读写模
	storageClassName :””      动态配置章节介绍


kubectl get pvc 
NAME         STATUS       VOLUME      CAPACITY      ACCESSMODES        AGE 
mongodb-pvc Bound      mongodb-pvc    l Gi           RWO,ROX           3s
pod 中使用持久卷声明
apiVersion: vl 
kind: Pod 
metadata: 
	name: mogodb
spec: 
	containers: 
	- image: mongo 
		name: mongodb 
		volumeMounts: 
		- name : mogodb-data
		  mountPath: /data/db 
		ports: 
		- containerPort: 27017 
		  protocol: TCP 
	volumes· 
		- name: mongodb data 
		persistentVolumeClaim:    
		claimName: mongodb-pvc     在 pod 的卷中引用持久卷声明名称


继续创建 pod ,现在检查这个 pod 是否确实在使用相同的持久卷和底层 GCEPD 。通过再次运行 MongoDB shell, 查看之前的数据

kubectl exec -it mongodb mongo
...
> use mystore 
switched to db mystore 

>db.foe.find() 
{"_id ": Objectid ("7a6leb9deOcfd512374cc75")"name""fpp"}

回收持久卷

先 删除 pod 和 持久卷声明, 如果再次创建持久卷声明会怎样?持久卷声明的状态显示为 Pending。未清理前不可绑定到全新的声明中。
通过使用相同的持久卷,新 pod 可以读取由前一个 pod 存放的数据,即使声明和pod 是在不同的命名空间中创建的(因此有可能属于不同的集群租户)

$ kubectl delete pod mongodb 
pod ” rnongodb" deleted 

$ ubectl delete pvc ngodb-pvc
persistentvolurneclairn ” rnongodb pvc" deleted


$ kubectl get pvc 
NAME       STATUS   VOLUME CAPACITY ACCESSMODES AGE 
mogodb-pvc  Pending                              13s

列出持久卷
NAME   CAPACITY  ACCESSMODES   STATUS        CLAIM      REASON    AGE 
mogodb-pv lGi    RWO,ROX      Released    default/rnongodb-pvc

手动回收持久卷:
persistentVolumeReclaimPolicy 设置为 Reta : 在持久卷从持久卷声明中释放后仍然能保留它的卷和数据内容。唯一方法是删除和 新创建 持久卷资源。

自动回收持久卷:

  • Recycle 第一种删除卷的内容并使卷可用于再次声明
  • Delete 策略删除底层存储

6 持久卷的动态卷配置

通过动态配置持久卷来自动执行此任务。集群管理员可以创建持久卷配置,并定义一个或多个 Storage Class, 从而让用户选择他们想要的持久卷类型而不仅仅只是创建持久卷。

创建 Storage Class资源后,用户可以在其持久卷声明中按名称引用存储类

apiVersion: storage.kBs.io/vl 
kind: StorageClass 
metadata : 
	name:  fast
provisioner: kubernetes.io/gce-pd   置备程序, 配置持久卷的插件
parameters:                       传达parameters的参数
	type:pd-ssd         
	zone:europe-westl-b


apiVersion: vl 
kind: PersistentVolumeClaim 
metadata:
	name: mongodb-pvc		 声明的名称,给pod 使用时需要用到
spec: 
	storageClassName:fast   PVC 请求自定义存储类
	resources: 
		request:
		  storage: lGi      申请1G空间
	accessModes: 
	- ReadWriteOnce           可以被单个客户端挂载为读写模
不指定存储类的动态配置

将看将持久卷附加到的最新和最简单的方法。SC 作为 storageclass 的简写。可以在不指定 storageClassName 属性的情况下创建 PVC,并且(在 Google K8s引擎上〉将为你提供 pd-standard 类型的 GCE 持久磁盘

列出存储类
$ kubectl get sc 
NAME                 TYPE 
fast                kubernetes.io/gce-pd 
standard (default)  kubernetes.io/gce-pd

检查默认存储类
kubectl get sc standard -o yaml

annotations:      将存储类型标记为默认
	storageclass.beta.kubernetes io/is-default-class:“true"   
parameters:    
	type: pd-standard 
provisi r: kubernetes.io/gce-pd

如果持久卷声明没有明确指出要使用哪个存储类, 默认存储类会用于动态提供持久卷的内容。

apiVersion: vl 
kind: PersistentVolumeClaim 
metadata:
	name: mongodb-pvc2		 声明的名称,给pod 使用时需要用到
spec: 
	resources:               没有指定PVC 请求自定义存储类
		request:
		  storage: lGi      申请1G空间
	accessModes: 
	- ReadWriteOnce           可以被单个客户端挂载为读写模


kubect1  getpvc mongodb-pvc2 
NAME        STATUS VOLUME   CAPACITY ACCESSMODES STORAGECLASS 
mongodb-pvc2 Bound pvc-95a5ecl2 lGi   RWO         standard
强制将持久卷声明绑定到预配置的其中一个持久卷
kind: PersistentVolumeClaim 
spec: 
	StorageClassName: ""

为什么将 storageClassNarne 设置为一个空字符串,当你想让 PVC 绑定到你手动配置的 PV 时。

如果尚未将 storageClassName 属性设置为空字符串, 则尽管已存在适当的预配置待久卷, 但动态卷置备程序仍将配置新的持久卷。