k8s阶段03 持久卷, PV和PVC, CSI存储方案示例csi-driver-nfs, OpenEBS, ConfigMap, Secret, DownwardAPI和Projected

2持久卷

PV和PVC

在Pod级别定义存储卷有两个弊端
  卷对象的生命周期无法独立于Pod而存在
  用户必须要足够熟悉可用的存储及其详情才能在Pod上配置和使用卷
  
PV和PVC可用于降低这种耦合关系
  PV(Persistent Volume)是集群级别的资源,负责将存储空间引入到集群中,通常由管理员定义
  PVC(Persistent Volume Claim)是名称空间级别的资源,由用户定义,用于在空闲的PV中申请使用符合过滤
条件的PV之一,与选定的PV是“一对一”的关系
  用户在Pod上通过pvc插件请求绑定使用定义好的PVC资源
  
StorageClass资源支持PV的动态预配(Provision)

PV, PVC 
    PV置备(provision)方式:
        静态置备:也可以使用StorageClass,分组,亦可作为筛选条件之一,可选项;
        动态置备:依赖于StorageClass(模板),必选项#后端存储需要支持动态置备功能

PV资源
  PV是标准的资源类型,除了负责关联至后端存储系统外,它通常还需要定义支持的存储特性
    Volume Mode:当前PV卷提供的存储空间模型,分为块设备和文件系统两种
    StorageClassName:当前PV隶属的存储类;
    #文件系统没有限制,块设备系统只能单路读写访问
    AccessMode:支持的访问模型,分为单路读写、多路读写和多路只读三种
    Size:当前PV允许使用的空间上限
  在对象元数据上,还能够根据需要定义标签
  #Retain:保留数据,PV变为release状态,待人工介入;Recycle:数据清除,PV可再次被其他PVC绑定(危险,被废弃)
  #Delete:删除PV,但后端存储空间的数据没被删
  一般需要定义回收策略:Retain、Recycle和Delete
  
PVC资源
  PVC也是标准的资源类型,它允许用户按需指定期望的存储特性,并以之为条件,按特定的条件顺序进行PV过滤
    VolumeMode → LabelSelector → StorageClassName → AccessMode → Size
  支持动态预配的存储类,还可以根据PVC的条件按需完成PV创建

使用静态PV和PVC的配置卷的步骤

 基于NFS的静态PV和PVC示例

#NFS PV 资源定义示例
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-demo
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:    #这里可以把支持的类型都声明出来
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain #回收策略
  mountOptions: #挂载选项,非必须项
    - hard
    - nfsvers=4.1
  nfs:
    path: "/data/redis"
    server: nfs.magedu.com
    
#PVC 资源定义示例
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
  namespace: default #可省略
spec:
  accessModes: ["ReadWriteMany"]
  volumeMode: Filesystem
  resources: #定义资源
    requests: #最小不能小于
      storage: 3Gi
    limits: #最大不能超过
      storage: 10Gi
      
#在Pod上使用PVC卷
apiVersion: v1
kind: Pod
metadata:
  name: volumes-pvc-demo
  namespace: default
spec:
  containers:
  - name: redis
    image: redis:alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 6379
      name: redisport
    volumeMounts:
    - mountPath: /data
      name: redis-rbd-vol
volumes:
- name: redis-rbd-vol
  persistentVolumeClaim:
    claimName: pvc-demo    #使用上面定义的pvc名字

实际操作示例

#在nfs服务器上创建文件夹导出
[root@ubuntu ~]#mkdir -pv /data/pv001
[root@ubuntu ~]#vim /etc/exports
/data/pv001/ 10.0.0.0/16(rw,async,no_subtree_check,no_root_squash)
#重新导出
[root@ubuntu ~]#exportfs -arv

#在k8s的控制节点上
[root@master01 volumes]#vim pv-nfs-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-demo
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
    - ReadOnlyMany
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path:  "/data/pv001"
    server: 10.0.0.155
    
[root@master01 volumes]#kubectl apply -f pv-nfs-demo.yaml
#查看pv (这里没定义STORAGECLASS,等下pvc也不能定义分类,否则找不到)
[root@master01 volumes]#kubectl get pv 
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-nfs-demo   5Gi        RWX            Retain           Available                          <unset>                          41s

[root@master01 volumes]#vim pvc-demo.yaml #会从Available状态的PV中进行筛选
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  accessModes: ["ReadWriteMany"] #能兼容对方就可以
  volumeMode: Filesystem
  resources:
    requests: #尽量接近3G
      storage: 3Gi
    limits:
      storage: 10Gi
[root@master01 volumes]#kubectl apply -f pvc-demo.yaml
#获取pvc要指名称空间,default可以不指,状态为bound绑定,一创建立即绑定
[root@master01 volumes]#kubectl get pvc -n default
NAME       STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc-demo   Bound    pv-nfs-demo   5Gi        RWO,ROX,RWX                   <unset>                 11m
#查看pv也能看出被绑定状态
[root@master01 volumes]#kubectl get pv

#定义pod使用pvc
[root@master01 volumes]#vim pod-with-pvc-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-dyn-pvc
spec:
  containers:
  - name: redis
    image: redis:7-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 6379
      name: redisport
    volumeMounts:
    - mountPath: /data
      name: redis-pvc-vol
  volumes:
  - name: redis-pvc-vol
    persistentVolumeClaim:
      claimName: pvc-demo
[root@master01 volumes]#kubectl apply -f pod-with-pvc-demo.yaml

#进入容器验证
[root@master01 volumes]#kubectl exec -it redis-dyn-pvc -- /bin/sh
/data # redis-cli
127.0.0.1:6379> set mykey "Hello"
OK
127.0.0.1:6379> BGSAVE
Background saving started
#nfs服务器上查看
[root@ubuntu ~]#ls /data/pv001/
dump.rdb

#删除pod只要不删pvc,那只要引用pvc,所有数据都在,卷也在

StorageClass

StorageClass资源
  Kubernetes支持的标准资源类型之一
  为管理PV资源之便而按需创建的存储资源类别(逻辑组)
  是PVC筛选PV时的过滤条件之一
  为动态创建PV提供“模板”
    需要存储服务提供管理API
    StorageClass资源上配置接入API的各种参数
        定义在parameters字段中
        还需要使用provisioner字段指明存储服务类型
  一般由集群管理员定义,隶属集群级别
  
#StorageClass资源示例
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io    #后端存储服务由哪个供应商提供的
parameters:
  server: nfs-server.default.svc.cluster.local #nfs服务器地址
  share: / #nfs服务器暴露的路径
reclaimPolicy: Delete #动态置备的pv拿到的回收策略
volumeBindingMode: Immediate#卷绑定模式,Immediate立即绑定PV和PVC,若用本地存储用延迟绑定(等pod创建出来)
mountOptions: #nfs卷使用参数,有些服务不需要指定mountOptions
  - hard
  - nfsvers=4.1

PVC和动态PV示例

有些存储类型默认并不支持动态PV机制,如下图。可以加CSI让它支持
多数CSI存储都支持动态PV,且支持卷扩展和卷快照等功能

#PVC向StorageClass申请绑定PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-dynamic
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
storageClassName: nfs-csi

 节点本地持久卷

local持久卷
  local卷插件用于将本地存储设备(如磁盘、分区或目录)配置为卷
    基于网络存储的PV通常性能损耗较大
    直接使用节点本地的SSD磁盘可获取较好的IO性能,更适用于存储类的服务,例如MongoDB、Ceph等
  hostPath卷在Pod被重建后可能被调度至其它节点而无法再次使用此前的数据,而基于local卷,调度器能自行完成调度绑定
    hostPath卷允许Pod访问节点上的任意路径,也存在一定程度的安全风险
  基于local的PV,需要管理员通过nodeAffinity声明其定义在的节点
    用户可通过PVC关联至local类型的PV
    然后,在Pod上配置使用该PVC即可
    调度器将基于nodeAffinity将执行Pod调度

local卷只能关联静态置备的PV,目前尚不支持动态置备

#Local PV资源示例
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-demo
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:    #local卷在某个主机上的路径
    path: /disks/vol1
  nodeAffinity:    #节点选择器
    required:
      nodeSelectorTerms:    #节点过滤器
      - matchExpressions:    #匹配条件
        - key: kubernetes.io/hostname #主机上要有该标签
          operator: In #主机名得是k8s-node01.magedu.com
          values:
          - k8s-node01.magedu.com
