第10章 Kubernetes存储

1. 为什么需要存储卷?

2. 数据卷概述

3. 临时数据卷,节点数据卷,网络数据卷

4. 持久数据卷概述

5. PV与PVC使用流程

6. PV生命周期

7. PV动态供给

8. 有状态应用部署:StatefulSet工作负载控制器

9. 应用程序配置文件存储:ConfigMap

10.敏感数据存储:Secret

10.1 为什么需要数据卷?

容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题。

问题1:当容器崩溃时,kubelet会重建容器,容器内文件丢失

问题2:一个pod中运行多个容器并需要共享文件

Kubernetes卷(volume)这一抽象概念能够解决这两个问题

常用的数据卷:

• 节点本地(hostPath,emptyDir)

• 网络(NFS,Ceph,GlusterFS)

• 公有云(AWS EBS)

• K8S资源(configmap,secret)

10.2临时数据卷:emptyDir

emptyDir卷:是一个临时存储卷,与pod生命周期绑定一起,如果Pod删除了卷也会被删除。

应用场景:Pod中容器之间数据共享。

示例:Pod内容器之前共享数据

复制代码
apiVersion: v1
kind: Pod
metadata:
 name: my-pod
spec:
 containers:
 - name: write
   image: centos
   command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
   volumeMounts:
    - name: data
      mountPath: /data
 - name: read
   image: centos
   command: ["bash","-c","tail -f /data/hello"]
   volumeMounts:
    - name: data
      mountPath: /data
 volumes: 
  - name: data
emptyDir: {}
复制代码

验证结果:

复制代码
root@k8s-master1 ~]# kubectl  exec -it my-pod -c write -- bash
[root@my-pod /]# tail -f /data/hello 
10
11
12
13
[root@k8s-node1 ~]# kubectl logs  my-pod -c  read -f 
7
8
9
10
11
12
13
14
复制代码

10.3节点数据卷:hostpath

Hostpath卷:挂载Node文件系统(pod所在节点)上传或者目录到pod中的容器。

应用场景:Pod中容器需要访问宿主机文件

示例:将宿主机/tmp目录挂载到容器/data目录

复制代码
apiVersion: v1
kind: Pod
metadata:
 name: hostpath-pod
spec:
 containers:
 - name: busybox
   image: busybox
   args:
   - /bin/sh
   - -c
   - sleep 36000
   volumeMounts:
   - name: data
     mountPath: /data
 volumes:
 - name: data
   hostPath:
    path: /tmp
    type: Directory
复制代码

10.4 网络数据卷:NFS

NFS卷:提供对NFS挂载支持,可以自动将NFS共享路径挂载到pod中

复制代码
NFS:是一个主流的文件共享服务器。
# yum install nfs-utils
# vi /etc/exports
/ifs/kubernetes *(rw,no_root_squash)
# mkdir -p /ifs/kubernetes
# systemctl start nfs
# systemctl enable nfs
注:每个Node上都要安装nfs-utils包
mount -t nfs 192.168.31.71:/ifs/kubernetes /mnt
showmount -e
复制代码

示例:将Nginx网站程序根目录持久化到NFS存储,为多个Pod提供网站程序文件

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
 name: web
spec:
 selector:
  matchLabels:
   app: nginx
 replicas: 3
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: nginx
     volumeMounts:
     - name: wwwroot
       mountPath: /usr/share/nginx/html
      ports:
      - containerPort: 80
     volumes:
     - name: wwwroot
       nfs:
        server: 192.168.31.63
        path: /ifs/kubernetes
---      
apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web-nfs
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
app: nginx
project: ms          
##############
Master主机的mnt为挂载目录,node2机器为远程挂载目录
Mount  -t nfs  192.168.31.73: /ifs/kubernetes  /mnt                                                                                                     
View Code
复制代码

10.5 Pv和PVC持久数据卷概述

  • PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理
  • PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节
  • Pod申请PVC作为卷来使用,Kubernetes通过PVC查找绑定的PV,并Mount给pod。
10.5.1 PV与PVC使用流程 

容器应用:

复制代码
apiVersion: v1
kind: Pod
metadata:
 name: my-pod
spec:
 containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
     - name: www
       mountPath: /usr/share/nginx/html
 volumes:
  - name: www
    persistentVolumeClaim:
     claimName: my-pvc
复制代码

数据卷定义:

复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
 name: my-pv
spec:
 capacity:
  storage: 5Gi
 accessModes:
  - ReadWriteMany
 nfs:
  path: /ifs/kubernetes
  server: 192.168.31.71
