K8s学习笔记 (10)
@ wgjak47 | 星期六,八月 3 日,2019 年 | 6 分钟阅读 | 更新于 星期六,八月 3 日,2019 年

k8s学习笔记

存储

为了管理存储,Kubernetes提供了Secret用于管理敏感信息,ConfigMap存储配置,Volume、PV、PVC、StorageClass等用来管理存储卷。

secret

类型

ServiceAccount

Service Account用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中。 例子:

$ kubectl run nginx --image nginx
deployment "nginx" created
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-3137573019-md1u2   1/1       Running   0          13s
$ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

Opaque

base64 编码格式的secret,用于存储敏感信息 例子:

apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=

----
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
# 以volume方式
volumeMounts:
- name: secrets
# 通过"/etc/secrets"方式读取
mountPath: "/etc/secrets"
readOnly: true
ports:
- name: cp
containerPort: 5432
hostPort: 5432
----
apiVersion: extensions/v1beta1
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 存储Docker registry认证信息

例子:

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret "myregistrykey" created.
$ cat ~/.docker/config.json | base64
$ cat > myregistrykey.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
data:
.dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson
EOF
$ kubectl create -f myregistrykey.yaml

使用:

apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: janedoe/awesomeapp:v1
# 指定pull image需要的Secrets
imagePullSecrets:
- name: myregistrykey

configMap

用于存储配置信息,和Docker image/各种控制器解偶。以key-value pair形式存储。例如:

kind: ConfigMap
apiVersion: v1
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: example-config
namespace: default
# 如果使用volume方式挂在
# data下每一项都会是一个独立的文件
data:
example.property.1: hello
example.property.2: world
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3

Pod使用ConfigMap

和Secret一样,也可以通过环境变量或者volume的方式使用

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: special-config
key: special.type
envFrom:
- configMapRef:
name: env-config
restartPolicy: Never

----
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
----
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/special.how" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
# volume方式
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: special.how
# 当前路径为/etc/config/
path: path/to/special-key
restartPolicy: Never

热更新

  • 更新configMap并不会更新容器,而只是更新容器内挂在的Volume内容(一定时间的延迟)
  • 更新configMap不会更新环境变量
  • 可以通过修改.spec.template.metadata.annotations来手动触发更新

Volume

emptyDir

当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。而容器崩溃的时候不会从节点移除Pod, 因此Empty一般用来以下用途:

  • 暂存空间,例如用于基于磁盘的合并排序
  • 用作长时间计算崩溃恢复时的检查点
  • 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: {}

挂载传播

挂载传播允许将由容器挂载的卷共享到同一个 Pod 中的其他容器上,甚至是同一节点上的其他 Pod。 通过--feature-gates命令参数中指定MountPropagation=true, 指定容器的mountPropagation字段指定方式:

  • HostToContainer, 与mount --make-salve类似,此卷挂载将接收所有后续挂载到此卷或其任何子目录的挂载。
  • Bidirectional, 与mount --make-shared类似,由容器创建的所有卷挂载将被传播回主机和所有使用相同卷的容器的所有容器

PV(Persistent volume)

PersistentVolume 子系统为用户和管理员提供了一个 API,该 API 将如何提供存储的细节抽象了出来。为此,我们引入两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。

  • PersistentVolume(PV)是由管理员设置的存储,它是群集的一部分。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。
  • PersistentVolumeClaim(PVC)是用户存储的请求。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)。

例子:

apiVersion: 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

访问模式

  • ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
  • ReadOnlyMany——该卷可以被多个节点以只读模式挂载
  • ReadWriteMany——该卷可以被多个节点以读/写模式挂载

StorageClass

PV 可以具有一个类,通过将 storageClassName 属性设置为 StorageClass 的名称来指定该类。一个特定类别的 PV 只能绑定到请求该类别的 PVC。没有 storageClassName 的 PV 就没有类,它只能绑定到不需要特定类的 PVC。

回收策略

同PV。

状态

  • Available(可用)——一块空闲资源还没有被任何声明绑定
  • Bound(已绑定)——卷已经被声明绑定
  • Released(已释放)——声明被删除,但是资源还未被集群重新声明
  • Failed(失败)——该卷的自动回收失败

PersistentVolumeClaim

PVC的一些属性基本与PV相同,但是多了selector来进一步过滤PV 例子:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
# 如果设置为"",则只能绑定到没有类的PV(没有注解或 "")
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}

卷和声明的声明周期

静态

集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费。

动态

当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此配置基于 StorageClasses:PVC 必须请求存储类,并且管理员必须创建并配置该类才能进行动态创建。声明该类为 "" 可以有效地禁用其动态配置。 要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass 准入控制器。

绑定

PVC 跟 PV 绑定是一对一的映射。master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起,防止容量可能超出要求的数量。

使用

用户通过在 Pod 的 volume 配置中包含 persistentVolumeClaim 来调度 Pod 并访问用户声明的 PV。

持久化卷声明的保护

PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除。如果用户删除了一个PVC,但是这个PVC正在被其它Pod使用, 那么该PVC不会被删除,直到没有Pod再继续使用它。

回收策略

保留

保留回收策略允许手动回收资源。当 PersistentVolumeClaim 被删除时,PersistentVolume 仍然存在,volume 被视为“已释放”。需要管理员手动清理数据。

回收

如果存储卷插件支持,回收策略会在 volume上执行基本擦除(rm -rf / thevolume / *),可被再次声明使用。

删除

对于支持删除回收策略的卷插件,删除操作将从 Kubernetes 中删除 PersistentVolume 对象,并删除外部基础架构(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中的关联存储资产

扩容

如果存储卷插件支持,可以通过启用PersistentVolumeClaimResize 准入控制插件,并指定allowVolumeExpansion字段:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: gluster-vol-default
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://192.168.10.100:8080"
restuser: ""
secretNamespace: ""
secretName: ""
allowVolumeExpansion: true

如果正在扩展的卷在 pod 或部署中使用,则需要删除并重新创建要进行文件系统调整大小的pod。

Storage Class

StorageClass 为管理员提供了描述存储 “class(类)” 的方法。 不同的 class 可能会映射到不同的服务质量等级或备份策略,或由群集管理员确定的任意策略。

例子:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard
# 使用的卷插件
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
# 回收策略
reclaimPolicy: Retain
# 挂在选项
mountOptions:
- debug