PVC迟延绑定
  ◼ 配置PVC绑定local PV时,通常要创建一个StorageClass
    ◆provisioner字段的值“no-provisioner”表示不使用动态置备PV,因为local插件不支持
    ◆volumeBindingMode字段的值“WaitForFirstConsumer”表示等待消费者(Pod)申请使用PVC时(即第一次被调度时)再进行PV绑定,即“延迟绑定”
    ◆延迟绑定机制,提供了基于消费者的需求来判定将PVC绑定至哪个PV的可能性
  ◼ 延迟绑定机制下,PVC创建后将处于“Pending”状态,直至被Pod消费


#实际操作示例:
#作为分组使用,不作为动态置备作用
[root@master01 local-pv-demo]#vim storageclass-local.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local
provisioner: kubernetes.io/no-provisioner #固定格式,没有动态置备就不需要没有供应商
volumeBindingMode: WaitForFirstConsumer #延迟绑定(等待首次被消费)

[root@master01 local-pv-demo]#kubectl apply -f storageclass-local.yaml
#查看,storageclass可以简写为sc
[root@master01 local-pv-demo]#kubectl get sc
NAME    PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local   kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  61

#定义pv,使用local类型卷
[root@master01 local-pv-demo]#vim local-pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-demo
spec:
  capacity:
    storage: 5Gi #存储空间
  volumeMode: Filesystem #卷模式
  accessModes:
  - ReadWriteOnce #访问模式
  persistentVolumeReclaimPolicy: Delete #回收策略
  storageClassName: local    #存储类型,通过local来定义
  local: #卷插件类型
    path: /disks/vol1 #指定本地磁盘路径
  nodeAffinity: #节点选择器
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node01 #在节点1上,事先创好路径
 
[root@master01 local-pv-demo]#kubectl apply -f local-pv-demo.yaml
#查看
[root@master01 local-pv-demo]#kubectl get pv

#定义pvc
[root@master01 local-pv-demo]#vim pvc-localpv-demo.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-localpv-demo
spec:
  accessModes:#访问模式
  - ReadWriteOnce
  resources:
    requests: #需要空间大小
      storage: 5Gi
  storageClassName: local #通过哪个存储类(两种要么统一存储类,要么都不属于任何存储类)
  
[root@master01 local-pv-demo]#kubectl apply -f pvc-localpv-demo.yaml 
#查看 此时处于pending状态
[root@master01 local-pv-demo]#kubectl get pvc

#定义pod 注意:pod调度器会结合pv控制器来判定该被调度到哪个节点上(hostpath卷不会,它不会使用pv control,无法影响pod schedule)
[root@master01 local-pv-demo]#vim pod-with-localpv.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-localpv
spec:
  containers:
  - name: redis
    image: redis:7-alpine
    ports:
    - containerPort: 6379
      name: redis
    volumeMounts:
    - mountPath: "/data"
      name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: pvc-localpv-demo #使用上面定义的pvc
        
[root@master01 local-pv-demo]#kubectl apply -f pod-with-localpv.yaml
#查看,创建在node1节点上
[root@master01 local-pv-demo]#kubectl get -f pod-with-localpv.yaml -o wide
#此时查看pvc,处于绑定状态
[root@master01 local-pv-demo]#kubectl get pvc

3 Kubernetes存储架构简介

存储卷的具体的管理操作由相关的控制器向卷插件发起调用请求来完成
  ◼ AD控制器:负责存储设备的Attach/Detach操作
    ◆Attach:将设备附加到目标节点
    ◆Detach:将设备从目标节点上拆除
  ◼ 存储卷管理器:负责完成卷的Mount/Umount操作,以及设备的格式化操作等
  ◼ PV控制器:负责PV/PVC的绑定、生命周期管理,以及存储卷的Provision/Delete操作
Scheduler:特定存储插件的调度决策会受到目标节点上的存储卷的影响

  Out-of-Tree存储

CSI简介
  ◼ 容器存储接口规范,与平台无关
  ◼ 驱动程序组件
    ◆CSI Controller:负责与存储服务的API通信从而完成后端存储的管理操作
    ◆Node Plugin:也称为CSI Node,负责在节点级别完成存储卷的管理

CSI存储组件和部署架构

CSI Controller:由StatefulSet控制器对象编排运行,副本量需要设置为1,以保证只会该存储服务运行单个CSI Controller实例;
Node Plugin:由DaemonSet控制器对象编排运行,以确保每个节点上精确运行一个相关的Pod副本

csi-driver-nfs

动态置备存储

Kuberentes社区
     主社区:Kubernetes项目,及各关键子项目
     SIG: Special Intresting Group,    #csi-driver-nfs在特别兴趣组项目下(github上)
         kubernetes-sigs/
             csi-driver-nfs 
             csi-driver-lvm
             ...
             
项目:csi-driver-nfs 
    负责为现有NFS Server提供PV的动态置备能力,它依赖于一个现有的NFS Server; 
        
    测试环境中,部署NFS Server的方法: 
        (1)在Kubernetes上部署一个NFS Server;#只能在测试环境中使用
            kubectl create namespace nfs 
            kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/nfs-provisioner/nfs-server.yaml \
                    -n nfs     #指定创建在nfs服务空间
            
            访问nfs服务的入口:nfs-server.nfs.svc.cluster.local 
               
        (2)自行在Kubernetes集群外部准备一个NFS Server; #购买网上的服务
                导出目录时要使用的导出选项:(rw,fsid=0,async,no_subtree_check,no_auth_nlm,insecure,no_root_squash) 

   部署csi-driver-nfs: 
        remote install:
            curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.6.0/deploy/install-driver.sh | bash -s v4.6.0 --

        local install: 
            git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
            cd csi-driver-nfs
            ./deploy/install-driver.sh v4.6.0 local
            
    默认部署在kube-system名称空间,各Image的仓库地址是registry.k8s.io;#可能需要上外网 

#操作实例
#部署csi-driver-nfs,采用local install方式
[root@master01 ~]#git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
[root@master01 ~]#cd csi-driver-nfs/deploy
#直接部署4.6.0版本  (每个节点下载镜像并运行)
[root@master01 deploy]#kubectl apply -f v4.6.0/
#查看(默认在kube-system空间下)
[root@master01 deploy]#kubectl get pods -n kube-system -o wide

#nfs服务器上
#创建路径作为动态置备
[root@ubuntu ~]#mkdir /nfspv
[root@ubuntu ~]#vim /etc/exports
/nfspv 10.0.0.0/16(rw,fsid=0,async,no_subtree_check,no_auth_nlm,insecure,no_root_squash)
#执行重新导出
[root@ubuntu ~]#exportfs -arv

#k8s控制节点主机上
#准备StroageClass,以完成csi-driver-nfs和nfs-server之间的对接:
#要使用nfs上的存储驱动,需要定义storageclass来完成
[root@master01 ~]#vim storageclass-csi-nfs.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
  server: 10.0.0.155 #nfs服务器地址
  share: /nfspv    #nfs对应地址(会在该路径下自动创建子目录作为动态置备存储路径)
reclaimPolicy: Delete #生产中用delete回收策略有风险
volumeBindingMode: Immediate

[root@master01 ~]#kubectl apply -f storageclass-csi-nfs.yaml
#查看存储类
[root@master01 ~]#kubectl get sc

#创建PVC进行测试(只需要创建pvc即可,pv会自动创建)
#路径在:  csi-driver-nfs/deploy/example/pvc-nfs-csi-dynamic.yaml
[root@master01 ~]#vim csi-driver-nfs/deploy/example/pvc-nfs-csi-dynamic.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-dynamic
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: nfs-csi
#创建pvc
[root@master01 ~]#kubectl create -f csi-driver-nfs/deploy/example/pvc-nfs-csi-dynamic.yaml
#查看pvc (显示状态已经Bound绑定了)
[root@master01 ~]#kubectl get pvc
NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc-nfs-dynamic   Bound    pvc-f6797db7-bf8e-47fa-8bc1-6c26c6b35876   10Gi       RWX            nfs-csi        <unset>                 65s
#查看pv(pv已经被自动创建出来)
[root@master01 ~]#kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-f6797db7-bf8e-47fa-8bc1-6c26c6b35876   10Gi       RWX            Delete           Bound    default/pvc-nfs-dynamic   nfs-csi        <unset>                          104s

#在nfs服务上查看,在路径上能看到对应子目录
[root@ubuntu ~]#cd /nfspv/
[root@ubuntu nfspv]#ls
pvc-f6797db7-bf8e-47fa-8bc1-6c26c6b35876

