Kubernetes学习目录
1、基础知识
1.1、流程梳理
1.1.1、PV-Persistent Volume
之前我们提到的Volume可以提供多种类型的资源存储(可持久或不持久),但是它定义在Pod上的,是属于"资
源对象"的一部分。工作中的存储资源一般都是独立的,这就是资源对象Persistent Volume(PV),是由管
理员设置的存储,它是群集的一部分,PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。。
Persistent Volume 跟Volume类似,区别就是:
PV就是Kubernetes集群中的网络存储,不属于Node、Pod等资源,但可以被他们访问。
PV是独立的网络存储资源对象,有自己的生命周期,支持很多种volume类型
1.1.2、PVC-Persistent Volume Claim
Persistent Volume Claim(PVC) 是一个网络存储服务的请求。PVC和PV与Pod之间的关系。
Pod能够申请特定的CPU和MEM资源,但是Pod只能通过PVC到PV上请求一块独立大小的网络存储空间,
而PVC 可以动态的根据用户请求去申请PV资源,不仅仅涉及到存储空间,还有对应资源的访问模式,对于真
正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
1.1.3、pod、pv、pvc关联关系
注意事项:
pod、pvc、pv 必须在同一个命名空间。
前提:
存储管理员配置各种类型的PV对象、
用户需要存储资源的时候:
1、用户根据资源需求创建PVC,由PVC自动匹配(权限、容量)合适的PV对象。
2、在pod内部通过PVC将pv绑定到当前的空间,进行使用。
3、如果用户不使用存储资源的话,解绑pvc和pod即可。
1.2、PV、PVC的生命周期图
1.2.1、流程细节说明
1、用户创建了一个包含 PVC 的 Pod,该 PVC 要求使用动态存储卷;
2、Scheduler 根据 Pod 配置、节点状态、PV 配置等信息,把 Pod 调度到一个合适的 Worker 节点上;
3、PV 控制器 watch 到该 Pod 使用的 PVC 处于 Pending 状态,于是调用 Volume Plugin(intree)创建存储卷,并创建 PV 对象(out-of-tree 由 External Provisioner 来处理);
4、AD 控制器发现 Pod 和 PVC 处于待挂接状态,于是调用 Volume Plugin 挂接存储设备到目标Worker 节点上
5、在 Worker 节点上,Kubelet 中的 Volume Manager 等待存储设备挂接完成,并通过 Volume
Plugin 将设备挂载到全局目录: **/var/lib/kubelet/pods/[pod uid]/volumes/kubernetes.io~iscsi/[PVname]**(以 iscsi 为例);
6、Kubelet 通过 Docker 启动 Pod 的 Containers,用 bind mount 方式将已挂载到本地全局目录的卷映射到容器中。
1.3、SC-StorageClass
1.3.1、需求
对于我们学习到的 PV 和 PVC 的使用方法而言,整个过程是比较繁琐的,不仅仅需要自己定义PV和PVC还需
要将其与Pod进行关联,而且对于PV和PVC的适配我们也要做好前提规划,而生产环境中,这种繁琐的事情是
有悖于我们使用kubernetes的原则的,而且这种方式在很大程度上并不能满足我们的需求,,而且不同的应
用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,比如我们有一个应用需要对存储的
并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于 StatefulSet 类型的应用简单
的来使用静态的 PV 就很不合适了,这种情况下我们就需要用到动态 PV。
1.3.2、简介
Kubernetes 为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可
以将存储资源定义为某种类型的资源,比如存储质量、快速存储、慢速存储等,为了满足不同用户的多种多样
的需求,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。
所以,StorageClass提供了一种资源使用的描述方式,使得管理员能够描述提供的存储的服务质量和等级,进而做出不同级别的存储服务和后端策略。
1.4、PV、PVC属性解析
1.4.1、PV-属性
PV的配置方法
静态:
集群管理员预制创建一些 PV。它们带有可供群集用户使用的实际存储的细节。
动态:
集群尝试根据用户请求动态地创建卷。此配置基于 StorageClasses:PVC 必须请求存储类,并且管
理员必须创建并配置该类才能进行动态创建。声明该类为 "" 可以有效地禁用其动态配置。
PV的属性信息
PV 作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略等关键信息
kubectl explain pv.spec
capacity 定义pv使用多少资源,仅限于空间的设定
accessModes 访问模式存储类型 每种存储类型的样式的属性名称都是专有的。
persistentVolumeReclaimPolicy 资源回收策略,主要三种Retain、Delete、Recycle
1.4.2、PVC-属性
它与所有空间都能使用的pv不一样,pvc是属于名称空间级别的资源对象,也就是说只有特定的资源才能使用
kubectl explain pods.spec.volumes.persistentVolumeClaim
claimName 定义pvc的名称
readOnly 设定pvc是否只读
kubectl explain pvc.spec
accessModes 访问模式 *
resources 资源限制 *
selector 标签选择器
storageClassName 动态存储名称
volumeMode 后端存储卷的模式
volumeName 指定卷(pv)的名称
1.5、PV生命周期状态图
状态 解析
Availabled 空闲状态,表示pv没有被其他对象使用
Bound 绑定状态,表示pv已经被其他对象使用
Released 未回收状态,表示pvc已经被删除了,但是资源没有被回收
Faild 资源回收失败
注意:这个过程是单向过程,不能逆向。
1.6、AccessModes属性介绍
AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括
类型 解析
ReadWriteOnce(RWO) 单节点读写
ReadOnlyMany(ROX) 多节点只读
ReadWriteMany(RWX) 多节点读写
ReadWriteOncePod(RWOP) 单pod读写
注意:
不同的后端存储支持不同的访问模式,所以要根据后端存储类型来设置访问模式。
一些 PV 可能支持多种访问模式,但是在挂载的时候只能使用一种访问模式,多种访问模式是不会生效的
1.7、PV - Retain、Recycle、Delete三种资源回收策略
当pod结束 volume 后可以回收资源对象删除PVC,而绑定关系就不存在了,当绑定关系不存在后这个PV需
要怎么处理,而PersistentVolume 的回收策略告诉集群在存储卷声明释放后应如何处理该卷。目前,
volume 的处理策略有保留、回收或删除。
类型 解析
Retain 保留存储空间数据,一般推荐使用此项,但是数据的删除需要人工干预
Recycle 清空存储空间
Delete 相关的存储实例一并删除。
注意:
目前,只有 NFS 和 HostPath 支持 Recycle 策略,其他支持 Delete 策略
2、PV & PVC实践
2.1、PV-实践
2.1.1、需求
PV对象可以有很多常见的类型:本地磁盘、NFS、分布式文件系统...我们接下来就以常见的NFS类型创建一个3G大小的存储资源对象
因为我们有一个现成的nfs环境,所以我们就创建一个NFS类型的pv(使用hostPath方式也可以)
2.1.2、定义资源配置清单
cat > storage-pv.yml<<'EOF'
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-test
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteOnce
nfs:
path: /nfs-data
server: 192.168.10.33
EOF
# 注意:虽然我们在创建pv的时候没有指定回收策略,而其策略自动帮我们配置了Retain
2.1.3、应用资源配置清单
master1 ]# kubectl apply -f storage-pv.yml
persistentvolume/pv-test created
master1 ]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-test 3Gi RWO Retain Available 3s
master1 ]# kubectl describe pv pv-test
Name: pv-test
Labels: <none>
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass:
Status: Available
Claim:
Reclaim Policy: Retain
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 3Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 192.168.10.33
Path: /nfs-data
ReadOnly: false
Events: <none>
2.1.4、配置清单属性解析
如果该pv的使用方式多的话,可以这么写:accessModes: ["ReadWriteMany","ReadWriteOnce"]
如果nfs提供的目录空间个数多的话,我们这里可以同样的方式写多个。
Pv的资源对象类型:PersistentVolume
存储空间大小设定:capacity
存储空间的访问模式:accessModes
ReadWriteOnce —— 该volume只能被单个节点以读写的方式映射
ReadOnlyMany —— 该volume可以被多个节点以只读方式映射
ReadWriteMany —— 该volume只能被多个节点以读写的方式映射
可以指定回收策略:persistentVolumeReclaimPolicy: Recycle
2.2、PVC-实践
2.2.1、定义资源配置清单
cat >storage-pvc.yml<<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
2.2.2、应用资源配置清单
master1 ]# kubectl apply -f storage-pvc.yml
persistentvolumeclaim/pvc-test created
master1 ]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-test Bound pv-test 3Gi RWO 4s
# 一旦我们启动pvc之后,他会自动去搜寻合适的可用的pv,然后绑定在一起,否则的话,pvc找不到对应的pv资源的话,他的状态会一直处于pending。
master1 ]# kubectl describe pvc pvc-test
Name: pvc-test
Namespace: default
StorageClass:
Status: Bound
Volume: pv-test
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 3Gi
Access Modes: RWO
VolumeMode: Filesystem
Used By: <none>
Events: <none>
3、应用实践
3.1、Nginx目录PVC挂载-实践
3.1.1、定义资源配置清单
cat >nginx-pvc.yml<<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
volumes:
- name: nginx-volume
persistentVolumeClaim:
claimName: pvc-test
containers:
- name: nginx-pv
image: 192.168.10.33:80/k8s/my_nginx:v1
volumeMounts:
- name: nginx-volume
mountPath: "/usr/share/nginx/html"
EOF
3.1.2、属性解析
spec.volumes 是针对pod资源申请的存储资源来说的,我们这里使用的主要是pvc的方式。
spec.containers.volumeMounts 是针对pod资源对申请到的存储资源的具体使用信息。
这里将本地的nfs目录挂载到
3.1.3、应用资源配置清单
master1 ]# kubectl apply -f nginx-pvc.yml
pod/nginx-pod created
master1 ]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 22s
master1 ]# kubectl describe pod nginx-pod
...
Mounts:
/usr/share/nginx/html from nginx-volume (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-tj96q (ro)
...
Volumes:
nginx-volume:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: pvc-test
ReadOnly: false
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 86s default-scheduler Successfully assigned default/nginx-pod to node1
Normal Pulled 85s kubelet Container image "192.168.10.33:80/k8s/my_nginx:v1" already present on machine
Normal Created 85s kubelet Created container nginx-pv
Normal Started 85s kubelet Started container nginx-pv
# 设置nginx默认主页
register ~]# echo "Hello Kubernetes PV" > /nfs-data/index.html
# 测试是否正常访问
master1 ]# curl 10.244.3.230
Hello Kubernetes PV
3.2、subPath-实践
3.2.1、需求
当前的nginx首页存放在/nfs-data的一级目录中,但是生产中,一个nfs肯定是对多个应用来使用的,所以
我们需要定制app的子目录首页,但是如果我们采用定制pv的方式,有些太繁琐了,有没有什么办法解决这种场景问题呢?
3.2.2、属性解析
这个功能其实可以直接在容器内部的属性直接实现,而无需对pv和pvc进行变动,这个属性是:
kubectl explain deployment.spec.template.spec.containers.volumeMounts
subPath <string>
属性解析:
subPath的属性主要的目的是设置数据卷的源地址,
不设置的话,表示是源地址的根目录
设置的话,表示是源地址的子目录
3.2.3、定义资源配置清单
cat >nginx-pvc-subdir.yml<<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
volumes:
- name: nginx-volume
persistentVolumeClaim:
claimName: pvc-test
containers:
- name: nginx-pv
image: 192.168.10.33:80/k8s/my_nginx:v1
volumeMounts:
- name: nginx-volume
mountPath: "/usr/share/nginx/html"
subPath: web1
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-flask
spec:
volumes:
- name: nginx-volume
persistentVolumeClaim:
claimName: pvc-test
containers:
- name: nginx-flask
image: 192.168.10.33:80/k8s/my_nginx:v1
volumeMounts:
- name: nginx-volume
mountPath: "/usr/share/nginx/html"
subPath: web2
EOF
3.2.4、应用资源配置清单
master1 ]# kubectl apply -f nginx-pvc-subdir.yml
pod/nginx-pod created
pod/nginx-flask created
master1 storage]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-flask 1/1 Running 0 2m 10.244.3.232 node1 <none> <none>
nginx-pod 1/1 Running 0 2m 10.244.3.231 node1 <none> <none>
# 往NFS写入测试的默认主页
register ~]# echo "web1 home">/nfs-data/web1/index.html
register ~]# echo "web2 home">/nfs-data/web2/index.html
# 访问测试
master1 ]# curl 10.244.3.232
web2 home
master1 ]# curl 10.244.3.231
web1 home
3.3、多PV、PVC-实践
3.3.1、NFS创建目录
register nfs-data]# mkdir redis00{1..3}
3.3.2、定义资源配置清单-创建多个pv
cat >pv-nfs-mul.yml<<'EOF'
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-001
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: "/nfs-data/redis001"
server: 192.168.10.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-002
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: "/nfs-data/redis002"
server: 192.168.10.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-003
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
path: "/nfs-data/redis003"
server: 192.168.10.33
EOF
3.3.3、应用pv资源配置清单
master1 ]# kubectl apply -f pv-nfs-mul.yml
persistentvolume/pv-nfs-001 created
persistentvolume/pv-nfs-002 created
persistentvolume/pv-nfs-003 created
master1 ]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-001 5Gi RWX Retain Available 3s
pv-nfs-002 5Gi ROX Retain Available 3s
pv-nfs-003 1Gi RWO Retain Available 3s
pv-test 3Gi RWO Retain Bound default/pvc-test 177m
3.3.4、定义资源配置清单-创建PVC
cat >pvc-mul.yml<<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo-0001
namespace: default
spec:
accessModes: ["ReadWriteMany"]
volumeMode: Filesystem
resources:
requests:
storage: 3Gi
limits:
storage: 10Gi
EOF
3.3.5、应用资源配置清单
master1 ]# kubectl apply -f pvc-mul.yml
persistentvolumeclaim/pvc-demo-0001 created
master1 ]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-001 5Gi RWX 2s
pvc-test Bound pv-test 3Gi RWO 97m
master1 ]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-001 5Gi RWX Retain Bound default/pvc-demo-0001 4m34s
pv-nfs-002 5Gi ROX Retain Available 4m34s
pv-nfs-003 1Gi RWO Retain Available 4m34s
pv-test 3Gi RWO Retain Bound default/pvc-test 3h1m
4、PV、PVC资源释放
4.1、删除pvc
# 在删除pvc的时候,应该先删除pvc被应用的pod资源
kubectl delete -f nginx-pvc.yml
kubectl delete -f storage-pvc.yml
master1 ]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-001 5Gi RWX Retain Bound default/pvc-demo-0001 10m
pv-nfs-002 5Gi ROX Retain Available 10m
pv-nfs-003 1Gi RWO Retain Available 10m
pv-test 3Gi RWO Retain Released default/pvc-test 3h7m
# 当移除pvc后,pv资源就被释放了,pv的状态变成了 Released。
4.2、强制删除
4.2.1、需求
生产中,对于存储资源的释放,最好按照流程来,即先清空应用,然后在清空pvc,但是生产中,经常遇
到应用资源意外终止或者其他情况,导致我们的pvc资源没有使用,而且也没有清空,我们推荐有多种方式,
最常用的一种方式就是,在所有的应用pod中增加一个prestop的钩子函数,从而让我们的应用资源合理的清空。
而对于特殊的异常情况,我们还有另外一种策略,即强制清空--一般不推荐使用。
4.2.2、正常删除
master1 ]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-001 5Gi RWX Retain Bound default/pvc-demo-0001 13m
pv-nfs-002 5Gi ROX Retain Available 13m
pv-nfs-003 1Gi RWO Retain Available 13m
pv-test 3Gi RWO Retain Released default/pvc-test 3h10m
master1 ]# kubectl delete pv pv-nfs-002
4.2.3、强制删除
master1 ]# kubectl delete pv pv-nfs-003 --grace-period=0 --force=true
4.3、pv claim占用无法挂载的处理
kubectl patch pv prometheus-data-pv -p '{"spec":{"claimRef": null}}'
5、StorageClass-实践
由于操作的东西比较多,单独开一个小节。