8. 老板 不加薪,我用了 这篇 加了 3K
在K8S中,容器本身是非持久化的,当容器崩溃后,kubelet将以镜像的初始状态重新启动容器,但是此时之前容器的数据已经丢失,我们该如何保护好容器的数据呢?
在同一Pod中的容器往往需要共享一些数据,此时我们又该如何实现呢?
这个时候就需要存储来解决这两个问题。
一、ConfigMap
ConfigMap
功能在 Kubernetes1.2
版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。 ConfigMap API
给我们提供了向容器中注入配置信息的机制, ConfigMap
可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON
二进制大对象。
1.1 ConfigMap 的创建
① 使用目录创建
[root@master configmap]
apple=8.0
orange=3.5
[root@master configmap]
beef=55.0
pork=28.0
[root@master configmap]
configmap/shop-config created
[root@master configmap]
NAME DATA AGE
shop-config 2 8s
[root@master configmap]
[root@master configmap]
② 使用文件创建
[root@master configmap]
tea=3.0
coffee=4.0
[root@master configmap]
configmap/drink-config created
[root@master configmap]
③ 使用字面值创建
使用文字值创建,利用 --from-literal
参数传递配置信息,该参数可以使用多次,格式如下:
[root@master configmap]
configmap/snacks-config created
[root@master configmap]
1.2 使用 ConfigMap
使用 ConfigMap
有三种方式,一种是通过环境变量的方式,直接传递 pod
,另一种是通过在 pod
的命令行下运行的方式,第三种是使用 volume
的方式挂载入到 pod
内。
① 使用 ConfigMap 来替代环境变量
[root@master configmap]
apiVersion: v1
kind: ConfigMap
metadata:
name: animal-config
namespace: default
data:
cat: cute
dog: lovely
[root@master configmap]
configmap/animal-config created
[root@master configmap]
apiVersion: v1
kind: Pod
metadata:
name: use-configmap-pod
spec:
containers:
- name: test-container
image: hub.hc.com/library/myapp:v1
command: [ "/bin/sh", "-c", "env" ]
env:
- name: animal-config-cat
valueFrom:
configMapKeyRef:
name: animal-config
key: cat
- name: animal-config-coffee
valueFrom:
configMapKeyRef:
name: animal-config
key: dog
envFrom:
- configMapRef:
name: snacks-config
restartPolicy: Never
[root@master configmap]
pod/use-configmap-pod created
[root@master configmap]
② 用 ConfigMap 设置命令行参数
apiVersion: v1
kind: Pod
metadata:
name: use--configmap-pod2
spec:
containers:
- name: test-container
image: hub.hc.com/library/myapp:v1
command: [ "/bin/sh", "-c", "echo $(animal-config-cat) $(animal-config-dog)" ]
env:
- name: animal-config-cat
valueFrom:
configMapKeyRef:
name: animal-config
key: cat
- name: animal-config-dog
valueFrom:
configMapKeyRef:
name: animal-config
key: dog
restartPolicy: Never
③ 通过数据卷插件使用 ConfigMap
在数据卷里面使用这个 ConfigMap
,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容。
apiVersion: v1
kind: Pod
metadata:
name: use-configmap-pod3
spec:
containers:
- name: test-container
image: hub.hc.com/library/myapp:v1
command: [ "/bin/sh", "-c", "ls /etc/config" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: animal-config
restartPolicy: Never
1.3 ConfigMap 热更新
[root@master configmap]
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: hub.hc.com/library/myapp:v1
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: snacks-config
[root@master configmap]
deployment.extensions/my-nginx created
[root@master configmap]
NAME READY STATUS RESTARTS AGE
my-nginx-bc7499bd8-hrgl9 1/1 Running 0 2s
[root@master configmap]
6.9
[root@master configmap]
[root@master configmap]
8.8
二、Secret
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用
Secret
有三种类型:
- Service Account:用来访问
Kubernetes API
,由Kubernetes
自动创建,并且会自动挂载到Pod
的/run/secrets/kubernetes.io/serviceaccount
目录中 - Opaque:
base64
编码格式的Secert
,用来存储密码、密钥等 - kubernetes.io/dockerconfigjson:用来存储私有
docker registry
的认证信息
2.1 Service Account
[root@master ~]
ca.crt namespace token
2.2 Opaque
Opaque
类型的数据是一个 map
类型,要求 value
是 base64
编码格式:
[root@master ~]
YWRtaW4=
[root@master ~]
MWYyZDFlMmU2N2Rm
创建 Opaque
类型的 secret
:
[root@master secert]
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
[root@master secert]
secret/mysecret created
[root@master secert]
NAME TYPE DATA AGE
mysecret Opaque 2 93s
将 Secret
挂载到 Volume
中:
[root@master secert]
apiVersion: v1
kind: Pod
metadata:
labels:
name: secret-test
name: secret-test
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- image: hub.hc.com/library/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath: /etc/config
[root@master secert]
pod/secret-test created
[root@master secert]
/
/etc/config
1f2d1e2e67df
admin
将 Secret
导出到环境变量中:
[root@master secert]
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: pod-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: hub.hc.com/library/myapp:v1
command: [ "/bin/sh", "-c", "env" ]
ports:
- containerPort: 80
env:
- name: TEST_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
[root@master secert]
deployment.extensions/pod-deployment created
2.3 kubernetes.io/dockerconfigjson
[root@master secert]
secret "myregistrykey" created
[root@master secert]
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: roc/awangyang:v1
imagePullSecrets:
- name: myregistrykey
三、Volume
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时, kubelet
会重启它,但是容器中的文件将丢失,容器以干净的状态(镜像最初的状态)重新启动。其次,在 Pod
中同时运行多个容器时,这些容器之间通常需要共享文件。 Kubernetes
中的 Volume
抽象就很好的解决了这些问题。
Kubernetes
中的卷( Volume
)有明确的寿命,与封装它的 Pod
相同。所f以,卷的生命比 Pod
中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod
不再存在时,卷也将不复存在。 Kubernetes
支持多种类型的卷, Pod
可以同时使用任意数量的卷。
3.1 emptyDir
当 Pod
被分配给节点时,首先创建 emptyDir
卷,并且只要该 Pod
在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。 Pod
中的容器可以读取和写入 emptyDir
卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod
时, emptyDir
中的数据将被永久删除。
emptyDir
的用法有:
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时的检查点
Web
服务器容器提供数据时,保存内容管理器容器提取的文件
[root@master volume]
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: hub.hc.com/library/myapp:v1
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
- image: busybox
name: test-container2
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c','sleep 3600']
volumeMounts:
- mountPath: /test
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
[root@master volume]
[root@master volume]
'NAME READY STATUS RESTARTS AGE
test-pd 2/2 Running 0 8m32s
[root@master volume]
/
/cache
/cache
Wed Aug 12 07:43:08 UTC 2020
[root@master ~]
/
/test
Wed Aug 12 07:43:08 UTC 2020
3.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给定的路径下必须存在块设备
使用这种卷类型时请注意:
- 由于每个节点上的文件都不同,具有相同配置(例如从
podTemplate
创建的)的pod
在不同节点上的行为可能会有所不同 - 当
Kubernetes
按照计划添加资源感知调度时,将无法考虑hostPath
使用的资源 - 在底层主机上创建的文件或目录只能由
root
写入。您需要在特权容器中以root
身份运行进程,或修改主机上的文件权限以便写入hostPath
卷
[root@master volume]
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: hub.hc.com/library/myapp:v1
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: Directory
[root@master volume]
[root@master volume]
/
/test-pd
[root@worker1 data]
[root@worker2 data]
2020年 08月 12日 星期三 17:52:43 CST
四、PV-PVC
4.1 相关概念
① PersistentVolume(PV)
是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样, PV
也是集群中的资源。 PV
是 Volume
之类的卷插件,但具有独立于使用 PV
的 Pod
的生命周期。此 API
对象包含存储实现的细节,即 NFS
、 iSCSI
或特定于云供应商的存储系统
② PersistentVolumeClaim(PVC)
是用户存储的请求,它与 Pod
相似。 Pod
消耗节点资源, PVC
消耗 PV
资源。 Pod
可以请求特定级别的资源( CPU
和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)
③ 静态 pv
集群管理员创建一些 PV
,它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API
中,可用于消费
④ 动态
当管理员创建的静态 PV
都不匹配用户的 PersistentVolumeClaim
时,集群可能会尝试动态地为 PVC
创建卷。此配置基于 StorageClasses
: PVC
必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为""可以有效地禁用其动态配置要启用基于存储级别的动态存储配置,集群管理员需要启用 API server
上的 DefaultStorageClass
[准入控制器]。例如,通过确保 DefaultStorageClass
位于 API server
组件的 --admission-control
标志,使用逗号分隔的有序值列表中,可以完成此操作
⑤ 绑定
master
中的控制环路监视新的 PVC
,寻找匹配的 PV
(如果可能),并将它们绑定在一起。如果为新的 PVC
动态调配 PV
,则该环路将始终将该 PV
绑定到 PVC
。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV
和 PVC
绑定后, PersistentVolumeClaim
绑定是排他性的,不管它们是如何绑定的。 PVC
跟 PV
绑定是一对一的映射
4.2 PV说明
PVC的保护
PVC
保护的目的是确保由 pod
正在使用的 PVC
不会从系统中移除,因为如果被移除的话可能会导致数据丢失当启用 PVC
保护 alpha
功能时,如果用户删除了一个 pod
正在使用的 PVC
,则该 PVC
不会被立即删除。 PVC
的删除将被推迟,直到 PVC
不再被任何 pod
使用
PV演示代码
apiVersion: v1
kind: PersistentVolumemeta
data:
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
PV类型
PV
类型以插件形式实现。 K8S
目前支持以下插件类型:
PV访问模式
PV
可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个 PV
的访问模式都将被设置为该卷支持的特定模式。例如, NFS
可以支持多个读/写客户端,但特定的 NFS PV
可能以只读方式导出到服务器上。每个 PV
都有一套自己的用来描述特定功能的访问模式:
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
的名称
4.3 持久化演示说明 - NFS
① 安装 NFS
服务器
[root@master ~]
[root@master ~]
[root@master ~]
/nfs *(rw,no_root_squash,no_all_squash,sync)
[root@master ~]
[root@worker1 ~]
[root@worker1 ~]
Export list for 192.168.182.100:
/nfs *
[root@worker1 ~]
[root@worker1 /]
② 部署 PV
[root@master pv]
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfs
server: 192.168.182.100
[root@master pv]
persistentvolume/nfs-pv1 created
[root@master pv]
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv1 1Gi RWO Retain Available nfs 5s
③ 创建服务并使用 PVC
[root@master /]
[root@master /]
[root@master /]
/nfs *(rw,no_root_squash,no_all_squash,sync)
/nfs2 *(rw,no_root_squash,no_all_squash,sync)
/nfs3 *(rw,no_root_squash,no_all_squash,sync)
[root@master pv]
[root@master pv]
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfs
server: 192.168.182.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv2
spec:
capacity:
storage: 5Gi
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfs2
server: 192.168.182.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv3
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: slow
nfs:
path: /nfs3
server: 192.168.182.100
[root@master pv]
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv1 1Gi RWO Retain Available nfs 23s
nfs-pv2 5Gi ROX Retain Available nfs 23s
nfs-pv3 1Gi RWX Retain Available slow 23s
[root@master pv]
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: hub.hc.com/library/myapp:v1
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs"
resources:
requests:
storage: 1Gi
[root@master pv]
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 7s
web-1 0/1 Pending 0 5s
[root@master pv]
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv1 1Gi RWO Retain Bound default/www-web-0 nfs 4m40s
nfs-pv2 5Gi ROX Retain Available nfs 4m40s
nfs-pv3 1Gi RWO Retain Bound default/www-web-1 nfs 4m40s
[root@master pv]
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 15m 10.244.2.84 worker2 <none> <none>
web-1 1/1 Running 0 15m 10.244.1.58 worker1 <none> <none>
[root@master pv]
Hello PV
[root@master pv]
Hello PV
[root@master pv]
pod "web-0" deleted
[root@master pv]
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 3s 10.244.2.85 worker2 <none> <none>
web-1 1/1 Running 0 18m 10.244.1.58 worker1 <none> <none>
[root@master pv]
Hello PV
4.4 关于 StatefulSet
- 匹配
Pod name
( 网络标识 ) 的模式为:$(statefulset名称)-$(序号)
,比如上面的示例:web-0
、web-1
StatefulSet
为每个Pod
副本创建了一个DNS
域名,这个域名的格式为:$(podname).(headless servername)
,也就意味着服务间是通过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
,Podname=web-[0-2]
,因此创建出来的PVC
是www-web-0
、www-web-1
- 删除
Pod
不会删除其pvc
,手动删除pvc
将自动释放pv
Statefulset
的启停顺序:
- 有序部署:部署
StatefulSet
时,如果有多个Pod
副本,它们会被顺序地创建(从0
到N-1
)并且,在下一个Pod
运行之前所有之前的Pod
必须都是Running
和Ready
状态 - 有序删除:当
Pod
被删除时,它们被终止的顺序是从N-1
到0
- 有序扩展:当对
Pod
执行扩展操作时,与部署一样,它前面的Pod
必须都处于Running
和Ready
状态
StatefulSet
使用场景:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于
PVC
来实现 - 稳定的网络标识符,即
Pod
重新调度后其PodName
和HostName
不变 - 有序部署,有序扩展,基于
init containers
来实现 - 有序收缩
微信搜一搜 : 全栈小刘 ,获取文章 pdf 版本