#定义一个pod使用该pvc做测试
[root@master01 volumes]#vim pod-with-dyn-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-pvc
spec:
  containers:
  - name: redis
    image: redis:7-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 6379
      name: redisport
    volumeMounts:
    - mountPath: /data
      name: redis-pvc-vol
  volumes:
  - name: redis-pvc-vol
    persistentVolumeClaim:
      claimName: pvc-nfs-dynamic #使用上面的pvc
[root@master01 volumes]#kubectl apply -f pod-with-dyn-pvc.yaml
[root@master01 volumes]#kubectl exec -it redis-pvc -- /bin/sh
/data # redis-cli
127.0.0.1:6379> set a "hi hello"
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
/data # ls
dump.rdb

#nfs服务器上查看到数据
[root@ubuntu nfspv]#ls pvc-f6797db7-bf8e-47fa-8bc1-6c26c6b35876/
dump.rdb

示例: 部署mysql, 使用csi-driver-nfs的动态置备存储

注意: mysql如果用网络卷作为存储,性能会有很大影响, 最好使用local卷

#pvc和pod创建在同一个目录中,文件可以部署多个资源
[root@master01 pods]#vim mydb.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-mydb
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: nfs-csi
---    #上一个资源内容,用---隔开
apiVersion: v1
kind: Pod
metadata:
  name: mydb
spec:
  containers:
  - name: mydb
    image: mysql:8.0
    env:
    - name: MYSQL_RANDOM_ROOT_PASSWORD #超级用户账号
      value: M@geEdu
    - name: MYSQL_DATABASE
      value: wpdb
    - name: MYSQL_USER
      value: wpuser
    - name: MYSQL_PASSWORD
      value: wpP@ss
    volumeMounts: #调用下面的卷挂载
    - name: mydb-stor
      mountPath: /var/lib/mysql/ #挂载点(mysql默认写在该路径下)
  volumes:
  - name: mydb-stor
    persistentVolumeClaim:
      claimName: pvc-nfs-mydb #调用上面pvc

#创建名称空间
[root@master01 pods]#kubectl create namespace dev
[root@master01 pods]#kubectl apply -f mydb.yaml -n dev
[root@master01 pods]#kubectl get pvc -n dev
NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES
pvc-nfs-mydb   Bound    pvc-478ac6b1-c1c4-4fa1-a6b5-d77000011f45   10Gi       RWX
[root@master01 pods]#kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-478ac6b1-c1c4-4fa1-a6b5-d77000011f45   10Gi       RWX            Delete           Bound    dev/pvc-nfs-mydb          nfs-csi        <unset>                          10m

#nfs服务器上
[root@ubuntu nfspv]#ls pvc-478ac6b1-c1c4-4fa1-a6b5-d77000011f45/
 auto.cnf        ca.pem               ib_buffer_pool   mysql                public_key.pem    undo_002
 binlog.000001   client-cert.pem      ibdata1          mysql.ibd            server-cert.pem   wpdb
 binlog.000002   client-key.pem       ibtmp1           mysql.sock           server-key.pem
 binlog.index   '#ib_16384_0.dblwr'  '#innodb_redo'    performance_schema   sys
 ca-key.pem     '#ib_16384_1.dblwr'  '#innodb_temp'    private_key.pem      undo_001

4 CAS和OpenEBS

CAS(Container Attached Storage)简介

容器附加存储(Container Attached Storage)
  ◼ Kubernetes的卷通常是基于外部文件系统或块存储实现,这种存储方案称为共享存储(Shared Storage)
  ◼ CAS则是将存储系统自身部署为Kubernetes集群上的一种较新的存储解决方案
    ◆存储系统自身(包括存储控制器)在Kubernetes上以容器化微服务的方式运行
    ◆使得工作负载更易于移植,且更容易根据应用程序的需求改动使用的存储
    ◆通常基于工作负载或者按集群部署,因此消除了共享存储的跨工作负载甚至是跨集群的爆炸半径
  ◼ 存储在 CAS 中的数据可以直接从集群内的容器访问,从而能显著减少读/写时间
  ◼ OpenEBS是CAS存储机制的著名实现之一,由CNCF孵化
基于CAS的存储解决方案,通常包含两类组件
  ◼ 控制平面
    ◆负责配置卷以及其他同存储相关任务
    ◆由存储控制器、存储策略以及如何配置数据平面的指令组成
  ◼ 数据平面
    ◆接收并执行来自控制平面的有关如何保存和访问容器信息的指令
    ◆主要组件是实现池化存储的存储引擎,这类引擎本质上负责输入/输出卷路径
    ◆OpenEBS支持存储引擎包括Mayastor、cStor、Jiva和OpenEBS LocalPV等
    
OPenEBS: 
    CAS风格的存储解决方案之一;由控制平面和数据平面,其中的数据平面的主要组成部分是存储引擎
    支持的存储引擎,MayaStor, cStor, Jiva, LocalPV

共享存储与CAS对比

CAS的重要特征
◼ 储控制器分解为可以彼此独立运行的组成部分
◼ 每个工作负载都有自己的一个或多个控制器

OpenEBS简介

OpenEBS简介
◼ OpenEBS能够将Kubernetes工作节点上可用的任何存储转换为本地卷或分布式复制卷
◼ 最初由MayaData构建,后捐赠给了CNCF,目前是CNCF的沙箱级项目
#分布式复制卷,一份数据存两份,放到2个不同的节点上

OPenEBS: 
    卷类型:本地卷和分布式复制卷
        本地卷:磁盘、分区、文件系统目录(local Volume)、ZFS、LVM
        复制卷:
            iSCSI: cStor和Jiva
            NVMEoF: MayaStor

            Jiva或cStor要建立在本地卷功能的基础之上;
                Jiva --> 依赖于本地卷来解决每个节点上的存储需求
                
#OpenEBS架构
OpenEBS存在着众多组件,他们大体可以分以两大类
◼ 数据引擎
◼ 控制平面

数据引擎和NDM

如何选择数据引擎
  ◼ 应用程序处于生产状态且不需要存储级复制,则首选 LocalPV
  ◼ 应用程序处于生产状态并且需要存储级复制,则首选 cStor
  ◼ 应用程序较小、需要存储级复制但不需要快照或克隆,则首选 Jiva
  ◼ 应用程序需要低延迟和接近磁盘的吞吐量,需要存储级复制,并且工作节点具有性能较高的CPU、RAM和NVME,那么 Mayastor 是首选

NDM(Node Disk Manager)
  ◼ 部署OpenEBS的过程中,NDM由专用DaemonSet编排运行于每个节点上
    ◆负责发现裸设备并过滤掉不支持使用的设备,例如已经带有文件系统的磁盘
    ◆需要特权模式,访问/dev、/proc和/sys目录来监视连接的设备,并使用各种探测器获取这些设备的详细信息
  ◼ 根据过滤器(filters)检测附加到节点上的裸磁盘设备,并将它们识别为“块设备CRD”
    ◆NDM支持使用include filters或exclude filters
    ◆filter的配置保存于ConfigMap中
  ◼ 基于节点上的裸磁盘设备提供PV的存储引擎,会依赖于NDM实现其功能,这包括Local PV device 和 cStor

配置使用OpenEBS

部署使用OpenEBS的基本流程
◼ 在各节点上部署iSCSI client #存储引擎cStor,Jiva需要,其他不需要部署
◼ 在Kubernetes集群上部署OpenEBS
◼ 选择要使用的数据引擎
◼ 为选择的数据引擎准备StorageClass

注意: 如果业务数据有冗余, 使用本地卷local-hostpath。如业务数据无冗余, 用复制卷

实际操作示例 (本地卷,无法跨节点, 自动置备pv存储)

#安装openebs环境 (3.10.x版本,官网有安装方法)
#部署pod
[root@master01 ~]#kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
#会创建独立名称空间 openebs
[root@master01 ~]#kubectl get ns
#查看名称空间中的资源,会创建很多pod
[root@master01 ~]#kubectl get all -n openebs
#每个节点上都会跑一个ndm(用于发现独立的裸磁盘设备,配置为独立的block device)
[root@master01 ~]#kubectl get pods -n openebs -o wide
#查看CRD 自定义资源定义(没发现一个块磁盘,就会创建一个blockdevices,目前系统没有,不用管)
[root@master01 ~]#kubectl get crd
blockdevices.openebs.io                          2024-11-21T14:53:41Z