复制代码

卷需求模板:

复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: my-pvc
spec:
 accessModes:
  - ReadWriteMany
 resources:
  requests:
   storage: 5Gi
复制代码

10.6PV生命周期

 10.6.1AccessModes(访问模式):

AccessModes是用来对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

  • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
  • ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
  • ReadWriteMany(RWX):读写权限,可以被多个节点挂载
10.6.2RECLAIM POLICY(回收策略): 

目前PV支持的策略有三种:

  • Retain(保留):保留数据,需要管理员手工清理数据
  • Recycle(回收):清除PV中的数据,效果相当于执行rm -rf /ifs/kubernetes/*
  • Delete(删除):与PV相连的后端存储同时删除

10.6.3Status状态

一个PV的生命周期中,可能会处于4种不同的阶段

  • Available)(可用):表示可用状态,还未被任何PVC绑定
  • Bound(已绑定):表示PV已经被PVC绑定
  • Released(已释放):PVC被删除,但是资源还未被集群重新声明
  • Failed(失败):表示该pv的自动回收失败

10.7PV的静态供给

现在PV使用方式称为静态供给,需要K8s运维工程师提前创建一堆PV,供开发者使用。

10.8PV动态供给(StorageClass)

PV静态供给明显的缺点是维护成本太高了!

因此,k8s开始支持PV动态供给,使用StorageClass对象实现。

SC是storageClass的缩写,表示存储类;这种资源主要用来对pv资源的自动供给提供接口;所谓自动供给是指用户无需手动创建pv,而是在创建pvc时对应pv会由persistentVolume-controller自动创建并完成pv和pvc的绑定;使用sc资源的前提是对应后端存储必须
支持restful类型接口的管理接口,并且pvc必须指定对应存储类名称来引用SC;简单讲SC资源就是用来为后端存储提供自动创建pv并关联对应pvc的接口;

 

10.8.1 基于NFS实现动态供给流程图

10.8.2 PV动态供给(StorageClass)

K8s默认不支持NFS动态供给,需要单独部署社区开发的插件。

项目地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

部署基于SC创建动态存储

复制代码
cat << EOF > nginx-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nginx-nfs-storage
  namespace: nginx-ss
provisioner: fuseim.pri/ifs  # or choose another name, must match deployment's env PROVISIONER_NAME'
reclaimPolicy: Retain        #回收策略:Retain(保留)、 Recycle(回收)或者Delete(删除)
volumeBindingMode: Immediate    #volumeBindingMode存储卷绑定策略
allowVolumeExpansion: true    #pvc是否允许扩容
EOF
复制代码

volumeBindingMode存储卷绑定策略

  • Immediate:创建PVC后立即创建存储卷,并且立即绑定新创建的pv和pvc。
  • WaitForFirstConsumer:当pvc被pod使用时,才触发pv和后端存储的创建,同时时间pvc/pv绑定,启用该配置后,Storage Class 中的Zone 和Region将不再生效,而是使用pod调度所在节点的zone和region创建文件系统,保证文件系统能被pod挂载。

StorageClass的定义包含四个部分:

  • provisioner:该字段指定使用存储卷类型,不同的存储卷提供者类型这里要修改成对应的值。【注意】provisioner必须和上面得Deployment的YAML文件中PROVISIONER_NAME的值保持一致。

  • parameters:指定 provisioner 的选项,比如 glusterfs 支持 resturl、restuser 等参数。

  • mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hard 和 nfsvers=4.2 等选项。

  • reclaimPolicy:指定回收策略,同 PV 的回收策略。Retain(保留)、 Recycle(回收)或者Delete(删除)

cd deploy

kubectl apply -f rbac.yaml # 授权访问apiserver

kubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服务器地址与共享目录

kubectl apply -f class.yaml # 创建存储类

kubectl get sc # 查看存储类

10.8.3 测试:在创建pvc时指定存储类名称
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: test-claim
spec:
 storageClassName: "managed-nfs-storage"
 accessModes:
  - ReadWriteMany
 resources:
  requests:
   storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
 name: test-pod
spec:
 containers:
 - name: test-pod
   image: nginx
   volumeMounts:
    - name: nfs-pvc
      mountPath: "/usr/share/nginx/html"
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:
     claimName: test-claim
View Code

10.9PV与PVC可能存在疑问 

复制代码
1、PV与PVC什么关系
一对一关系
2、pv与pvc什么匹配条件
- 存储容量
- 访问模式
3、容量匹配策略
- 匹配最接近的PV容量(匹配大的)
- 如果都满足不了,pvc处于pending
4、容量是实际限制?
不能是用于限制,主要匹配的一种标记,实际取决于后端的存储。
5、一个deployment能不能使用多个pvc
可以,定义多个卷来源和pvc
复制代码
10.9.1创建pvc之后,一直绑定不上pv(pending)

1.pvc的空间申请大小大于pv的大小;

2.pvc的StorageClassName没有和pv的的一致;

3.pvc的accessModes和pv的一致。

10.9.2创建挂载了PVC的pod之后,一直处于pending状态:
  1. pvc没有被创建成功,或者被创建
  2. pvc和pod不在同一Namespace。
10.9.3 pvc的删除操作:

删除pvc后,k8s会创建一个用于回收的pod,根据pv的回收策略进行pv的回收,回收完以后pv的状态就会变成可被绑定的状态也就是空闲状态,其他的pending状态的pvc如果匹配到了这个pv,他就能和这个pv进行绑定。

10.10有状态应用部署:statefulset控制器

有状态与无状态:

  Deployment控制器设计原则:管理所有pod一摸一样,提供同一服务,也不考虑在那台Node运行,可随意扩容和缩容。这种应用称为"无状态",例如web服务。

  在实际的场景中,这并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如主从关系,主备关系,这种应用称为"有状态",例如:mysql,etcd集群

10.10.1statefulset控制器的特定:
  • 部署有状态应用
  • 解决Pod独立生命周期,保持Pod启动顺序和唯一性

(1)   稳定,唯一的网络标识符,持久存储

(2)   有序,优雅的部署和扩展、删除和终止

(3)   有序,滚动更新

应用场景:分布式应用,数据库集群

10.10.2StatefulSet控制器的网络ID和存储
  • 稳定的网络ID

使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份。并且添加serviceName:“nginx”字段指定StatefulSet控制器要使用这个Headless Service

DNS解析名称:<statefulsetName-index>.<service-name> .<namespace-name>.svc.cluster.local

  • 稳定的存储

StatefulSet的存储卷使用VolumeClaim Template创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC

10.10.3 StatefulSet与Deployment区别:有身份的! 

身份三要素:

  • 域名
  • 主机名
  • 存储(PVC)

10.11应用程序数据存储

  • ConfigMap:存储配置文件
  • Secret:存储敏感数据

10.11.1 应用程序数据存储:ConfigMap

创建ConfigMap后,数据实际会存储在k8s中Etcd,然后通过创建pod时引用该数据。

应用场景:应用程序配置

Pod使用configmap数据有两种方式:

  • 变量注入
  • 数据卷挂载

10.11.2 应用程序数据存储:ConfigMap

 

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
 containers:
   - name: demo
     image: nginx
     env:
      - name: ABCD
        valueFrom:
         configMapKeyRef:
          name: configmap-demo
          key: abc
      - name: CDEF
        valueFrom:
         configMapKeyRef:
          name: configmap-demo
          key: cde
     volumeMounts:
     - name: config
       mountPath: "/config"
       readOnly: true
 volumes:
  - name: config
    configMap:
     name: configmap-demo
     items:
     - key: "redis.properties"
       path: "redis.properties"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo
data:
 abc: "123"
 cde: "456"
 redis.properties: |
  port: 6379
  host: 192.168.31.10
复制代码

验证结果:

10.11.3 应用程序数据存储:Secret

与ConfigMap类似,区别在于Secret主要存储敏感数据,所有的数据要经过base64编码。。

应用场景:凭据

       Kubectl create secret 支持三种数据类型:

  • Docker-registry:存储镜像仓库认证信息
  • Generic:从文件、目录或者字符串创建,例如存储用密码
  • Tls:存储证书,例如Https证书

10.11.4 使用应用程序数据存储Secret

 
复制代码
apiVersion: v1
kind: Secret
metadata:
 name: db-user-pass
type: Opaque
data:
 username: YWRtaW4=
 password: MWYyZDFlMmU2N2Rm
---
apiVersion: v1
kind: Pod
metadata:
 name: secret-demo-pod
spec:
 containers:
   - name: demo
     image: nginx
     env:
      - name: USER
        valueFrom:
         secretKeyRef:
          name: db-user-pass
          key: username
      - name: PASS
        valueFrom:
         secretKeyRef:
          name: db-user-pass
          key: password
     volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
 volumes:
   - name: config
     secret:
      secretName: db-user-pass
      items:
      - key: username
        path: my-username
View Code
复制代码

 

 

posted @   逆风飞翔的博客  阅读(21)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示