为了管理存储,Kubernetes提供了Secret用于管理敏感信息,ConfigMap存储配置,Volume、PV、PVC、StorageClass等用来管理存储卷。
3.9.1 Secret
Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
Secret可以以Volume或者环境变量的方式使用。
Secret有三种类型:
- Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;
- Opaque:base64编码格式的Secret,用来存储密码、密钥等。
- kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
Opaque Secret
Opaque类型的数据是一个map类型,要求value是base64编码格式:
echo -n "admin"| base64
secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
创建好Secret之后,有两种方式使用它:
- 以Volume方式
- 以环境变量方式
将Secret挂载到Volume中
apiVersion: v1
kind: Pod
metadata:
labels:
name: db
name: db
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- image: gcr.io/my_project_id/pg:v1
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/secrets"
readOnly: true
ports:
- name: cp
containersPort: 5432
hostPort: 5432
将Secret导出到环境变量中
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-deployment
spec:
replicas: 2
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: wordpress
visualize: "true"
spec:
containers:
- name: "wordpress"
image: "wordpress"
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
kubernetes.io/dockerconfigjson
可以直接使用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
也可以直接读取~/.docker/config.json的内容来创建:
cat ~/.docker/config.json | base64
cat > myregistry.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
data:
.dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg
type: kubernetes.io/dockerconfigjson
EOF
kubectl create -f myregistry.yaml
在创建Pod时,通过imagePullSecrets来引用创建的myregistrykey:
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: janedoe/awesomeapp:v1
imagePullSecrets:
- name: myregistrykey
Service Account
Service Account用来访问Kubernetes API, 由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中。
3.9.2 ConfigMap
ConfigMap可以用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。
ConfigMap
ConfigMap API资源用来保存key-value pair配置数据,这个数据可以在Pods里使用,或者被用来为像controller一样的系统组件存储配置数据。
ConfigMap更方便的处理不包含敏感信息的字符串。
使用ConfigMap配置来创建Kubernetes Volumes,ConfigMap中的每个data项都会成为一个新文件:
kind: ConfigMap
apiVersion: v1
metadata:
creationTimestamp: 2020-08-23T15:34:00Z
name: example-config
namespace: default
data:
example.property.1: hello
example.property.2: world
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
data一栏包括了配置数据,ConfigMap可以被用来保存单个属性,也可以用来保存一个配置文件。
配置数据可以通过多种方式在Pods里被使用。
ConfigMaps可以被用来:
- 设置环境变量的值
- 在容器里设置命令行参数
- 在数据卷里面创建Config文件
用户和系统组件都可以在ConfigMap里存储配置数据。
创建ConfigMaps
可使用该命令,用给定值、文件或目录来创建ConfigMap。
kubectl create configmap
使用目录创建
比如我们已经有了一些配置文件,其中包含了我们想要设置的ConfigMap的值:
$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties
$ cat docs/user-guide/configmap/kubectl/game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
$ cat docs/user-guide/configmap/kubectl/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
使用下面的命令创建一个包含目录中所有文件的ConfigMap。
kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
—from-file指定在目录下的所有文件都会被用在ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容。
以yaml格式输出配置:
kubectl get configmaps game-config -o yaml
使用文件创建
只要指定一个文件就可以从单个文件中创建ConfigMap。
kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties
kubectl get configmaps game-config-2 -o yaml
—from-file可以使用多次。
使用字面值创建
使用字面值创建,利用—from-literal 参数传递配置信息,该参数可使用多次,格式如下:
kubectl create configmap special-config --from-literal=special.how=very --from-litral=special.type=charm
kubectl get configmaps special-config -o yaml
Pod中使用ConfigMap
ConfigMap可用来填入环境变量。
apiVerion: 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
在Pod中使用ConfigMap:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: speical-config
key: special.type
envFrom:
- configMapRef:
name: env-config
restartPolicy: Never
用ConfigMap设置命令行参数
ConfigMap可以用来设置容器中的命令或参数值。
它使用的是Kubernetes的$(VAR_NAME)替换语法:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
为了将ConfigMap中的值注入到命令行的参数里面,需要使用环境变量替换语句${VAR_NAME}。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
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
通过数据卷插件使用ConfigMap
还是这个ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
将文件填入数据卷:
apiVersion: v1
kind: Pod
metadata:
name:
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","cat /etc/config/special.how" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
restartPolicy: Never
运行这个Pod的输出是very。
也可以在ConfigMap值被映射的数据卷里控制路径。
apiVersion: v1`
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: special.how
path: path/to/special-key
restartPolicy: Never
运行该Pod的结果为very。
3.9.2.1 ConfigMap热更新
ConfigMap是用来存储配置文件的Kubernetes资源对象,所有的配置内容都存储在etcd中。
更新ConfigMap后,
- 使用该ConfigMap挂载的Env不会同步更新;
- 使用该ConfigMap挂载的Volume中的数据需要一段时间才能同步更新。
ENV是在容器启动时注入的,启动之后Kubernetes就不会再改变环境变量的值,且同一个namespace中的Pod的环境变量是不断累加的。
为了更新容器中使用ConfigMap挂载的配置,需要通过滚动更新pod的方式来强制重新挂载ConfigMap。
3.9.3 Volume
Kubernetes中的寿命与封装它的Pod相同。
Kubernetes支持多种类型的卷,Pod可以同时使用任意数量的卷。
卷的核心是目录,可能还包含了一些数据,可以通过pod中的容器来访问。
要使用卷,需要为pod指定为卷(spec.volumes字段)以及将它挂载到容器的位置(spec.containers.volumeMounts字段)。
Pod中的每个容器都必须独立指定每个卷的挂载位置。
卷的类型
- cephfs
- emptyDir
- glusterfs
- hostPath
- local
- nfs
emptyDir
emptyDir最初是空的。
当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删除。
注意:容器崩溃不会从节点中移除Pod,因此emptyDir卷中的数据在容器崩溃时是安全的。
emptyDir的用法:
- 暂存空间,例如用于基于磁盘的合并排序;
- 用作长时间计算崩溃恢复时的检查点;
- Web服务器容器提供数据时,保存内容管理器容器提取的文件;
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath
hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中。
hostPath的用法如下:
- 运行需要访问Docker内部的容器;使用/var/lib/docker的hostPath
- 在容器中运行cAdvisor;使用/dev/cgroups的hostPath
- 允许pod指定给定的hostPath是否应该在pod运行之前存在,是否应该创建,以及它应该以什么形式存在。
除了所需的path属性之外,用户还可以为hostPath卷指定type。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: Directory
local
local卷表示挂载的本地存储设备、如磁盘、分区及目录。
local卷可以以持久的方式使用,无需手动将pod调度到节点上。
3.9.4 Persistent Volume(持久化卷)
Persistent Volume(PV)是由管理员设置的存储,它是群集的一部分。
Persistent Volume Claim(PVC)是用户存储的请求。
PVC消耗PV资源。
Pod可以请求特定级别的资源(CPU和内存)。
声明可以请求特定的大小和访问模式(例如:可以读/写一次或 只读多次模式挂载。)
卷和声明的生命周期
PV属于集群中的资源。PVC是对这些资源的请求,也作为对资源的请求的检查。
PV和PVC遵循这样的生命周期:
配置(Provision)
有两种方式配置PV:静态和动态。
静态
集群管理员创建一些PV。它们带有可供集群用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费。
动态
根据StorageClasses,当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试动态的为PVC创建卷。
绑定
在动态配置的情况下,用户创建或已经创建了具有特定存储量的 PersistentVolumeClaim
以及某些访问模式。master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后,PersistentVolumeClaim
绑定是排他性的,不管它们是如何绑定的。 PVC 跟 PV 绑定是一对一的映射。
如果没有匹配的卷,声明将无限期地保持未绑定状态。随着匹配卷的可用,声明将被绑定。例如,配置了许多 50Gi PV的集群将不会匹配请求 100Gi 的PVC。将100Gi PV 添加到群集时,可以绑定 PVC。
使用
Pod使用声明作为卷。集群检查声明以查找绑定的卷并为集群挂载该卷。
对于支持多种访问模式的卷,用户指定在使用声明作为容器中的卷时所需的模式。
用户进行了声明,并且该声明是绑定的,则只要用户需要,绑定的PV就属于该用户。
用户通过在Pod的volume配置中包含PersistentVolumeClaim来调度Pod并访问用户声明的PV。
持久化卷声明的保护
PVC保护的目的是确保由Pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能导致数据丢失。
注意:当pod的状态为Pending并且Pod已经分配给节点或pod为Running状态时,PVC处于活动状态。
当启用PVC保护alpha功能时,如果用户删除了一个Pod正在使用的PVC,则该PVC不会被立即删除。
PVC删除将被推迟,直到PVC不再被任何Pod使用。
回收
用户用完volume后,可以从允许回收资源的API中删除PVC对象。
PersistentVolumeClaim的回收策略告诉集群在存储卷声明释放后应如何处理该卷。
目前,volume的处理策略有保留、回收或删除。
扩展持久化卷声明
管理员可以通过将ExpandPersistentVolumes特性门设置为true来允许扩展持久卷声明。
管理员还应该启用PersistentVolumeClaimResize 准入控制插件来执行对可调整大小的卷的其他验证。
一旦PersistentVolumeClaimResize 准入插件已打开,将只允许其allowVolumeExpansion字段设置为true的存储类进行大小调整。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: gluster-vo1-default
provisioner: kubernetes.io/glusterfs
parameters:
result1: "http://192.168.10.100:8080"
restuser: ""
secretNamespace: ""
secretName: ""
allowVolumeExpansion: true
对于扩展包含文件系统的卷,只有在ReadWrite模式下使用PersistentVolumeClaim启动新的Pod时,才会执行文件系统调整大小。
如果正在扩展的卷在pod或部署中使用,则需要删除并重新创建要进行文件系统调整大小的Pod。
文件系统大小调整仅适用于如下文件系统:
- XFS
- Ext3、Ext4
持久化卷
每个PV配置中都包含一个spec规格字段和一个Status卷状态字段。
apiVerison: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
卷模式
volumeMode的有效值可以是Filesystem或者Block。
如果未指定,volumeMode默认为Filesystem。
访问模式
存储模式包括:
- ReadWriteOnce ——该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany ——该卷可以被多个节点以只读模式挂载
- ReadWriteMany ——该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
- RWO—-ReadWriteOnce
- ROX—-ReadOnlyMany
- RWX—-ReadWriteMany
注意:一个卷一次只能使用一种访问模式挂载,即使它支持多种访问模式。
回收策略
当前的回收策略包括:
- Retain(保留)——手动回收
- Recycle(回收)——基本擦除(
rm -rf /thevolume/*
) - Delete(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除
当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略。
状态
卷可以处于以下的某种状态:
- Available(可用)——一块空闲资源还没有被任何声明绑定
- Bound(已绑定)——卷已经被声明绑定
- Released(已释放)——声明被删除,但是资源还未被集群重新声明
- Failed(失败)——该卷的自动回收失败
命令行会显示绑定到 PV 的 PVC 的名称。
PersistentVolumeClaim
每个PVC中都包含一个spec规格字段和一个status声明状态字段。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment,operator: In,values: [dev]}
选择器
声明可以指定一个标签选择器来进一步过滤该组卷。只有标签与选择器匹配的卷可以绑定到声明。
选择器有2个字段组成:
- matchLabels: volume必须有具有该值的标签
- matchExpressions: 这是一个要求列表,通过指定关键字,值列表以及与关键字和值相关的运算符组成。有效的运算符包括In、NotIn、Exists和DoesNotExist。
声明作为卷
通过将声明用作卷来访问存储。
声明必须与使用声明的pod存在于相同的命名空间中。
集群在Pod的命名空间中查找声明,并使用它来获取支持声明的PersistentVolume。该卷然后被挂载到主机的Pod上。
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: dockerfile/nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
3.9.5 StorageClass
StorageClass为管理员提供了描述存储“Class(类)”的方法。
不同的class可能会映射到不同的服务质量等级或备份策略。
StorageClass资源
StorageClass中包含provisioner、parameters和reclaimPolicy字段,当class需要动态分配PersistentVolume时会使用到。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
mountOptions:
- debug
Provisioner(存储分配器)
StorageClass有一个分配器,用来决定使用哪个卷插件分配PV。该字段必须指定。