#自动创建两个存储类(因为用的都是本地卷,所以采用延迟绑定机制) 可改存储路径,删存储类重建或修改下,并建目录
[root@master01 ~]#kubectl get sc
NAME               PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
openebs-device     openebs.io/local               Delete          WaitForFirstConsumer   false                  12h
openebs-hostpath   openebs.io/local               Delete          WaitForFirstConsumer   false                  12h
#自此openebs环境准备完成,如果对lvm等有需求,openebs官网再部署其他pod

#准备pvc文件
[root@master01 local-pv-hostpath]#vim openebs-local-hostpath-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: openebs-local-hostpath-pvc
spec:
  storageClassName: openebs-hostpath #部署完openebs自动生成的storageClass,会自动置备存储
  accessModes:
    - ReadWriteOnce #此处必须是单路读写
  resources:
    requests: #请求使用空间5个g
      storage: 5G
[root@master01 local-pv-hostpath]#kubectl apply -f openebs-local-hostpath-pvc.yaml

root@master01 local-pv-hostpath]#kubectl get pvc
NAME                         STATUS    STORAGECLASS       VOLUMEATTRIBUTESCLASS   AGE
openebs-local-hostpath-pvc   Pending   openebs-hostpath   <unset>                 17s

#准备pod (运行pod会自动置备pv存储)
[root@master01 local-pv-hostpath]#vim redis-with-openebs-local-hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-with-openebs-local-hostpath
spec:
  containers:
  - name: redis
    image: redis:7-alpine
    ports:
    - containerPort: 6379
      name: redis
    volumeMounts:
    - mountPath: /data
      name: local-storage
  volumes:
  - name: local-storage
    persistentVolumeClaim:
      claimName: openebs-local-hostpath-pvc
[root@master01 local-pv-hostpath]#kubectl apply -f redis-with-openebs-local-hostpath.yaml
#查看创建的pods,会是pending状态(首次消费pv,pv有初始化过程,会下载一初始化pod在openebs空间,准备好会自动删除)
[root@master01 local-pv-hostpath]#kubectl get pods
redis-with-openebs-local-hostpath   0/1     Pending   0              27s

#等到running状态后,查看数据存到哪了
[root@master01 local-pv-hostpath]#kubectl get sc
[root@master01 local-pv-hostpath]#kubectl get sc openebs-hostpath -o yaml
... Default value is /var/openebs/local ...
#/var/openebs/local    pod所在节点下,在该目录下创建子目录作为pv存储后端

[root@master01 local-pv-hostpath]#kubectl get pvc
NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       VOLUMEATTRIBUTESCLASS   AGE
openebs-local-hostpath-pvc   Bound    pvc-a4125f1e-eaf3-4020-b7e8-1ff770ca7430   5G         RWO            openebs-hostpath   <unset>                 157m
#节点3上查看
[root@node03 ~]#ls /var/openebs/local
pvc-a4125f1e-eaf3-4020-b7e8-1ff770ca7430

实际操作示例 (复制卷,跨节点冗余)

#复制卷后台用的还是本地卷,在本地卷基础上加了复制的引擎(需要单独的pod来运行)
#这里采用jiva  (cstor和jiva的区别在于cstor可使用快照)

#基于上面openebs环境部署完成后
#安装jiva-operator
[root@master01 ~]#kubectl apply -f https://openebs.github.io/charts/jiva-operator.yaml
#每个节点上安装jiva驱动节点
[root@master01 ~]#kubectl get pods -n openebs

#定义jiva卷策略
[root@master01 jiva-csi]#vim openebs-jivavolumepolicy-demo.yaml
apiVersion: openebs.io/v1alpha1
kind: JivaVolumePolicy    #安装jiva创建的新的jivavolumepolicy
metadata:
  name: jivavolumepolicy-demo
  namespace: openebs #一般放在这个名称空间下
spec:
  replicaSC: openebs-hostpath #复制时使用的存储类,这里用基于目录存储(上面用的本地卷方式相同)
  target:
    # This sets the number of replicas for high-availability
    # replication factor <= no. of (CSI) nodes
    replicationFactor: 2 #复制因子,数据打算冗余几份

[root@master01 jiva-csi]#kubectl apply -f openebs-jivavolumepolicy-demo.yaml
#查看创建的jivavolumepolicy资源类型
[root@master01 jiva-csi]#kubectl get jivavolumepolicy -n openebs 
NAME                    AGE
jivavolumepolicy-demo   32s

#创建存储类
[root@master01 jiva-csi]#vim openebs-jiva-csi-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: openebs-jiva-csi
provisioner: jiva.csi.openebs.io
allowVolumeExpansion: true #是否支持卷扩缩容(使用路径不支持,用LVM支持)
parameters:
  cas-type: "jiva"
  policy: "jivavolumepolicy-demo" #在哪个policy管控jiva存储卷
  
[root@master01 jiva-csi]#kubectl apply -f openebs-jiva-csi-storageclass.yaml
[root@master01 jiva-csi]#kubectl get sc

#创建pvc
[root@master01 jiva-csi]#vim openebs-jiva-csi-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: openebs-jiva-csi-pvc
spec:
  storageClassName: openebs-jiva-csi #使用上面的存储类
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
[root@master01 jiva-csi]#kubectl apply -f openebs-jiva-csi-pvc.yaml
#查看pvc,直接绑定了(绑定的是jiva卷)
[root@master01 jiva-csi]#kubectl get pvc
NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       VOLUMEATTRIBUTESCLASS   AGE
openebs-jiva-csi-pvc         Bound    pvc-1057bf10-245f-4718-a0ca-f91cd899d952   5Gi        RWO            openebs-jiva-csi   <unset>                 31s
#查看jiva卷(jiva卷要复制2份数据到两个节点上) Unknown是因为初始化pod还没有运行完成(openebs空间下)
[root@master01 jiva-csi]#kubectl get jivavolume -n openebs 
NAME                                       REPLICACOUNT   PHASE   STATUS
pvc-1057bf10-245f-4718-a0ca-f91cd899d952   2              Ready   RW

#openebs名称空间下创建了3个pod,一个是jiva卷微控制器,另外两个是两份数据副本
[root@master01 jiva-csi]#kubectl get pods -n openebs
pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-ctrl-6c75c9d5z4vl   2/2     Running
pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-rep-0               1/1     Running
pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-rep-1               1/1     Running   
#在openebs自动创建了2个pvc
[root@master01 jiva-csi]#kubectl get pvc -n openebs
openebs-pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-rep-0
openebs-pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-rep-1

#要使用jiva的pvc存数据,在所有节点(包括master)上安装iSCSI client
[root@node01 ~]#apt-get install open-iscsi
[root@node01 ~]#systemctl enable --now iscsid

#到此为止,jiva的环境设定完成

#使用redis实例
[root@master01 jiva-csi]#vim redis-with-openebs-jiva-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-with-openebs-jiva-pvc
spec:
  containers:
  - name: redis
    image: redis:7-alpine
    ports:
    - containerPort: 6379
      name: redis
    volumeMounts:
    - mountPath: /data
      name: local-storage
  volumes:
  - name: local-storage
    persistentVolumeClaim:
      claimName: openebs-jiva-csi-pvc #使用上面基于jiva的pvc
[root@master01 jiva-csi]#kubectl apply -f redis-with-openebs-jiva-pvc.yaml

#测试
[root@master01 jiva-csi]#kubectl exec -it redis-with-openebs-jiva-pvc -- /bin/sh
/data # redis-cli
127.0.0.1:6379> SET test "testing"
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
/data # ls
dump.rdb    lost+found#说明是二进制设备存储空间

#查看存在哪个卷上
[root@master01 jiva-csi]#kubectl get pvc -n openebs
[root@master01 jiva-csi]#kubectl get pvc openebs-pvc-1057bf10-245f-4718-a0ca-f91cd899d952-jiva-rep-0 -o yaml -n openebs
...
volume.kubernetes.io/selected-node: node01
#node1节点查看(大部分rdb文件被封装了,因这是复制引擎)
[root@node01 ~]#ls /var/openebs/local/pvc-023b9bd4-5f23-4e91-a16e-545bc1aeaeef/
log.info          volume-head-001.img       volume-snap-bc8e1cfc-55f9-41e2-b093-92ec82447d8f.img
replica.log       volume-head-001.img.meta  volume-snap-bc8e1cfc-55f9-41e2-b093-92ec82447d8f.img.meta
revision.counter  volume.meta

注意: 无论是前面的hostpath还是jiva带复制能力的卷, 存取接口一般都是单路读写, 无法实现多路读写

