第五课:尚硅谷K8s学习-存储机制
第五课:尚硅谷K8s学习-存储机制tags:golang2019尚硅谷categories:K8sconfigMapSecretvolumePVPVC文章目录第五课:尚硅谷K8s学习-存储机制第一节存储机制-configMap1.1 configMap介绍和创建1.2 Pod中configMap的使用1.3 用ConfigMap设置命令行参数1.4 通过数据卷插件使用ConfigMap1.5 Co
第五课:尚硅谷K8s学习-存储机制
tags:
- golang
- 2019尚硅谷
categories:
- K8s
- configMap
- Secret
- volume
- PV
- PVC
文章目录
第一节 存储机制-configMap
- k8s中的存储类型有以下四种
- configMap: k8s中存储配置文件
- Secret: 需要加密的信息比如:秘钥,用户密码
- volume: 给Pod提供共享存储卷的能力
- Persistent Volume(简称PV): 服务持久卷的构建
1.1 configMap介绍和创建
-
ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象
-
ConfigMap 的创建方式
- 使用目录创建
- 使用文件创建
- 使用字面值创建
-
configMap使用目录创建
mkdir configmap
cd configmap
vim 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
vim ui.properties
# 测试配置如下
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# —from-file指定在目录下的所有文件都会被用在 ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl create configmap game-config --from-file=configmap
# 查看创建成功后的配置
kubectl get cm game-config
# 以yaml的格式输出
kubectl get cm game-config -o yaml
- configMap使用文件创建: 这里直接把上面文件夹变成指定的文件就可以。使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的(上面是文件夹下所有配置文件运行)
kubectl create configmap game-config-2 --from-file=/configmap/game.properties
- configMap使用字面值创建
使用字面值创建,利用–from-literal参数传递配置信息,该参数可以使用多次,格式如下:
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
1.2 Pod中configMap的使用
- 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
- 配置文件env.yaml创建configMap。 kubectl apply -f env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
- 注入上面俩个configMap的变量到Pod中。pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: hub.qnhyn.com/library/myapp
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
- 实验查看基本操作
# 查看configMap中详细信息
kubectl describe cm env-config
# 创建测试pod-test
kubectl create -f pod-test.yaml
# 查看日志, 确认导入环境变量成功
kubectl logs dapi-test-pod
1.3 用ConfigMap设置命令行参数
- 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
- pod-test2.yaml配置文件
apiVersion: v1
kind: Pod
metadata:
name: pod-test2
spec:
containers:
- name: test-container
image: hub.qnhyn.com/library/myapp
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
- 实验查看基本操作
# 创建测试pod-test
kubectl create -f pod-test2.yaml
# 查看日志, 确认导入环境变量成功 输出结果为(very charm)
kubectl logs pod-test2
1.4 通过数据卷插件使用ConfigMap
- 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
- 在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容。
apiVersion: v1
kind: Pod
metadata:
name: test-pod3
spec:
containers:
- name: test-container
image: hub.qnhyn.com/library/myapp
command: ["/bin/sh","-c","sleep 600s"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
restartPolicy: Never
- 实验查看基本操作
# 创建测试ptest-pod3
kubectl create -f test-pod3.yaml
# 交互到test-pod3容器中 容器中有储存的配置
kubectl exec test-pod3 -it -- /bin/sh
cd /etc/config
cat special.how
1.5 ConfigMap 的热更新
- 建立configMap和pod。
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- name: nginx-deployment
image: hub.qnhyn.com/library/myapp
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: log-config
- 实验查看基本操作
# 进入pod中容器查看configMap信息
kubectl exec nginx-568bdc484c-vwzmv -it -- /bin/sh
cd /etc/config
# 热更新修改 ConfigMap
kubectl edit configmap log-config
# 修改log_level的值为DEBUG等待大概 10 秒钟时间,再次查看环境变量的值
kubectl exec nginx-568bdc484c-vwzmv -it cat /etc/config/log_level
- ConfigMap 更新后滚动更新 Pod
- 更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新
kubectl patch deployment my-nginx --patch’{“spec”: {“template”: {“metadata”: {“annotations”:{“version/config”: “20190411” }}}}}’
- 这个例子里我们在.spec.template.metadata.annotations中添加version/config,每次通过修该version/config来触发滚动更新
- !!!更新 ConfigMap 后:
- 使用该 ConfigMap 挂载的 Env 不会同步更新
- 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
第二节 存储机制-Secret
2.1 secret的介绍
- Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活。
- Secret的类型:
- Service Account:用来访问Kubernetes API, 由Kubernetes 自动创建。对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
- Opaque:base64编码格式的Secret,用来存储密码、密钥等。使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
- kubernetes.io/dockerconfigjson: 用于存储docker registry的认证信息。
2.2 Secret的类型-Service Account
- Service Account 创建时 Kubernetes 会默认创建对应的 secret。对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
- 实验过程。这种实际应用中用的比较少。( 每个namespace下有一个名为default的默认的ServiceAccount对象 )
kubectl get sa
# 挑选一个可以访问Kubernetes API的pod,这里选kube-proxy-799ln
kubectl get pod -n kube-system
# 进去查看有三个文件 接口通过HTTPS双向认证
kubectl exec kube-proxy-799ln -n kube-system -it -- /bin/sh
cd /run/secrets/kubernetes.io/serviceaccount
2.3 Secret的类型-Opaque
- Opaque类型的数据是一个map类型,要求value是base64编码格式:
- 它实际上是表面上加密,很容易破解。
# 加密
echo -n "admin" | base64
echo -n "123456" | base64
# 解密
echo -n "YWRtaW4=" | base64 -d
- 创建一个Opaque类型的Secret: kubectl create -f So.yaml
kubectl get secret
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
- 将Secret挂载到Volume中
apiVersion: v1
kind: Pod
metadata:
labels:
name: secret-test
name: secret-test
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- image: hub.qnhyn.com/library/myapp
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/secrets"
readOnly: true
kubectl create -f secret-test.yaml
kubectl exec secret-test -it -- /bin/sh
cd /etc/secrets
- 将Secret设置为环境变量
apiVersion: v1
kind: Pod
metadata:
name: secret-env
spec:
containers:
- name: nginx
image: hub.qnhyn.com/library/myapp
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
kubectl get pod
# 查看环境变量
kubectl exec secret-env -- env
2.4 Secret的类型-kubernetes.io/dockerconfigjson
- harbor仓库中创建一个私有仓库并提镜像上去。对于私有仓库的拉取,需要登录认证否则无法成功拉取,登录认证信息存放在主机上(.docker/config.json)有安全隐患。
- docker logout hub.qnhyn.com
- 因为不是公有再次拉取报验证错误,docker pull hub.qnhyn.com/test/myapp
- 使用kubectl创建docker registry认证的secret
kubectl create secret docker-registry myregistrykey --docker-server=hub.qnhyn.com --docker-username=admin --docker-password=123456 --docker-email=""
- 在创建Pod的时候,通过imagePullSecrets来引用刚创建的myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: hub.qnhyn.com/test/myapp
imagePullSecrets:
- name: myregistrykey
第三节 存储机制-Volume
3.1 Volume介绍
- 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失,容器以干净的状态 (镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题
- Kubernetes中的卷有明确的寿命,与封装它的Pod相同。所f以,卷的生命比Pod中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当Pod不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
- Kubernetes支持多种类型的卷
- awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwgrdAPI、 emptyDir
- fc、flocker、 gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs
- persistentVolumeClaim、projected、 portworxVolume、quobyte、rbd、scaleI0 、secret
- storageos、vsphereVolume
3.2 emptyDir卷
- 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod中的容器可以读取和写入emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删除
- emptyDir的用法有:
- 暂存空间,例如用于基于磁盘的合井排序
- 用作长时间计算前溃恢复时的检查点
- Web服务器容器提供数据时,保存内容管理器容器提取的文件
- 下面声明了一个名字叫cache-volume的volumes类型是emptyDir,把容器test-container中的/cache挂载在上面。em.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: hub.qnhyn.com/library/myapp
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
- image: busybox
name: test-busybox
command: ["/bin/sh","-c","sleep 6000s"]
volumeMounts:
- mountPath: /test
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
- 到容器中查看,是否/cache下是一个空目录。
kubectl create -f em.yaml
# -c指定Pod中的容器
kubectl exec test-pd -c test-container -it -- /bin/sh
# 在容器test-container的cache目录下
cd cache
date > index.html
exit
# 在容器test-busybox的test的目录下查看index.html文件
kubectl exec test-pd -c test-busybox -it -- /bin/sh
cd test
exit
3.3 hostPath卷
-
hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中
-
hostPath 的用途如下:
- 运行需要访问Docker内部的容器;使用 /var/lib/docker 的 hostPath
- 在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath
-
这种方法非常灵活。只要存储服务能被挂载到node所在的节点,我们就可以用hostPath方案让Pod使用
-
除了所需的 path 属性之外,用户还可以为hostPath卷指定 type。
值 | 行为 |
---|---|
空字符串 (默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate | 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet 具有相同的组和所有权。 |
Directory | 给定的路径下必须存在目录 |
FileOrCreate | 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。 |
File | 给定的路径下必须存在文件 |
Socket | 给定的路径下必须存在UNIX套接字 |
CharDevice | 定的路径下必须存在字符设备 |
BlockDevice | 定的路径下必须存在块设备 |
- 使用这种卷类型是请注意,因为:
- 由于每个节点上的文件都不同,具有相同配置(例如从podTemplate创建的)的pod在不同节点上的行为可能会有所不同(没有你去挂能挂上吗?逗逼)
- 当Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源(hostpath资源不归k8s管)
- 在底层主机上创建的文件或目录只能由 root写入。您需要在特权容器中以 root身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷(没权限,去改)
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: hub.qnhyn.com/library/myapp
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
- 实验
# 查看运行权限
ps aux | grep kubelete
# 创建文件夹 这里需要三个节点都创建文件夹哈 防止pod创建不成功
mkdir /data
kubectl create -f pod1.yaml
# 容器挂载目录下写入文件
kubectl exec test-pd -it -- /bin/sh
cd /test-pd
date > hello.txt
# 到对应节点下的/data下查看
cd /data
第四节 存储机制-持久卷PV和PVC
4.1 持久卷PV和PVC概念
- 假如没有PVC,你需要自己判断PV大小是否可用。非常耗时
- PersistentVolume(PV)是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源-样, PV也是集群中的资源。PV 是Volume之类的卷插件,但具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定于云供应商的存储系统
- PersistentVolumeClaim(PVC)是用户存储的请求。它与Pod相似。Pod 消耗节点资源,PVC 消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写次或只读多次模式挂载)
- PV分类
- 静态PV: 集群管理员创建一些PV。它们带有可供群集用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费
- 动态PV:(可以跟云存储上申请存储,以后的趋势,暂时并不友好,需要收费且麻烦,不太成熟。了解即可
- 当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim 时,集群可能会尝试动态地为PVC创建卷。此配置基于StorageClasses : PVC 必须请求[存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为“ “可以有效地禁用其动态配置
- 要启用基于存储级别的动态存储配置,集群管理员需要启用API server上的
DefaultstorageClass[准入控制器]。例如,通过确保DefaultStorageClass位于API server组件的
–admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作
- 绑定PV
- master中的控制环路监视新的PVC,寻找匹配的PV (如果可能) ,并将它们绑定在一 起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦PV和PVC绑定后,PersistentVolumeClaim绑定是排他性的, 不管它们是如何绑定的。PVC跟PV绑定是一对一的映射
- 持久化卷声明的保护
- PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失
- 当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何pod使用
- 持久化卷的类型
- GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)
- FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS
- Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
- HostPath VMware Photon Portworx Volumes ScalelO Volumes StorageOS
apiVersion: v1
kind: PersistentVolume
metadata:
name:pve003
spec:
capacity:
# 卷的大小为5G
storage: 5Gi
# 存储卷的类型为:文件系统
volumeMode: Filesystem
# 访问策略:该卷可以被单个节点以读/写模式挂载
accessModes:
- ReadwriteOnce
# 回收策略:回收
persistentVolumeReclaimPolicy: Recycle
# 对应的具体底层存储的分级 存储类的级别
# 比如有些固态或者其他存储类型比较快,就可以定义为strong
storageClassName: slow
# (可选的)挂载选项
mountOptions:
- hard
- nfsvers=4.1
# 具体对应的真实底层存储类型为nfs
# 挂载到172服务器下的/tmp目录
nfs:
path: /tmp
server: 172.17.0.2
4.2 PV访问模式(spec.accessModes)
- PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式:
- ReadWriteOnce: 该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany: 该卷可以被多个节点以只读模式挂载
- ReadWriteMany: 该卷可以被多个节点以读/写模式挂载
- 在命令行cli中,三种访问模式可以简写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
- 但不是所有的类型的底层存储都支持以上三种,每种底层存储类型支持的都不一样。各种底层存储具体支持的访问模式如下:
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✓ | × | × |
AzureFile | ✓ | ✓ | ✓ |
AzureDisk | ✓ | × | × |
CephFS | ✓ | ✓ | ✓ |
Cinder | ✓ | × | × |
FC | ✓ | ✓ | × |
FlexVolume | ✓ | ✓ | × |
Flocker | ✓ | × | × |
GCEPersistentDisk | ✓ | ✓ | × |
Glusterfs | ✓ | ✓ | ✓ |
HostPath | ✓ | × | × |
iSCSI | ✓ | ✓ | × |
PhotonPersistentDisk | ✓ | × | × |
Quobyte | ✓ | ✓ | ✓ |
NFS | ✓ | ✓ | ✓ |
RBD | ✓ | ✓ | × |
VsphereVolume | ✓ | × | × |
PortworxVolume | ✓ | × | ✓ |
ScaleIO | ✓ | ✓ | × |
4.3 PV的回收策略(spec.persistentVolumeReclaimPolicy)
- 回收策略的三种策略
- Retain(保留): pv被删除后会保留内存,手动回收
- Recycle(回收): 删除卷下的所有内容(rm-rf /thevolume/*)
- Delete(删除): 关联的存储资产(例如AWS EBS、GCE PD、Azure Disk 和OpenStack Cinder卷)将被删除。即直接把卷给删除了
- 回收策略注意事项
- 当前,只有NFS和HostPath支持Recycle回收策略。 但是最新版本中的Recycle已被废弃,截图如下
- 附:具体官网文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes
4.3 PV的状态
- PV可以处于以下的某种状态:
- Available(可用): 块空闲资源还没有被任何声明绑定
- Bound(已绑定): 卷已经被声明绑定, 注意:但是不一定不能继续被绑定,看accessModes而定
- Released(已释放): 声明被删除,但是资源还未被集群重新声明
- Failed(失败): 该卷的自动回收失败
- 命令行会显示绑定到PV的PVC的名称
第五节 实验-持久化演示说明-NFS
5.1 安装NFS服务器
- 在hub仓库机器上创建NFS服务器
yum install -y nfs-common nfs-utils rpcbind
mkdir /nfsdata
mkdir /nfsdata{1..3}
chmod 777 /nfsdata /nfsdata1 /nfsdata2 /nfsdata3
chown nfsnobody /nfsdata /nfsdata1 /nfsdata2 /nfsdata3
# 一下创建四个挂载目录
vim /etc/exports
/nfsdata *(rw,no_root_squash,no_all_squash,sync)
/nfsdata1 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata2 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata3 *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind
systemctl start nfs
# 如果修改配置 重启生效
systemctl restart rpcbind
systemctl restart nfs
# 其他k8s节点安装客户端
yum install -y nfs-utils rpcbind
# 在任意节点测试是否能挂载成功
mkdir /test
# 查看共享目录
showmount -e 192.168.1.100
mount -t nfs 192.168.1.100:/nfsdata /test/
cd /test/
ls
vim index.html
# 解除挂载
cd -
umount /test/
rm -rf /test
5.2 部署PV
- 部署PV, 创建kubectl create -f pv.yaml.这里一下创建四个pv
- 查看创建的pv: kubectl get pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv1
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfsdata
server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv2
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfsdata1
server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv3
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: slow
nfs:
path: /nfsdata2
server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv4
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfsdata3
server: 192.168.1.100
5.3 创建服务并使用PVC
- 一般我们不会直接用PV,而是用PVC的方案去调度。创建服务并使用PVC。kubectl create -f pod.yaml
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 # 要使用StatefulSet控制器,必须建立一个无头服务
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx" # 无头服务名称
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: hub.qnhyn.com/library/myapp
ports:
- containerPort: 80
name: web
volumeMounts: # 挂载下面声明的PVC
- name: www
mountPath: /usr/share/nginx/html # nginx的共享目录
volumeClaimTemplates: # 声明一个PVC名称为www
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs"
resources:
requests:
storage: 1Gi # 大小
- 上面创建pod时候会不成功。报错:没有匹配的volume,原因如下:
- 既满足accessModes: [ “ReadWriteOnce” ]和 storageClassName: "nfs"的只有第一个PV
- 而我们需要三个副本数。所以创建第二个时就卡住了。
- 更改下PV的创建文件。重新创建PV即可。
5.4 关于 Statefulset
- StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为:S(podname).(headless servername),也就意味着服务间是通过Pod域名来通信而非PodIP,因为当Pod所在Node发生故障时,Pod会被飘移到其它 Node上,PodIP会发生变化,但是Pod域名不会有变化
- StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:S(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、 www-web-2
- 在其他pod中可以直接访问:curl www-web-0 安装: yum install -y bind-utils
- kubectl get pod -o wide -n kube-system 查看coredns的pod的ip为:10.244.0.11
- dig -t A nginx.default.svc.cluster.local. @10.244.0.11 查看路由路径
- 删除 Pod 不会删除其pvc,手动删除pvc将自动释放pv
- Statefulset的启停顺序:
- 有序部署:部罢Statefulset时,如果有多个Pod副本,它们会被顺序地创建**(从0到N-1)**并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
- 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。kubectl delete -f pod.yaml然后手动删除pv。
- 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。
- Statefulset使用场景:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC 来实现。
- 稳定的网络标识符,即Pod 重新调度后其iPodName 和 HostName不变。
- 有序部署,有序扩展,基于init containers 来实现。
- 有序收缩。
更多推荐
所有评论(0)