Kubernetes 学习笔记(七)--- K8S存储卷、Con
目录
emptyDir
gitRepo
hostPath
nfs
pvc
1. 配置NFS共享存储:
2. 创建PV
3. 定义PVC,并使用
accessModes <[]string>
存储类(StorageClass)
configmap
1. 通过命令行创建ConfigMap
2. 通过yaml文件创建ConfigMap
3. 使用ConfigMap
secret
存储卷是属于Pod,不属于容器。但是可以在容器中去挂载存储卷来使用。
K8S上可用的存储卷类型:
emptyDir
空目录,只在节点本地使用,一旦Pod被删除,则这个存储卷也会随之删除;所以,emptyDir这种存储卷不是做为持久化而设计的,可以做为临时目录,按需创建。也可以当做缓存空间来使用。emptyDir存储卷的生命周期同Pod容器。
使用示例:https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
gitRepo
在Pod创建时,会自动连接至Git仓库(需要确保宿主机有git命令,它是基于宿主机来驱动的。),将Git仓库里的代码克隆至宿主机的某个目录,并把这个目录做为存储卷挂载至Pod上。实质上gitRepo
是建立在emptyDir
之上的。gitRepo
本质上也是emptyDir
。
使用示例:https://kubernetes.io/docs/concepts/storage/volumes/#gitrepo
hostPath
宿主机路径,将宿主机文件系统上的路径做为存储卷挂载至Pod容器中。Pod删除后,此存储卷不会被删除,数据不会丢失。不过在跨节点调度时,必须保证每个节点主机上的相同路径有相同的数据。
使用示例:https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
nfs
通过命令:kubectl explain pod.spec.volumes.nfs
查看用法 。
pvc
PVC (Persistent Volume Claim)持久化卷请求。
PVC示意图:
image.png
存储设备由存储管理员去管理,pv由K8S集群管理员定义,pvc由K8S用户或开发者定义
image.png
使用PVC的流程:
- 配置存储空间 --- 由存储管理员配置存储设备(如NFS,iSCSI,Ceph RBD,Glusterfs),并且划割好了很多可被独立使用的存储空间;
- 定义PV --- K8S集群管理员将配置好的那些存储空间引入至K8S集群中,定义成PV (Persistent Volume,持久化卷);
-
定义PVC --- K8S用户在创建Pod时如果要用到PVC时,必须先创建PVC( 在K8S集群中找一个能符合条件的存储卷PV来用)。注意:PV和PVC是一一对应关系,一旦某个PV被一个PVC占用,那么这个PV就不能再被其他PVC占用,被占用的PV的状态会显示为
Bound
。PVC创建以后,就相当于一个存储卷,可以被多个 Pod所使用。 -
使用PVC --- 在Pod中去使用PVC,如果符合PVC条件的PV不存在,而这时去使用这个PVC,则Pod这时会显示
Pending(挂起)
状态。
接下来演示一个使用NFS做为后端存储的PVC使用示例:
1. 配置NFS共享存储:
这里用192.168.100.132做为NFS共享存储服务器。
# 安装NFS软件包
yum install nfs-utils -y
mkdir /data/nfs/volumes/v{1,2,3,4,5} -p
# 编辑/etc/exports文件
[root@fh-db nfs]# cat /etc/exports
/data/nfs/volumes/v1 192.168.100.0/24(rw,no_root_squash)
/data/nfs/volumes/v2 192.168.100.0/24(rw,no_root_squash)
/data/nfs/volumes/v3 192.168.100.0/24(rw,no_root_squash)
/data/nfs/volumes/v4 192.168.100.0/24(rw,no_root_squash)
/data/nfs/volumes/v5 192.168.100.0/24(rw,no_root_squash)
# 导出共享目录
[root@fh-db nfs]# exportfs -arv
exporting 192.168.100.0/24:/data/nfs/volumes/v5
exporting 192.168.100.0/24:/data/nfs/volumes/v4
exporting 192.168.100.0/24:/data/nfs/volumes/v3
exporting 192.168.100.0/24:/data/nfs/volumes/v2
exporting 192.168.100.0/24:/data/nfs/volumes/v1
# 启动nfs
[root@fh-db nfs]# systemctl start nfs
[root@fh-db nfs]# showmount -e localhost
Export list for localhost:
/data/nfs/volumes/v5 192.168.100.0/24
/data/nfs/volumes/v4 192.168.100.0/24
/data/nfs/volumes/v3 192.168.100.0/24
/data/nfs/volumes/v2 192.168.100.0/24
/data/nfs/volumes/v1 192.168.100.0/24
注意:K8S集群节点上也需要安装nfs:
yum install nfs-utils -y
,否则在使用nfs做为存储卷时不能正常挂载。
2. 创建PV
PV也是标准的K8S资源,但是PV是K8S集群级别的资源,而不是namespace(名称空间)级别的资源。所以在定义PV时,不需要指定namespace。这就意味着PV不限名称空间,所有名称空间都可使用。需要注意的是PVC是namespace级别的资源。
PV的访问模式(accessModes <[]string>
)
- ReadWriteOnce --- 单路读写,显示简写:RWO
- ReadOnlyMany --- 多路只读,显示简写:ROX
- ReadWriteMany --- 多路读写,显示简写:RWX
注意:定义PV清单文件时,访问模式不支持简写,简写仅用于显示时。
需要注意的是,有些后端存储设备是不支持多路读写的,在定义PV的访问模式时,需要确认后端存储设备支持的访问模式。PV的访问模式只能是存储设备支持的访问模式的子集。参考如下:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
capacity
: 指定PV的可用存储容量,单位:M | G | T | P | E (1000换算),Mi | Gi | Ti | Pi | Ei (1024换算)
PV的回收策略(persistentVolumeReclaimPolicy <string>
):
如果某个已经绑定PV的PVC被删除了,那么这个PV将被回收,回收策略有以下三种:
-
Retain
--- 默认,表示保留PV中存在的数据,在PV下次被PVC绑定时,数据还存在;通常都使用这种回收策略。 -
Recycle
--- 回收,表示将删除PV里面的数据,并将其状态置为空闲状态,供其他PVC去绑定;危险! -
Delete
--- 删除,表示如果PVC删除了,那么PV也随之删除,数据会被清除。危险!
编辑PV清单文件:vim pv-demo.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/nfs/volumes/v1
server: 192.168.100.132
accessModes: ['ReadWriteOnce', 'ReadWriteMany', 'ReadOnlyMany']
capacity:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/nfs/volumes/v2
server: 192.168.100.132
accessModes: ['ReadWriteOnce', 'ReadWriteMany']
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/nfs/volumes/v3
server: 192.168.100.132
accessModes: ['ReadOnlyMany']
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/nfs/volumes/v4
server: 192.168.100.132
accessModes: ['ReadOnlyMany', 'ReadWriteOnce']
capacity:
storage: 15Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/nfs/volumes/v5
server: 192.168.100.132
accessModes: ['ReadWriteOnce', 'ReadWriteMany', 'ReadOnlyMany']
capacity:
storage: 10Gi
应用PV清单文件pv-demo.yaml
[root@k8s-master manifests]# kubectl apply -f pv-demo.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
查看生成的PV:
[root@k8s-master manifests]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 20Gi RWO,ROX,RWX Retain Available 7m
pv002 10Gi RWO,RWX Retain Available 7m
pv003 5Gi ROX Retain Available 7m
pv004 15Gi RWO,ROX Retain Available 7m
pv005 10Gi RWO,ROX,RWX Retain Available 7m
3. 定义PVC,并使用
accessModes <[]string>
PVC也需要定义访问模式,且PVC的访问模式必须得是PV的子集。也就是说只有符合PVC访问模式的PV,才能够与PVC进行绑定。注意:PVC必须与Pod在同一名称空间才能被Pod使用。
编辑清单文件pod-vol-pvc.yaml
---
# 定义PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ['ReadWriteMany']
resources:
requests:
storage: 8Gi
---
# 定义Pod
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-pvc
namespace: default
spec:
containers:
- name: myapp-pvc
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc # 使用上述定义的PVC名称
应用清单文件:
[root@k8s-master manifests]# kubectl apply -f pod-vol-pvc.yaml
persistentvolumeclaim/mypvc created
pod/pod-vol-pvc created
再来查看PV列表:
image.png
从上图可以看出,名为pv002的PV符合PVC定义的条件被绑定了。
查看PVC:
[root@k8s-master manifests]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv002 10Gi RWO,RWX 22
注意:如果此时发现Pod没有正常运行,查看pod描述信息中的Events,显示Pod挂载volume pv002失败。去检查Pod调度到的那个节点主机是否安装了nfs-utils包。然后安装即可:
image.pngyum install -y nfs-utils
。
在kubernetes 1.9+ ,只要PV被PVC绑定着,那么PV就不能被删除。
存储类(StorageClass)
使用上述PVC时,有一个弊端:当K8S用户创建要使用PVC时,必须确保K8S集群中已经存在符合PVC条件的PV,否则Pod就会处于Pending(挂起)状态。
存储类(StorageClass)就是来解决这个问题的。使用存储类时,无需事先创建好PV。而是在使用PVC时,根据PVC的条件,动态创建PV供PVC绑定。
定义存储类,可以从任意维度去给存储分类:如存储性能、存储所在区域等等。。。
定义好存储类以后,PVC再去申请PV时,不再直接针对PV进行绑定,而是通过存储类去动态创建符合PVC条件的PV,再进行绑定。
但是后端的存储设备必须要支持RESTful 风格的创建请求接口,才能通过存储类实现PV的动态供给。支持RESTful 有后端存储设备有Ceph,Glusterfs通过第三方接口也可以实现RESTful风格的接口。但是去部署这样的后端存储设备,也不是一件容易的事件。所以存储类(StorageClass)的操作先暂时放下,后续再说。。。
configmap
secret和configmap可以理解为特殊的存储卷,但是它们不是给Pod提供存储功能的,而是提供了从集群外部向集群内部的应用注入配置信息的功能。ConfigMap扮演了K8S集群中配置中心的角色。ConfigMap定义了Pod的配置信息,可以以存储卷的形式挂载至Pod中的应用程序配置文件目录,从configmap中读取配置信息;也可以基于环境变量的形式,从ConfigMap中获取变量注入到Pod容器中使用。但是ConfigMap是明文保存的,如果用来保存数据库账号密码这样敏感信息,就非常不安全。一般这样的敏感信息配置是通过secret
来保存。secret
的功能和ConfigMap一样,不过secret是通过Base64的编码机制保存配置信息。
1. 通过命令行创建ConfigMap
使用nginx_port=8080
和nginx_server_name=myapp.magedu.com
创建名为my-config
的新ConfigMap
kubectl create configmap my-config --from-literal=nginx_port=8080 --from-literal=nginx_server_name=myapp.magedu.com
创建一个新ConfigMap名为my-www,指定key名为key1,value为file1.txt的内容
kubectl create configmap my-www --from-file=www_conf=./www.conf
创建一个新ConfigMap名为my-www,key名默认为文件名www.conf,value为文件www.conf的内容。
kubectl create configmap my-www --from-file=./www.conf
2. 通过yaml文件创建ConfigMap
编辑文件:nginx-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-cm-yaml
namespace: default
data:
nginx_server_port: "8088"
nginx_server_name: "myapp01.magedu.com"
注意:如上,
ConfigMap
的清单文件相对较简单,它没有spec
字段,data
字段的内容就是配置信息数据,配置信息数据的值必须用引号包含(如:nginx_server_port: "8088"
),否则创建时会报错。
根据清单文件创建ConfigMap
kubectl apply -f nginx-cm.yaml
获取前两步创建的ConfigMap
[root@k8s-master manifests]# kubectl get cm
NAME DATA AGE
my-config 2 4h
my-www 1 1h
nginx-cm-yaml 2 50m
注意:
cm
为configmap
的简写。可通过kubectl api-resources
命令查看K8S所有资源和对应简写。
3. 使用ConfigMap
从ConfigMap中获取配置信息的方法有两种:
- 一种是利用环境变量将配置信息注入Pod容器中的方式,这种方式只在Pod创建的时候生效,这就意味着在ConfigMap中的修改配置信息后,更新的配置不能被已经创建Pod容器所应用。
- 另一种是将ConfigMap做为存储卷挂载至Pod容器内,这样在修改ConfigMap配置信息后,Pod容器中的配置也会随之更新,不过这个过程会有稍微的延迟。
先来看看通过环境变量注入配置信息的方式:
vim pod-configmap-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-configmap
labels:
name: myapp-configmap
config: configmap
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
env:
- name: NGINX_SERVER_PORT
valueFrom:
configMapKeyRef:
name: my-config
key: nginx_port
- name: NGINX_SERVER_NAME # 传入Pod容器中的变量名为NGINX_SERVER_NAME,值为
valueFrom:
configMapKeyRef:
name: my-config # 选择需要的configmap的名称
key: nginx_server_name
要点:
NGINX_SERVER_PORT
和NGINX_SERVER_NAME
是传入Pod容器内的变量名,它的值是从名为my-config(ConfigMap)中对应的KEY获取。NGINX_SERVER_NAME=nginx_server_name=myapp.magedu.com
应用清单文件创建Pod:
kubectl apply -f pod-configmap-env.yaml
进入Pod容器中验证变量是否存在:
# 进入指定Pod的命令
kubectl exec -it myapp-configmap -- /bin/sh
image.png
从上图可以看出变量已经传入Pod容器中了。
接下来再看一下把ConfigMap当作存储卷挂载至Pod中的用法:
编辑vim pod-configmap-vol-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-configmap-vol-2
labels:
name: pod-configmap-vol-2
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: my-cm-www
mountPath: /etc/nginx/conf.d/ # 将名为my-www的configmap挂载至Pod容器的这个目录下。
volumes:
- name: my-cm-www
configMap: # 存储卷类型选configMap
name: my-www # 选择一个configmap
应用清单文件创建Pod:
kubectl apply -f pod-configmap-vol-2.yaml
进入名为pod-configmap-vol-2的Pod中验证:
image.png从上图中可以看出ConfigMap已经挂载至Pod容器中了。
secret
待续。。。