要使用多路读写, 只能建nfs server。或者做一个jiva卷, 在jiva卷的上面再部署nfs服务(支持不太成熟,在官网上有写)

 

1 ConfigMap和Secret基础

特殊卷:configMap/secret 介绍

应用配置:
    临时卷:empytDir
    本地卷:hostPath, local 
    网络卷:nfs, ...
    特殊卷:configMap,secret, downwardAPI
    卷扩展:CSI

    特殊卷:configMap,secret, downwardAPI

    configMap/secret: 
        几重概念:
            (1) 资源类型 
            (2) 卷插件 
            
        资源类型:configMap、secret
            保存于api server中的资源对象, 最终存储于etcd中

        卷插件:
            在Pod上,基于该类型卷插件,以卷的形式引用configmap/secret资源对象

        容器配置参数:
            环境变量:
                1、启动容器时,自定义要运行的命令及选项、参数;
                    Dockerfile, CMD, ENTRYPOINT
                2、通过环境进行配置;
                    Dockerfile, entrypoint.sh脚本来代理预处理环境变量
                3、将配置焙进Image,重制Image;
                4、将配置文件放置在卷上,由容器通过卷加载;
                    卷:ConfigMap/Secret 
                    
        configMap:保存非敏感的配置,数据以明文存储
        secret: 保存敏感配置,数据以base64编码格式存储
            数据格式:
                Key: Value 

                Value:分为两类
                    单行值:单行字符串
                    多行值:文件格式的配置信息

            每个对象中,可以保存多个kv数据;
            
ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷
  ◼ ConfigMap用于为容器中的应用提供配置数据以定制程序的行为,而敏感的配置信息,例如密钥、证书等则通常由Secret来配置
  ◼ ConfigMap和Secret将相应的配置信息保存于资源对象中,而后在Pod对象上支持以存储卷的形式将其挂载并加载相关的配置,从而降低了配置与镜像文件的耦合关系,提高了镜像复用能力
  ◼ Kubernetes借助于ConfigMap对象实现了将配置文件从容器镜像中解耦,从而增强了工作负载的可移植性,使其配置更易于更改和管理,并避免了将配置数据硬编码到Pod配置清单中

此二者都属于名称空间级别,只能被同一名称空间中的Pod引用

◼ ConfigMap和Secret资源都是数据承载类的组件,是Kubernetes API的标准资源类型,是一等公民
  ◼ 主要负责提供key-value格式的数据项,其值支持
    ◆单行字符串:常用于保存环境变量值,或者命令行参数等
    ◆多行字串:常用于保存配置文件的内容

#定义示例
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-confs
data:
  PORT: "8080"
  myserver-status.cfg: | #多行的v用|加换行缩进的方式(将来转为文件会顶格写不会有缩进)
    location /nginx-status {
      stub_status on;
      access_log off;
    }

◼ 从Kubernetes v1.19版本开始,ConfigMap和Secret支持使用immutable字段创建不可变实例

在Pod中引用配置的方式

环境变量
  ◼ 将configmap对象上的某key的值赋值给(valueFrom)指定的环境变量
卷
  ◼ 在Pod上基于configMap卷插件引用configmap对象
  ◼ 在Container上挂载configMap卷
    ◆每个kv会分别被映射为一个文件,文件名同key,value将成为文件内容

2 ConfigMap

创建ConfigMap对象

创建ConfigMap对象的方法有两种
  ◼ 命令式命令
    ◆ 字面量:kubectl create configmap NAME --from-literal=key1=value1
    ◆ 从文件加载:kubectl create configmap NAME --from-file=[key=]/PATH/TO/FILE
    ◆ 从目录加载: kubectl create configmap NAME --from-file=[key=]/PATH/TO/DIR/
  ◼ 配置文件
    ◆命令式:kubectl create -f 
    ◆声明式:kubectl apply -f
提示:基于文件内容生成时,可以使用命令式命令以dry-run模式生成并保存

    创建方法:
        指令式命令:
            kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none]
            直接值:直接于命令行给出kv
            从文件加载:从文件加载生成kv
        对象配置:
            kubectl create -f /path/to/configmap_manifest_file
            
#例:
#创建demoapp-cfg名的configmap;--from-literal指定kv;可以指定名称空间,这里默认
~]#kubectl create configmap demoapp-cfg --from-literal=listen="127.0.0.1" --from-literal=port="8080"
#查看configmap,可以简称cm
~]#kubectl get cm

#不创建configmap只生成yaml
~]#kubectl create configmap demoapp-cfg --from-literal=listen="127.0.0.1" --from-literal=port="8080" --dry-run=client -o yaml

#从文件中加载
~]#kubectl create configmap nginx-cfg --from-file=./myserver.conf --dry-run=client -o yaml
apiVersion: v1
data:
  myserver.conf: |
    server {
        listen 8080;
        server_name www.ik8s.io;

        include /etc/nginx/conf.d/myserver-*.cfg;

        location / {
            root /usr/share/nginx/html;
        }
    }
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: nginx-cfg
#可以指定键名,修改将来挂载的文件名
~]#kubectl create configmap nginx-cfg --from-file=my.conf=./myserver.conf --dry-run=client -o yaml
apiVersion: v1
data:
  my.conf: |
    server {
        listen 8080;
        server_name www.ik8s.io;

        include /etc/nginx/conf.d/myserver-*.cfg;

        location / {
            root /usr/share/nginx/html;
        }
    }
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: nginx-cfg 

#加载多个文件
~]#kubectl create configmap nginx-cfg --from-file=./myserver.conf --from-file=./myserver-status.cfg --dry-run=client -o yaml

#加载当前目录下的所有文件(无法改文件名)
~]#kubectl create configmap nginx-cfg --from-file=./ --dry-run=client -o yaml


#使用示例(从环境变量中直接引用)
[root@master01 configmaps_and_secrets]#vim configmaps-env-demo.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: demoapp-config
  namespace: default
data:
  demoapp.port: "8080"
  demoapp.host: 127.0.0.1
---
apiVersion: v1
kind: Pod
metadata:
  name: configmaps-env-demo
  namespace: default
spec:
  containers:
  - image: ikubernetes/demoapp:v1.0
    name: demoapp
    env:
    - name: PORT
      valueFrom:    #引用
        configMapKeyRef: #configmap中的键引用
          name: demoapp-config #configmap名字
          key: demoapp.port #键名
          optional: false #如在ConfigMap中找不到指定的key,K8s将会报错
    - name: HOST
      valueFrom:
        configMapKeyRef:
          name: demoapp-config
          key: demoapp.host
          optional: true
#创建
[root@master01 configmaps_and_secrets]#kubectl apply -f configmaps-env-demo.yaml
configmap/demoapp-config created
pod/configmaps-env-demo created
#查看ConfigMap
[root@master01 configmaps_and_secrets]#kubectl get cm
NAME               DATA   AGE
demoapp-config     2      27s
[root@master01 configmaps_and_secrets]#kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
configmaps-env-demo   1/1     Running   0          58s
#查看是否监听8080
[root@master01 configmaps_and_secrets]#kubectl exec configmaps-env-demo -- netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN
#可以通过env打印出全部的环境变量
[root@master01 configmaps_and_secrets]#kubectl exec configmaps-env-demo -- env

#一般不建议修改configmap,但是可以修改,改法有两种
#第一种,直接修改configmap
]#vim configmaps-env-demo.yaml
  ...
  demoapp.port: "10080"
#只是变了configmap
]#kubectl apply -f configmaps-env-demo.yaml
#查看configmap的yaml形式,端口已变10080
]#kubectl get cm demoapp-config -o yaml
#查看环境变量PORT依然是8080
[root@master01 configmaps_and_secrets]#kubectl exec configmaps-env-demo -- env
#pod里面监听的端口还是8080,除非重启整个pod


#使用示例(基于卷引用方式,卷插件方式)  这种方式修改会重新注入到pod内部(能不能生效看系统是否自动装载新配置)
#创建configmap
[root@master01 configmaps_and_secrets]#kubectl create configmap nginx-config-files --from-file=./nginx-conf.d/
#调用
[root@master01 configmaps_and_secrets]#vim configmaps-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: configmaps-volume-demo
  namespace: default
spec:
  containers:
  - image: nginx:alpine
    name: nginx-server
    volumeMounts:
    - name: ngxconfs
      mountPath: /etc/nginx/conf.d/ #挂载点
      readOnly: true    #只读
  volumes:
  - name: ngxconfs
    configMap:
      name: nginx-config-files #引用nginx-config-files的configMap
      optional: false #必选
