一、存储方式
- ConfigMap
- Secret
- Volume
- Persistent Volume
1.1 ConfigMap
ConfigMap功能在Kubernetes1.2版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API给我们提供了向容器中注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象
1.1.1 ConfigMap的创建
1、使用目录创建
$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties
$ cat docs/user-guide/configmap/kubectl/game.properties
$ cat docs/user-guide/configmap/kubectl/ui.properties
// 创建configmap
$ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
其中,–from-file 指定在目录下的所有文件都会被用在ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容
2、使用文件创建
只要指定为一个文件就可以从单个文件中创建ConfigMap
// 与上面的区别是一个使用的是目录,一个使用的是文件
$ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties
$ kubectl get configmap game-config-2 -o yaml
其中,–from-file 这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的
3、使用字面值创建
使用文字值创建,利用 –from-literal 参数传递配置信息,该参数可以使用多次,格式如下:
$ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
$ kubectl get configmaps special-config -o yaml
1.1.2 Pod中使用ConfigMap
1、使用ConfigMap来替代环境变量
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
special.how:very
special.type:charm
apiVersion:v1
kind:ConfigMap
metadata:
name:env-config
namespace:default
data:
log.level:INFO
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image: www.baidu.com/library/myapp:v1
# 打印环境变量
command: ["/bin/sh", "-c", "env"]
# 以下为导入special ConfigMap
env:
- name:SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:special.how
- name:SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:special.type
# 以下为导入env ConfigMap
envFrom:
- configMapRef:
name:env-config
restartPolicy:Never
2、使用ConfigMap设置命令行参数
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
special.how:very
special.type:charm
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image: www.baidu.com/library/myapp:v1
# 打印环境变量
command: ["/bin/sh", "-c", "echo ${SPECIAL_LEVEL_KEY} ${SPECIAL_TYPE_KEY}"]
# 以下为导入special ConfigMap
env:
- name:SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:special.how
- name:SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:special.type
restartPolicy:Never
3、通过数据卷插件使用ConfigMap
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
special.how:very
special.type:charm
在数据卷里面使用这个ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
1.1.3 ConfigMap的热更新
apiVersion:v1
kind:ConfigMap
metadata:
name:log-config
namespace:default
data:
log.level:INFO
---
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:my-nginx
spec:
replicas:1
template:
metadata:
labels:
run:my-nginx
spec:
containers:
- name:my-nginx
image:www.baidu.com/library/myapp:v1
ports:
- containerPort:80
volumeMounts:
- name:config-volume
mountPath:/etc/config
volumes:
- name:config-volume
configMap:
name:log-config
修改ConfigMap
$ kubectl edit configmap log-config
修改 log_level 的值为DEBUG,等待大概10秒钟时间,再次查看环境变量的值
⚠️注意:ConfigMap如果以 ENV 的方式挂载至容器,修改 ConfigMap 并不会实现热更新
ConfigMap更新后滚动更新Pod
更新ConfigMap目前并不会触发相关Pod的滚动更新,可以通过修改pod annotations的方式强制触发滚动更新
kubectl path deployment my-nginx --patch '{"spec":{"template":{"metadata":{"annotations":{"version/config":"20200101"}}}}}'
在这个例子里,.spec.template.metadata.annotations中添加 version/config,每次通过修改 version/config 来触发滚动更新
⚠️注意:更新ConfigMap后:
(1)使用该ConfigMap挂载的Env不会同步更新
(2)使用该ConfigMap挂载的Volume中的数据需要一段时间(大约10秒)才能同步更新
1.2 Secret
1.2.1 Secret存在的意义
Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用
1.2.2 Secret三种类型
- Service Account:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到Pod的
/run/secrets/kubernetes.io/serviceaccount
目录中 - Opaque:base64编码格式的Secret,用来存储密码、密钥等
- kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息
Service Account
Opaque Secret
1、创建说明
Opaque类型的数据是一个map,要求value是base64编码
// Linux下使用base64命令加密字符串
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
NWYyZDF1MmU2N2Rm
secrets.yml
apiVersion:v1
kind:Secret
metadata:
name:mysecret
type:Opaque
data:
password:NWYyZDF1MmU2N2Rm
username:YWRtaW4=
2、使用方式
(1)将Secret挂载到Volume中,使用时会自动解密
apiVersion:v1
kind:Pod
metadata:
labels:
name:secret-test
name:secret-test
spec:
volumes:
- name:secrets
secret:
secretName:mysecret
containers:
name:db
image:www.baidu.com/library/myapp:v1
volumeMounts:
- name:secrets
mountPath:"/etc/secrets"
readOnly:true
(2)将Secret导出到环境变量中
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:pod-deployment
spec:
replicas:2
template:
metadata:
labels:
app:pod-deployment
spec:
containers:
- name:pod-1
image:www.baidu.com/library/myapp:v1
ports:
- containerPort:80
env:
- name:TEST_USER
valueFrom:
secretKeyRef:
name:mysecret
key:username
- name:TEST_PASSWORD
valueFrom:
secretKeyRef:
name:mysecret
key:password
kubernetes.io/dockerconfigjson
1、使用 kubectl 创建 docker registry 认证的secret
$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
2、创建一个Pod
apiVersion:v1
kind:Pod
metadata:
name:foo
spec:
containers:
name:foo
image:www.baidu.com/library/myapp:v1
imagePullSecrets:
- name:myregistrykey
1.3 Volume
1.3.1 产生背景
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet会重启它,但是容器中的文件将会丢失(即容器以初始化的状态重新启动);其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes中的volume抽象就很好的解决了上述问题
1.3.2 Volume简介
Kubernetes中的卷有明确的寿命,与封装它的Pod相同。所以,卷的生命比Pod中的所有容器都长,当这些容器重启时数据会被保留下来。当然,当Pod不存在时,卷也不会存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod可以同时使用任意数量的卷
1.3.3 卷的类型
Kubernetes支持以下类型的卷:
- awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwardAPI、emptyDir、fc、flocker、gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret、storageos、vsphereVolume
1、emptyDir
当Pod被分配给节点时,首先创建 emptyDir 卷,并且该Pod只有在该节点上运行时,该卷才会存在。如同卷的名字一样,它最初是空的。Pod中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中相同或不同路径上。当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删除
⚠️注意:容器崩溃不会从节点中移除Pod,即 emptyDir 卷中的数据在容器崩溃时是安全的
emptyDir的用法:
- 临时空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时的检查点
- web服务器容器提供数据时,保存内容管理器容器提取的文件
apiVersion:v1
kind:Pod
metadata:
name:test-pd
spec:
containers:
name:test-container
image:www.baidu.com/library/myapp:v1
volumeMounts:
- mountPath: /cache
name:cache-volume
volumes:
- name:cache-volume
emptyDir:{}
2、hostPath
hostPath卷将主机节点的文件系统中的文件或者目录挂载到集群中
hostPath的用法:
- 运行需要访问Docker内部的容器,使用
/var/lib/docker
的 hostPath - 在容器中运行cAdvisor,使用
/dev/cgroups
的hostPath
除了所需的path属性之外,用户还可以为hostPath卷指定type
- 空字符串:空字符串(默认)用于向后兼容,这意味着在挂载hostPath卷之前不会执行任何检查
- DirectoryOrCreate:如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权
- Directory:给定的路径下必须存在目录
- FileOrCreate:如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权
- File:给定的路径下必须存在文件
- Socket:给定的路径下必须存在UNIX套接字
- CharDevice:给定的路径下必须存在字符设备
- BlockDevice:给定的路径下必须存在块设备
使用这种卷类型时需要注意
- 由于每个节点上的文件都是不同的,具有相同配置的Pod在不同节点上的行为可能会有所不同
- 当Kubernetes按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源
- 在底层主机上创建的文件或目录只能由root写入,需要在特权容器中以root身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷
举例:
apiVersion:v1
kind:Pod
metadata:
name:test-pd
spec:
containers:
- image:www.baidu.com/library/myapp:v1
name:test-container
volumeMounts:
- mountPath: /test-pd
name:test-volume
volumes:
- name:test-volume
hostPath:
# 主机本地目录
path:/data
type:Directory
1.4 Persistent Volume(PV)
1.4.1 概念
是由管理员设置的存储,它是集群的一部分,就像节点是集群中的资源一样,PV也是集群中的资源。PV是Volume类的卷插件,但是具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定于云供应商的存储系统
1.4.2 PersistentVolumeClaim(PVC)
是用户存储的请求,它与Pod相似。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。PVC可以请求特定的大小和访问模式(例如,可以以读/写一次 或 只读多次模式挂载)
1.4.3 静态PV
集群管理员创建一些PV。他们带有可供集群用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费
1.4.4 动态
当管理员创建的静态PV都不匹配用户的 PVC 时,集群可能会尝试动态为PVC创建卷。此配置基于 StorageClasses:PVC必须请求【存储类】,并且管理员必须创建并配置该类才能进行动态创建。声明该类为“”可以有效地禁用其动态配置
要启动基于存储级别的动态配置,集群管理员需要启动API Server上的DefaultStorageClass【准入控制器】。例如,通过确保DefaultStorageClass位于API Server组件的 --admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作
1.4.5 绑定
master中的控制环路监视新的PVC,寻找匹配的PV,并将他们绑定在一起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦PV和PVC绑定后,PVC绑定是排他性的,不管它们是如何绑定的。PVC和PV绑定是一对一的映射
1.4.6 持久卷声明的保护
PVC保护的目的是确保由Pod正在使用的PV不会从系统中移除,因为如果被移除的话可能会导致数据丢失
⚠️:当Pod状态为Pending,并且Pod已经分配给节点或Pod为Running状态时,PVC处于活动状态
当启动PVC保护alpha功能时,如果用户删除了一个Pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何Pod使用
1.4.7 持久化卷类型
PV类型以插件形式实现。Kubernetes目前支持以下插件类型
- GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC(Fibre Channel)FlexVolume Flocker NFS iSCSI RBD CephFS等等
1.4.8 PV访问模式
PV可以以资源提供者支持的任何方式挂载到主机上。供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上,每个PV都有一套自己的用来描述特定功能的访问模式
- ReadWriteOnce(RWO) ----该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany(ROX) ----该卷可以被多个节点以只读模式挂载
- ReadWriteMany(RWX) ----该卷可以被多个节点以读/写模式挂载
⚠️:一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。例如,GCEPersistentDisk可以由单个节点作为 ReadWriteOnce 模式挂载,或由多个节点以 ReadOnlyMany 模式挂载,但不能同时挂载
1.4.9 回收策略
- Retain(保留):手动回收
- Recycle(回收):基本删除(rm -rf /thevolume/*)
- Delete(删除):关联的存储资产(例如:AWS EBS、GCE PD)将被删除
当前,只有NFS和HostPath支持回收策略,AWS EBS、GCE PD、Azure Disk和Cinder卷支持删除策略
1.4.10 状态
卷可以处于以下的某种状态
- Available(可用)---- 一块空闲资源还没有被任何声明绑定
- Bound(已绑定)---- 卷已经被声明绑定
- Released(已释放)---- 声明被删除,但是资源还未被集群重新声明
- Failed(失效)---- 该卷的自动回收失败
1.4.11 关于StatefulSet
- 匹配Pod name(网络标识)的模式为: ( s t a t e f u l 名 称 ) − (stateful名称)- (stateful名称)−(序号),比如上面的示例:web-0,web-1,web-2
- StatefulSet 为每个Pod副本创建了一个DNS域名,这个域名的格式为:$(podname).(headless server name),也就是意味着服务间是通过Pod域名来通信而非Pod IP,因为当Pod所在Node发生故障时,Pod会被转移到其他Node上,Pod IP会发生变化,但Pod域名不会有变化
- StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:(servicename).(namespace).svc.cluster.local。其中,cluster.local指的是集群的域名
- 根据volumeClaimTemplates,为每个Pod创建一个PVC,PVC的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的volumeMounts.name=www,Pod name=web-0,创建出来的PVC是www.web-0
- 删除Pod不会删除其PVC,手动删除PVC将自动释放PV