[root@master01 configmaps_and_secrets]#kubectl apply -f configmaps-volume-demo.yaml

#进入pod容器
[root@master01 configmaps_and_secrets]#kubectl exec -it configmaps-volume-demo -- /bin/sh
/etc/nginx/conf.d # ls -l
total 0
lrwxrwxrwx    1 root     root            24 Nov 23 08:27 myserver-gzip.cfg -> ..data/myserver-gzip.cfg
lrwxrwxrwx    1 root     root            26 Nov 23 08:27 myserver-status.cfg -> ..data/myserver-status.cfg
lrwxrwxrwx    1 root     root            20 Nov 23 08:27 myserver.conf -> ..data/myserver.conf
/etc/nginx/conf.d # ls -al
total 12
drwxrwxrwx    3 root     root          4096 Nov 23 08:27 .
drwxr-xr-x    3 root     root          4096 Nov 12 02:02 ..
drwxr-xr-x    2 root     root          4096 Nov 23 08:27 ..2024_11_23_08_27_23.4057447185
lrwxrwxrwx    1 root     root            32 Nov 23 08:27 ..data -> ..2024_11_23_08_27_23.4057447185
lrwxrwxrwx    1 root     root            24 Nov 23 08:27 myserver-gzip.cfg -> ..data/myserver-gzip.cfg
lrwxrwxrwx    1 root     root            26 Nov 23 08:27 myserver-status.cfg -> ..data/myserver-status.cfg
lrwxrwxrwx    1 root     root            20 Nov 23 08:27 myserver.conf -> ..data/myserver.conf
#实际上配置文件被关联到..data路径下,而它其实是..2024_11_23_08_27_23.4057447185这个隐藏目录,名字是时间戳
#这个时间戳代表configMap版本,每次改了configMap,configMap版本会变

#修改configMap内容测试
#直接在线修改configMap(这样改有风险,不建议)
[root@master01 ~]#kubectl edit cm nginx-config-files
#随便改写内容保存

#每个pod会等待一段时间(一般几秒~几十秒),pod内文件才会变更,时间k8s自行控制
#新版本可以发现配置文件变更并生效。1.20及之前的版本做不到
#查看内容,时间戳已发生改变
/etc/nginx/conf.d # ls -al
total 12
drwxrwxrwx    3 root     root          4096 Nov 23 08:43 .
drwxr-xr-x    3 root     root          4096 Nov 12 02:02 ..
drwxr-xr-x    2 root     root          4096 Nov 23 08:43 ..2024_11_23_08_43_42.901207710
lrwxrwxrwx    1 root     root            31 Nov 23 08:43 ..data -> ..2024_11_23_08_43_42.901207710
lrwxrwxrwx    1 root     root            24 Nov 23 08:27 myserver-gzip.cfg -> ..data/myserver-gzip.cfg
lrwxrwxrwx    1 root     root            26 Nov 23 08:27 myserver-status.cfg -> ..data/myserver-status.cfg
lrwxrwxrwx    1 root     root            20 Nov 23 08:27 myserver.conf -> ..data/myserver.conf
#查看里面nginx的配置已变更
#nginx -T可以查看当前nginx加载的配置,经确认也已变更(说明自动重载新配置了)
/etc/nginx/conf.d #nginx -T

#注:这种方式修改会重新注入到pod内部,是否生效看系统是否自动装载新配置(新的服务都可以,早期java可能要重启pod)

3 Secret

Secret资源类型:
    类型之分:
        kubectl create secret (docker-registry | generic | tls) [options]
            docker-registry:专用于认证到docker registry服务上的认证信息类型
                kubectl create secret docker-registry NAME --docker-username=user --docker-password=password --docker-email=email[--docker-server=string]

                引用方式:pods.spec.imagePullSecrets,列表型数据 
                第二种引用方式:pods.spec.serviceAccountName
                    serviceaccount.imagePullSecrets 
                    
            tls:专用配置服务基于ssl/tls通信时使用的数字证书和私钥的类型
                kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none]
                证书的键名:tls.crt 
                私钥的键名:tls.key 
                
            generic: 通用类型,可划分为多种子类型
                --type 

创建Secret资源

secret和configmap的显著区别是尽量不要用加载环境变量的方式去加载secret(导致敏感信息泄露), 用卷的方式加载

但有些场景没办法, 像mysql必须使用环境变量提供

支持类似于ConfigMap的创建方式,但Secret有类型子命令,而且不同类型在data或stringData字段中支持嵌套使用的key亦会有所有同;
命令式命令
  ◼ generic
    ◆kubectl create secret generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1]
    ◆除了后面docker-registry和tls命令之外的其它类型,都可以使用该命令中的--type选项进行定义,但有些类型有key的特定要求
  ◼ tls
    ◆kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file
    ◆通常,其保存cert文件内容的key为tls.crt,而保存private key的key为tls.key
  ◼ docker-registry
    ◆kubectl create secret docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-file=[key=]source]
    ◆通常,从已有的json格式的文件加载生成的就是dockerconfigjson类型,命令行直接量生成的也是该类型

#generic示例 (使用环境变量引用,不太靠谱,信息依然会泄露):
#创建secret generic类型,名称叫mysql-secret (自动做base64编码进行存储)
[root@master01 ~]#kubectl create secret generic mysql-secret --from-literal=root.password='M@geEdu' --from-literal=user.password="wpP@ss" -n wordpress
#查看secret (不归类的都定义为Opaque) DATA为2表示有2项
[root@master01 pods]#kubectl get secret -n wordpress
NAME           TYPE     DATA   AGE
mysql-secret   Opaque   2      14s
[root@master01 pods]#kubectl get secret -o yaml -n wordpress
apiVersion: v1
items:
- apiVersion: v1
  data:
    root.password: TUBnZUVkdQ==
    user.password: d3BQQHNz
  kind: Secret
  metadata:
    creationTimestamp: "2024-11-23T10:04:35Z"
    name: mysql-secret
    namespace: default
    resourceVersion: "634108"
    uid: 3b51fdcf-ba8c-437a-8b65-1b6273ea3f03
  type: Opaque
kind: List
metadata:
  resourceVersion: ""

#定义mysql的pod,引用上面的secret
]#vim pod-mydb.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mydb
  namespace: wordpress
spec:
  containers:
  - name: mydb
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD #超级用户账号
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: root.password
          optional: false #必选
    - name: MYSQL_DATABASE #放在secret或configmap都行
      value: wpdb
    - name: MYSQL_USER #放在secret或configmap都行
      value: wpuser
    - name: MYSQL_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: user.password
[root@master01 ~]#kubectl apply -f pod-mydb.yaml
[root@master01 ~]#kubectl get -f pod-mydb.yaml
#进入pod
[root@master01 ~]#kubectl exec -ti mydb -n wordpress -- /bin/sh
#查看环境变量可以看到密码
sh-5.1# env


#docker-registry示例
]#kubectl create secret docker-registry magedu-dockerhub --docker-username=magedu --docker-password=M@geEdu --docker-email=mage@magedu.com --dry-run=client -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJtYWdlZHUiLCJwYXNzd29yZCI6Ik1AZ2VFZHUiLCJlbWFpbCI6Im1hZ2VAbWFnZWR1LmNvbSIsImF1dGgiOiJiV0ZuWldSMU9rMUFaMlZGWkhVPSJ9fX0=
kind: Secret
metadata:
  creationTimestamp: null
  name: magedu-dockerhub
type: kubernetes.io/dockerconfigjson

#引用:创建pod时修改pods.spec.imagePullSecrets字段(列表型数据),把Secret值写入


#tls示例
#准备好私钥和证书
[root@master01 certs.d]#ls
nginx.crt  nginx.key
#不创建tls类型的secret,生成yaml
[root@master01 certs.d]#kubectl create secret tls nginx-cert --cert=./nginx.crt --key=./nginx.key --dry-run -o yaml
W1123 11:13:44.112377  194065 helpers.go:703] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsVENDQW4yZ0F3SUJBZ0lVR2Zya05FeGZiS2N5Yy9LYkpLUXJ5MzRTcHI0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1dqRUxNQWtHQTFVRUJoTUNRMDR4RURBT0JnTlZCQWdNQjBKbGFXcHBibWN4RURBT0JnTlZCQWNNQjBKbAphV3BwYm1jeER6QU5CZ05WQkFvTUJrUmxkazl3Y3pFV01CUUdBMVVFQXd3TmQzZDNMbWxzYVc1MWVDNXBiekFlCkZ3MHlNREEwTVRVd05UQXdORE5hRncweU1EQTFNVFV3TlRBd05ETmFNRm94Q3pBSkJnTlZCQVlUQWtOT01SQXcKRGdZRFZRUUlEQWRDWldscWFXNW5NUkF3RGdZRFZRUUhEQWRDWldscWFXNW5NUTh3RFFZRFZRUUtEQVpFWlhaUApjSE14RmpBVUJnTlZCQU1NRFhkM2R5NXBiR2x1ZFhndWFXOHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRE1pNSsyUStZTlNxeS9vVVhNQzAraklqc2puS2M5SzdjVzYweFhrQzZOa3lSY3BZSmwKdWM4ckFYRUxyZjUxMmJUWGhxb0hqVG5JeFExVFROeDNRbE9oTHBYVjJCbGtObVNzY0w0Uy9IL1VEWTlQayt0cwpiOGlEZSszdlBEQ1ZiQytvOEFYYUhUaktaQ0pXc0oxY0RJY0JGenQ0MFQzUWswL1hQcVYrM1pERWFNcW9LYklJCmRvbENLLzZiN1BlaElXVVFWeFVDK3NoZ0xVbjJReXJmK0UrRC9TQmZFOVd3UGp0YXdCeHdxaDZOczV1dEVsL0cKVmltbEMxM2tsWTNGQ1RMWEhFU3hNKzdGNlU2VUdpYm1CWFRsLzZlV1I2bmlVdW1kMjhyU2NneXVDTnA1NGY2cAp1VGFMK0ZNbG0wN0NiS3lLWHhDZHpVNXVrSFlOYXlqa3p3ck5BZ01CQUFHalV6QlJNQjBHQTFVZERnUVdCQlE1ClhNbkhJanZYZFVCb1BEd3BpbjdiVWN6SHJqQWZCZ05WSFNNRUdEQVdnQlE1WE1uSElqdlhkVUJvUER3cGluN2IKVWN6SHJqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQlVwU1pSNUE5Rgo2bVZhSU16TUl0anZadXFpRDNpeG9PN3NEdEZCcGVsYVZNV0dIaTZ3cFlTL21kNkNmS0hQQ3pySDhnNmpWTGhaClRpRWd5OVREUG5wMmU0VWNBUzdYMVBPM21GWTVscGpVakxJZjR4bUZrUy9FdFQ1ZE5TbUF1NGxGN2ZrRkEraEYKc244b2s5bk9DNk05OVBxbmQ1SlpVR1pwRFJCK1NQblpIVzZ3R2JiSVd3R3hPQmNtejBBMHNJNTkyVm9POThYKwoxK2w4MEVmdkhjRDJQRmdmSzhqS3g5eEl0UjEwcnBtVE4yQmtPQlBiREZ4SHZEcTNjRlRBSVVhMGhWS04xT0xJCk1oSEsvVnJmRUxHanJvY0pTZEFxcGpPTFl0R2JQN09sWURHTzFPRDk2ZEVTYStWWTRXYnFqYzc5S0luREQrWnkKWVlqbkJKR2F5VExyCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBekl1ZnRrUG1EVXFzdjZGRnpBdFBveUk3STV5blBTdTNGdXRNVjVBdWpaTWtYS1dDClpiblBLd0Z4QzYzK2RkbTAxNGFxQjQwNXlNVU5VMHpjZDBKVG9TNlYxZGdaWkRaa3JIQytFdngvMUEyUFQ1UHIKYkcvSWczdnQ3end3bFd3dnFQQUYyaDA0eW1RaVZyQ2RYQXlIQVJjN2VORTkwSk5QMXo2bGZ0MlF4R2pLcUNteQpDSGFKUWl2K20rejNvU0ZsRUZjVkF2cklZQzFKOWtNcTMvaFBnLzBnWHhQVnNENDdXc0FjY0tvZWpiT2JyUkpmCnhsWXBwUXRkNUpXTnhRa3kxeHhFc1RQdXhlbE9sQm9tNWdWMDVmK25sa2VwNGxMcG5kdkswbklNcmdqYWVlSCsKcWJrMmkvaFRKWnRPd215c2lsOFFuYzFPYnBCMkRXc281TThLelFJREFRQUJBb0lCQUNjeWpvMndIMUxtdjRvTgpqc0dXWFZHR3lzeDlSYk04UUY3ZEFvazVNU0tpVXZLS0tSM3phSmIyTk1Lbk9qODlWQ0dGUmVvaWp6TkJSOWR4CndFSCtiT1pUZGhVL3owWGNBcGpsRmhldldaTzZjWDh2ZW9zU05OdTFrUmdxY2FrQXpYVlRZZHUxZzkrTkp1TnoKL3dQWHhydFh4MmJVdWtMUktCaTRnYUI1TnpmY0FSdzBIWG9aUjExbVRydkhLSWRSQUx4Q21KR09aTlg5RjhGMQpsQ1dCN2hjWVNkRVg5MTBkT2VFTlRzUUNMeVJvaDdXWkJSejBEUVBYNnNJd2FJTGtFT0puSVQ0K3JYNldCZGdkCmRkRjN3L0ZYcGxFdW9BSVplSDJmZnkvMzNyTFpSSXlSZWFEVnJUeHFUMnVOQlVkbkJPN1NFa2VYV25kUEh2V2MKaUpRUGxTRUNnWUVBOXdGQmpzOGk2a0YrWDM1N09ueFpuZXB4WnVZMGhqRk5BcVdPSGlUMWsvcWt6T2pRSG1kMgpHSnJZZjc0OUc3VHB2R2Y2TytzalIvZm96ODVsdFViSnh5Wk1IK2JqQzgwM0VUeXp2TmlXZzE2MVp6Nyt5NGpKClI5dlhCS05vd0NlazVFYVRyZ3owZkp5bjJ1WlRDak1aUE1WVVFBRmlYc0RtUTAybUp6dVdwTmtDZ1lFQTAvNkkKTjg2a2szalRzaHhvTEM5VUR0K0x4VTVaUE8vS0t0a21SUEorYU1IbS9uUXJYazZ6a1pJVUF2OHIrOWZXVXdHbQpYUmd2QjVlaHAvT1htdkxLWEhSVmhhVjc3QTZvMEVQVFRrcU5iZU5GSHg1cVFObU85ZHdIVTNSTW5PeWk0TnluCmFJNlljNGIvMWJXdXlBYlVlc0tEdXI3L0FMOFo5UU1XVUVUb2pSVUNnWUF2bzY1aFBOSWZIRUtqYUdHY0JoL0MKdFZUcDQ3eDlwVVNWSGhrcTl6WG1OSkZVZEJLdnlvU2Nla0VIWWttbTdsMm1XT2VLWnUrSEVlbDFLdm15M05STgo5TFQ1OGk0WU9KeEdWczdUdlhKS0pCb1lyNjIwMDh6K2J3Z3BmTnJYTk00NHVPUUN6YnpaeTkwVCt4aEkvMUgrCnhwQlpSK3NSRzJOTjE4d1VCUW9wQVFLQmdFdnNHWDdiRytmUTJ3Z3Iwa2NZd0NML2ZvQXdPaGR2elZpaEltcUkKNmlxOFh1ejhUOWZibWNYbHFoTVVyZnpvNU5JZmdpUlBGL0RCSmwwUENWbXQ0RGxTVkpxamxJa0xDdnhqZmhiSQo3blBQZEI3YjlyTzQ5dEVvZHRzMWlJYWUzUXBwRys5L09pd055aXdRZ0VNVTV4Mzc4Yzk4dmJqWHVBVWVrT3c0CmNZeXRBb0dBTEtNazBwMUUrZHJtVzVuS3VMa2dyNDYzbmtlenBld2Y4eVJ2UHZQcUo4UkdobTBGblphOW1mQ0YKd1JCMDh1MkZ6YTRHSldEY0p2VG9kV3NtSmpCVHRMQ0wzaFlCSmNNQXNVNEdEbXBCZDdQMVBQQ1ZCb0JMeVJjbApyK2VTOFJzZTRwTERjOWdpQk9ZSGp4Q2hsVktSdVhESmh2V2k0azZVNGY5bStBNmp4STg9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
kind: Secret
metadata:
  creationTimestamp: null
  name: nginx-cert
type: kubernetes.io/tls

#tls示例,创建nginx服务,配https证书和秘钥
[root@master01 nginx-ssl-conf.d]#vim myserver.conf
server {
    listen 443 ssl;
    server_name www.ik8s.io;

    ssl_certificate /etc/nginx/certs/tls.crt; #secret挂载点,键名为文件名(会自动base64解码)
    ssl_certificate_key /etc/nginx/certs/tls.key; #secret挂载点,键名为key(会自动base64解码)

    ssl_session_timeout 5m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 

    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
    ssl_prefer_server_ciphers on;

    include /etc/nginx/conf.d/myserver-*.cfg;

    location / {
        root /usr/share/nginx/html;
    }
}

server {
    listen 80;
    server_name www.ilinux.io; 
    return 301 https://$host$request_uri; 
}

#pod文件
[root@master01 configmaps_and_secrets]#vim secrets-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: secrets-volume-demo
  namespace: default
spec:
  containers:
  - image: nginx:alpine
    name: ngxserver
    volumeMounts:
    - name: nginxcerts
      mountPath: /etc/nginx/certs/
      readOnly: true
    - name: nginxconfs #加载配置文件
      mountPath: /etc/nginx/conf.d/
      readOnly: true
  volumes:
  - name: nginxcerts
    secret:
      secretName: nginx-ssl-secret #secret名称
  - name: nginxconfs
    configMap:
      name: nginx-sslvhosts-confs
      optional: false #不加,默认为false
      
#创建secret tls类型
[root@master01 configmaps_and_secrets]#kubectl create secret tls nginx-ssl-secret --cert=./certs.d/nginx.crt --key=./certs.d/nginx.key
[root@master01 configmaps_and_secrets]#kubectl get secret
#创建configmap
[root@master01 configmaps_and_secrets]#kubectl create configmap nginx-sslvhosts-confs --from-file=./nginx-ssl-conf.d/
[root@master01 configmaps_and_secrets]#kubectl get cm
#创建pod
[root@master01 configmaps_and_secrets]#kubectl apply -f secrets-volume-demo.yaml
#进入pod查看
[root@master01 configmaps_and_secrets]#kubectl exec -it secrets-volume-demo -- /bin/sh
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
/ # cd /etc/nginx/certs/
/etc/nginx/certs # ls
tls.crt  tls.key
#和configmap的引用逻辑相同
/etc/nginx/certs # ls -al
total 4
drwxrwxrwt    3 root     root           120 Nov 23 12:42 .
drwxr-xr-x    1 root     root          4096 Nov 23 12:42 ..
drwxr-xr-x    2 root     root            80 Nov 23 12:42 ..2024_11_23_12_42_04.1485291318
lrwxrwxrwx    1 root     root            32 Nov 23 12:42 ..data -> ..2024_11_23_12_42_04.1485291318
lrwxrwxrwx    1 root     root            14 Nov 23 12:42 tls.crt -> ..data/tls.crt
lrwxrwxrwx    1 root     root            14 Nov 23 12:42 tls.key -> ..data/tls.key
#配置信息发生改变,要确保应用程序能自动重载(逻辑同configmap)

4 DownwardAPI 和 Projected

 关于DownwardAPI
 DownwardAPI
  ◼ 与ConfigMap和Secret不同,DownwardAPI自身并非一种独立的API资源类型
  ◼ DownwardAPI只是一种将Pod的metadata、spec或status中的字段值注入到其内部Container里的方式
 DownwardAPI提供了两种方式用于将 POD 的信息注入到容器内部
  ◼ 环境变量:用于单个变量,可以将 POD 信息和容器信息直接注入容器内部 #一般采用这种
  ◼ Volume挂载:将 POD 信息生成为文件,直接挂载到容器内部中去

可向容器注入的元数据

在容器上基于DownwardAPI引用Pod元数据,可通过两种字段完成
  ◼ fieldRef:引用常规的元数据
  ◼ resourceFieldRef:引用同资源限制和资源需求相关的元数据

fieldRef 如图

有关容器资源限制和资源需求的信息则要通过resourceFieldRef 字段注入
  ◼ 这些信息都能够基于环境变量和卷的方式注入到容器中

resourceFieldRef 如图

  DownwardAPI示例

#通过环境变量示例
#下面的配置片断截取自由三个RabbitMQ Pod构建的RabbitMQ Cluster配置示例之上
containers:
  - name: rabbitmq
  image: registry.magedu.com/rabbitmq/rabbitmq:3.12-management
  ports:
  - containerPort: 15672
    name: discovery
  - containerPort: 5672
    name: amqp
  env:
  - name: RABBIT_POD_NAME
    valueFrom:
      fieldRef:
        apiVersion: v1 #pod api版本号
        fieldPath: metadata.name
  - name: RABBIT_POD_NAMESPACE
    valueFrom:
      fieldRef:
        fieldPath: metadata.namespace
  - name: RABBITMQ_NODENAME #引用变量$()实现
    value: rabbit@$(RABBIT_POD_NAME).rabbitmq.$(RABBIT_POD_NAMESPACE).svc.cluster.local
  - name: RABBITMQ_USE_LONGNAME
    value: "true"
  - name: RABBITMQ_CONFIG_FILE
    value: "/config/rabbitmq"
  - name: RABBITMQ_ERLANG_COOKIE
    valueFrom:
      secretKeyRef:
        name: rabbit-secret
        key: RABBITMQ_ERLANG_COOKIE
  - name: K8S_HOSTNAME_SUFFIX
    value: .rabbitmq.$(RABBIT_POD_NAMESPACE).svc.cluster.local


#通过volume挂载示例(一般不这么用)  必须是上面支持使用卷引用的字段
]#vim pod-use-downwardapi.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod-use-downwardapi
  name: pod-use-downwardapi
spec:
  containers:
  - image: ikubernetes/demoapp:v1.0
    name: pod-use-downwardapi
    volumeMounts:
    - name: dapi
      mountPath: /dapi
  volumes:
  - name: dapi
    downwardAPI:
      items:
      - path: "name" #挂载路径下文件名
        fieldRef: #引用字段名称
          fieldPath: metadata.name
#进入容器
]#ls /dapi/
name
]#cat name
pod-use-downwardapi

Projected Volume

 Projected Volume是一种特殊的卷类型,它能够将已存在的多个卷投射进同一个挂载点目录中
 Projected Volume仅支持对如下四种类型的卷(数据源)进行投射操作,这类的卷一般都 是用于为容器提供预先定义好的数据
  ◼ Secret:投射Secret 对象
  ◼ ConfigMap:投射ConfigMap对象
  ◼ DownwardAPI:投射Pod元数据
  ◼ ServiceAccountToken:投射ServiceAccount Token
  
#
volumes:
- name: local-storage
  persistentVolumeClaim:
    claimName: openebs-jiva-csi-pvc
- name: kube-api-access-9s76w
  projected:
    defaultMode: 420
    sources: #指定哪些卷投射进同一路径下
    - serviceAccountToken:
      expirationSeconds: 3607
      path: token
    - configMap:
      items:
      - key: ca.crt
        path: ca.crt
      name: kube-root-ca.crt
    - downwardAPI:
      items:
      - fieldRef:
        apiVersion: v1
        fieldPath: metadata.namespace #内容
      path: namespace #以namespace文件名挂载

#示例: 修改pod文件
]#vim pod-use-projected.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod-use-projected
  name: pod-use-projected
spec:
  containers:
  - image: ikubernetes/demoapp:v1.0
    name: pod-use-downwardapi
    volumeMounts:
    - name: proj
      mountPath: /proj
  volumes:
  - name: proj
    projected:
      defaultMode: 0644
      sources:
      - configMap:
          items:
          - key: myserver.conf
            path: my.conf #换个名字
          name: nginx-config-files
      - secret:
          items:
          - key: tls.crt
            path: nginx.crt #换个名字
          name: nginx-ssl-secret
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace #内容
            path: namespace #以namespace文件名挂载
]#kubectl apply -f pod-use-projected.yaml
#进入容器
]#kubectl exec -it pod-use-projected -- /bin/sh
]#ls /proj
]#my.conf namespace nginx.crt

总结:

为Pod提供配置:
    ConfigMap、Secret
        API Server支持资源类型:需要先定义出资源对象,而后引用
                       
    downwardAPI
        非为资源类型,可直接引用,因为它们自身即为Pod属性
            fieldRef 
            resourceFieldRef
     
    Projected
        非为资源类型,但其要引用现有的configmap、secret资源对象,或downwardAPI中的元数据信息
        投射进同一个挂载点

 

posted @ 2024-11-24 12:40  战斗小人  阅读(213)  评论(0编辑  收藏  举报