2025,每天10分钟,跟我学K8S(三十一)- 对象属性 - Volume - hostPath

2025,每天10分钟,跟我学K8S(三十一)- 对象属性 - Volume - hostPath-CSDN博客

        hostPath,顾名思义,就是将主机的目录挂载到pod里面,这样可以将pod里面产生的数据永久保留到主机的磁盘里面,也可以反过来将主机中的文件共享到pod中,例如可以将主机中的hosts文件挂载到多个pod,每次只需要修改主机的hosts文件即可。

        上面说的他的几个好处,坏处当然也是有不少,比如多个pod共享同一个hostpath,如果这些pod同时产生数据写入,有可能爆发数据冲突,同时pod产生的数据并不会随着pod删除而消失,会积累在主机的磁盘越来越大,浪费主机性能。

一、适用场景:

  • 访问节点资源:如读取节点日志(/var/log)、硬件信息(/sys
  • 开发调试:临时挂载配置文件或工具到容器。
  • 特殊需求:需要直接操作节点文件系统的场景(如自定义设备驱动)。

 

二、配置示例

1. 基础配置

创建一个nginx的容器,并且将主机的/var/log 目录挂载到pod内部。

yaml文件演示

 
  1.  
    apiVersion: v1
  2.  
    kind: Pod
  3.  
    metadata:
  4.  
    name: hostpath-demo
  5.  
    spec:
  6.  
    containers:
  7.  
    - name: nginx
  8.  
    image: m.daocloud.io/docker.io/nginx
  9.  
    command: ["sh", "-c", "tail -f /dev/null"]
  10.  
    volumeMounts:
  11.  
    - name: node-logs
  12.  
    mountPath: /host-logs
  13.  
    volumes:
  14.  
    - name: node-logs
  15.  
    hostPath:
  16.  
    path: /var/log # 节点上的路径
  17.  
    type: DirectoryOrCreate # 路径类型(见下文说明)
 

2. 路径类型(type 字段)​

类型 说明
Directory 路径必须为已存在的目录,否则 Pod 启动失败
DirectoryOrCreate 路径不存在时自动创建目录(权限默认为 0755,属主为 kubelet)
File 路径必须为已存在的文件,否则 Pod 启动失败
FileOrCreate 路径不存在时自动创建空文件(权限 0644,属主为 kubelet)
Socket 路径必须为已存在的 Unix 套接字
CharDevice 路径必须为已存在的字符设备
BlockDevice 路径必须为已存在的块设备

3. 结果验证

三、典型使用场景

1. 收集节点日志

启动一个日志收集的pod,共享节点的/var/log,并且将这个目录进行收集

 
  1.  
    volumes:
  2.  
    - name: node-log
  3.  
    hostPath:
  4.  
    path: /var/log
  5.  
    type: Directory
 
  • 用途:Sidecar 容器读取节点日志并上传到日志系统(如 ELK)。

2.  硬件监控

启动一个监控的pod,共享节点的/sys,并且将这个目录下的指标进行收集

 
  1.  
    volumes:
  2.  
    - name: sys-dir
  3.  
    hostPath:
  4.  
    path: /sys
  5.  
    type: Directory
 
  • 用途:读取硬件指标(如温度传感器数据)。

​四、与 emptyDir 的对比

特性 hostPath emptyDir
数据持久性 与节点本地存储一致 Pod 删除后数据丢失
共享范围 同一节点的所有 Pod 仅同一 Pod 内的容器
典型用途 节点级数据访问 临时数据交换
安全风险 高(需严格限制路径)

2025,每天10分钟,跟我学K8S(三十二)- 对象属性 - Volume - PV PVC-CSDN博客

        前面我们讲解了 hostPath 或者 emptyDir 的方式来持久化数据,但是他们也有各自的缺点,是否有更加可靠的存储来保存应用的持久化数据,这样容器在重建后,依然可以使用之前的数据?而且显示情况会出现存储资源和 CPU 资源以及内存资源有很大不同,为了屏蔽底层的技术实现细节,让用户更加方便的使用,Kubernetes 便引入了 PV 和 PVC 两个重要的资源对象来实现对存储的管理。这也是本章节需要和大家讲解的核心:PV 和 PVC。

一、什么是PV/PVC?

1. PersistentVolume (PV)

        PV 是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。

2. PersistentVolumeClaim (PVC)

        PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

3. PV 与 PVC 的关系

 
  1.  
    Admin[管理员创建 PV/StorageClass] --> PV
  2.  
    User[用户创建 PVC] -->|匹配条件| PVC
  3.  
    PVC -->|动态绑定| PV((动态生成的 PV))
  4.  
    Pod -->|挂载| PVC
 

二、配置示例

为了演示方便,采用 NFS 这种存储资源作为后端存储,在k8s-node01(172.21.176.4)这个节点上安装NFS

需要注意的是,虽然只是在k8s-node01一台服务器上挂载NFS,但是所有的节点都是需要安装NFS服务的。也就是需要(apt-get install nfs-kernel-server)

 
  1.  
    # 安装 NFS 服务端 这一步需要所有服务器运行
  2.  
    sudo apt-get install nfs-kernel-server
  3.  
     
  4.  
    # 创建共享目录
  5.  
    sudo mkdir -p /data/nfs_share
  6.  
    sudo chmod 777 /data/nfs_share
  7.  
     
  8.  
    # 配置导出规则(/etc/exports)
  9.  
    echo "/data/nfs_share *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
  10.  
     
  11.  
    # 应用配置
  12.  
    sudo exportfs -a
  13.  
    sudo systemctl restart nfs-kernel-server
 

1. 静态供给示例​

创建 PV

 
  1.  
    apiVersion: v1
  2.  
    kind: PersistentVolume
  3.  
    metadata:
  4.  
    name: nfs-pv
  5.  
    spec:
  6.  
    capacity:
  7.  
    storage: 10Gi
  8.  
    accessModes:
  9.  
    - ReadWriteMany
  10.  
    storageClassName: nfs
  11.  
    persistentVolumeReclaimPolicy: Retain
  12.  
    nfs:
  13.  
    path: /data/nfs_share
  14.  
    server: 172.21.176.4
  15.  
    readOnly: false
 

创建 PVC

 
  1.  
    apiVersion: v1
  2.  
    kind: PersistentVolumeClaim
  3.  
    metadata:
  4.  
    name: nfs-pvc
  5.  
    spec:
  6.  
    storageClassName: nfs
  7.  
    accessModes:
  8.  
    - ReadWriteMany
  9.  
    resources:
  10.  
    requests:
  11.  
    storage: 5Gi
 

Pod 挂载 PVC

 
  1.  
    apiVersion: v1
  2.  
    kind: Pod
  3.  
    metadata:
  4.  
    name: web-server
  5.  
    spec:
  6.  
    containers:
  7.  
    - name: nginx
  8.  
    image: m.daocloud.io/docker.io/nginx
  9.  
    volumeMounts:
  10.  
    - name: data
  11.  
    mountPath: /usr/share/nginx/html
  12.  
    volumes:
  13.  
    - name: data
  14.  
    persistentVolumeClaim:
  15.  
    claimName: nfs-pvc
 

查看演示结果​:

① 创建pv

② 创建pvc

③ 创建pod挂载pvc

④ 查看pv,pvc 这里面包含一些pv,pvc的属性参数具体查看下文

⑤ 查看创建成功的pod

三、关键配置参数

1. PV 配置参数

参数 说明
capacity.storage 存储容量(如 10Gi

访问模式

accessModes

ReadWriteOnce:

 RWO 存储卷可被单个节点上的一个 Pod ​以读写模式挂载单Pod独占读写(如数据库)

ReadOnlyMany:

 ROX 存储卷可被多个节点上的多个 Pod ​以只读模式挂载多 Pod 共享静态数据(如配置文件)

ReadWriteMany:

  RWX 存储卷可被多个节点上的多个 Pod ​以读写模式挂载    多 Pod 并发读写(如日志共享目录)

回收策略

persistentVolumeReclaimPolicy

 

Retain(保留数据)

  保留 PV 和底层存储数据,需手动清理。PV 状态变为 Released,不可被新 PVC 复用(如数据库)

Delete(删除数据)

  随着pod的删除而自动删除 PV 对象及底层存储资源(如云存储卷、磁盘)

Recycle(新版本废弃)
storageClassName 关联的 StorageClass 名称
volumeMode 存储类型:Filesystem(文件系统)、Block(块设备)

2. PVC 配置参数

参数 说明
resources.requests.storage 请求的存储容量
accessModes 必须与 PV 的访问模式兼容,具体pvc参数讲解
storageClassName 指定动态供给时使用的 StorageClass
selector 筛选符合条件的 PV(如匹配标签)

四、其他类型的后端

上面举例是最常用的NFS类型,除了NFS以外,pv/pvc还支持多种类型的后端卷,例如云存储(各大平台云盘、文件存储 NAS、对象存储 OSS等)、分布式存储(Ceph、GlusterFS)等,操作都大同小异,这里不单独举例。

 

 

        上一章节学习了K8S中PV/PVC,这种创建卷的方式给我们带来了不少好处,例如持久化,共享卷等,但是最大的问题就是它是静态的。什么意思?就是我们每次想使用一个卷的时候,先要创建pv,然后声明pvc,最后才能在pod里面去使用这个卷。少的情况下还好,万一生产环境里面有成1000个pod都需要用到卷存储,那岂不是要先创建1000个PV?删除pod后不是还要删除1000次PV?能不能省略掉创建和删除的步骤?

        这种情况下我们就需要用到动态 PV,也就是我们今天要讲解的 StorageClass。


​一、概念与作用

      StorageClass(存储类)​ 是 Kubernetes 中用于动态创建和管理 ​PersistentVolume(PV)​ 的核心资源对象。它解决了传统静态存储分配的低效问题,通过定义存储策略(如存储类型、性能等级、回收规则等),实现按需自动化创建 PV,并与 ​PersistentVolumeClaim(PVC)​ 绑定。

核心作用:

​动态供应存储:根据 PVC 请求自动创建匹配的 PV,无需管理员手动干预。
​抽象存储细节:用户无需关心底层存储实现(如 AWS EBS、NFS、Ceph 等),只需声明存储需求。
​支持多存储后端:通过不同的 provisioner 字段对接多种存储系统,如云存储、分布式存储等。

一个完整的创建过程(NFS作为后端)

前提所有的服务器安装NFS服务端,这个上一章节之前有操作过,这里不再复述。

1. NFS Provisioner 部署(含 RBAC 权限)​

 
  1.  
    # rbac.yaml
  2.  
    # ServiceAccount 权限
  3.  
    apiVersion: v1
  4.  
    kind: ServiceAccount
  5.  
    metadata:
  6.  
    name: nfs-provisioner
  7.  
    namespace: default
  8.  
    ---
  9.  
    apiVersion: rbac.authorization.k8s.io/v1
  10.  
    kind: ClusterRole
  11.  
    metadata:
  12.  
    name: nfs-provisioner-runner
  13.  
    rules:
  14.  
    - apiGroups: [""]
  15.  
    resources: ["endpoints"]
  16.  
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  17.  
    - apiGroups: [""]
  18.  
    resources: ["persistentvolumes"]
  19.  
    verbs: ["get", "list", "watch", "create", "delete"]
  20.  
    - apiGroups: [""]
  21.  
    resources: ["persistentvolumeclaims"]
  22.  
    verbs: ["get", "list", "watch", "update"]
  23.  
    - apiGroups: ["storage.k8s.io"]
  24.  
    resources: ["storageclasses"]
  25.  
    verbs: ["get", "list", "watch"]
  26.  
    ---
  27.  
    apiVersion: rbac.authorization.k8s.io/v1
  28.  
    kind: ClusterRoleBinding
  29.  
    metadata:
  30.  
    name: run-nfs-provisioner
  31.  
    subjects:
  32.  
    - kind: ServiceAccount
  33.  
    name: nfs-provisioner
  34.  
    namespace: default
  35.  
    roleRef:
  36.  
    kind: ClusterRole
  37.  
    name: nfs-provisioner-runner
  38.  
    apiGroup: rbac.authorization.k8s.io
 

上面​是一个RBAC的创建过程,后面会有具体章节进行讲解,这里只做简单的说明。总共分为3部分。

 
  1.  
    1.创建一个SA,名为nfs-provisioner
  2.  
     
  3.  
    2.创建一个ClusterRole,名为nfs-provisioner-role,他有以下权限
  4.  
     
  5.  
      对resources: ["endpoints"] 拥有["get", "list", "watch", "create", "update", "patch"]的权限
  6.  
      对resources: ["persistentvolumes"] 拥有["get", "list", "watch", "create", "delete"]的权限
  7.  
      对resources: ["persistentvolumeclaims"]用有["get", "list", "watch", "update"]的权限
  8.  
      对resources: ["storageclasses"]拥有["get", "list", "watch"]的权限
  9.  
     
  10.  
    3.创建一个ClusterRoleBinding,名为nfs-provisioner-binding,它将nfs-provisioner这个SA绑定到nfs-provisioner-role的权限上。
 

 

2. NFS Provisioner 控制器

由于原生 NFS 不支持动态卷分配,需使用 nfs-subdir-external-provisioner 实现动态 PV 创建。

 
  1.  
    # nfs-provisioner.yaml
  2.  
    apiVersion: apps/v1
  3.  
    kind: Deployment
  4.  
    metadata:
  5.  
    name: nfs-provisioner
  6.  
    namespace: default
  7.  
    spec:
  8.  
    replicas: 1
  9.  
    selector:
  10.  
    matchLabels:
  11.  
    app: nfs-provisioner
  12.  
    strategy:
  13.  
    type: Recreate
  14.  
    template:
  15.  
    metadata:
  16.  
    labels:
  17.  
    app: nfs-provisioner
  18.  
    spec:
  19.  
    serviceAccount: nfs-provisioner
  20.  
    containers:
  21.  
    - name: nfs-provisioner
  22.  
    image: k8s.m.daocloud.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
  23.  
    volumeMounts:
  24.  
    - name: nfs-client-root
  25.  
    mountPath: /persistentvolumes
  26.  
    env:
  27.  
    - name: PROVISIONER_NAME
  28.  
    value: k8s-sigs.io/nfs-subdir-external-provisioner # 注意这里的值要和StorageClass里面的provisioner: nfs-provisioner保持一致
  29.  
    - name: NFS_SERVER
  30.  
    value: 172.21.176.4 # 替换为你的NFS服务器IP
  31.  
    - name: NFS_PATH
  32.  
    value: /data/nfs_share # 替换为NFS共享路径
  33.  
    volumes:
  34.  
    - name: nfs-client-root
  35.  
    nfs:
  36.  
    server: 172.21.176.4 # 同上
  37.  
    path: /data/nfs_share # 同上
 

3. StorageClass 定义

 
  1.  
    # storageclass.yaml
  2.  
    apiVersion: storage.k8s.io/v1
  3.  
    kind: StorageClass
  4.  
    metadata:
  5.  
    name: nfs-storage
  6.  
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 注意这里的值要和上面的里面的name: PROVISIONER_NAME 的值保持一致
  7.  
    parameters:
  8.  
    archiveOnDelete: "false" # 删除PVC时是否保留数据目录
  9.  
    reclaimPolicy: Delete # 或 Retain
 

4. PVC 申请存储

 
  1.  
    # pvc.yaml
  2.  
    apiVersion: v1
  3.  
    kind: PersistentVolumeClaim
  4.  
    metadata:
  5.  
    name: nfs-pvc
  6.  
    spec:
  7.  
    storageClassName: nfs-storage # 必须与StorageClass名称匹配
  8.  
    accessModes:
  9.  
    - ReadWriteMany
  10.  
    resources:
  11.  
    requests:
  12.  
    storage: 10Gi
 

5. Deployment 挂载 PVC

 
  1.  
    # deployment.yaml
  2.  
    apiVersion: apps/v1
  3.  
    kind: Deployment
  4.  
    metadata:
  5.  
    name: nfs-web-app
  6.  
    spec:
  7.  
    replicas: 2
  8.  
    selector:
  9.  
    matchLabels:
  10.  
    app: nfs-web
  11.  
    template:
  12.  
    metadata:
  13.  
    labels:
  14.  
    app: nfs-web
  15.  
    spec:
  16.  
    containers:
  17.  
    - name: web
  18.  
    image: m.daocloud.io/docker.io/nginx:alpine
  19.  
    volumeMounts:
  20.  
    - name: nfs-volume
  21.  
    mountPath: /usr/share/nginx/html
  22.  
    volumes:
  23.  
    - name: nfs-volume
  24.  
    persistentVolumeClaim:
  25.  
    claimName: nfs-pvc
 

二、部署流程说明

1. 部署 NFS 服务器

确保 /data/nfs 目录已通过 rw,sync,no_subtree_check 参数导出

上一章节已经在k8s-node01的服务器上面设置好了

 

2.​应用 RBAC 和 Provisioner

 
  1.  
    kubectl apply -f rbac.yaml
  2.  
    kubectl apply -f nfs-provisioner.yaml
  3.  
     
  4.  
    # 通过 # kubectl get pod 查看pod,如果有报错可以通过describe或者log来查看报错内容
  5.  
    NAME READY STATUS RESTARTS AGE
  6.  
    nfs-provisioner-d7cc848df-xspjz 1/1 Running 0 15m
 

 

3.创建 StorageClass

 
  1.  
    kubectl apply -f storageclass.yaml
  2.  
     
  3.  
     
  4.  
    # 通过下面命令查看是否创建成功
  5.  
    # kubectl get storageclasses.storage.k8s.io
  6.  
    NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
  7.  
    nfs-storage k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 47m
 

4.申请 PVC

 
  1.  
    kubectl apply -f pvc.yaml
  2.  
     
  3.  
     
  4.  
    # 通过命令得到pvc,此时应该是Bound 的状态,pv也自动创建成功
  5.  
    # kubectl get pvc,pv
  6.  
    NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
  7.  
    persistentvolumeclaim/nfs-pvc Bound pvc-fd38b271-06b1-497b-a2dc-dafe82d45d72 10Gi RWX nfs-storage <unset> 52m
  8.  
     
  9.  
    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
  10.  
    persistentvolume/pvc-fd38b271-06b1-497b-a2dc-dafe82d45d72 10Gi RWX Delete Bound default/nfs-pvc nfs-storage <unset> 16m
 

5.部署应用

 
  1.  
    kubectl apply -f deployment.yaml
  2.  
     
  3.  
    # 通过命令查看新创建的pod
  4.  
    # kubectl get pod
  5.  
    NAME READY STATUS RESTARTS AGE
  6.  
    nfs-provisioner-d7cc848df-xspjz 1/1 Running 0 17m
  7.  
    nfs-web-app-7b7cf4454-bhlrn 1/1 Running 0 41m
  8.  
    nfs-web-app-7b7cf4454-dktj8 1/1 Running 0 41m
 

 

三、验证数据持久化

1.进入任意 Pod 写入测试文件:

 
  1.  
    kubectl exec -it <pod-name> -- sh -c "echo 'Hello NFS' > /usr/share/nginx/html/test.txt"
  2.  
     
  3.  
    # kubectl exec -it nfs-web-app-7b7cf4454-bhlrn -- sh -c "echo 'Hello NFS' > /usr/share/nginx/html/test.txt"
 

2.删除 Pod 后重新进入另外一个 Pod查看:

 
  1.  
    kubectl exec -it <new-pod-name> -- cat /usr/share/nginx/html/test.txt # 应看到文件内容
  2.  
     
  3.  
    # kubectl exec -it nfs-web-app-7b7cf4454-dktj8 -- cat /usr/share/nginx/html/test.txt
  4.  
    Hello NFS
 

 四、典型应用场景对比

场景 静态 PV 动态 PV
开发测试环境 适合小型环境,存储需求稳定 不适用(可能资源浪费)
生产环境 需配合人工监控和扩容 适合弹性伸缩、自动化运维
多存储类型混合架构 需为每种存储单独配置 PV 通过 StorageClass 统一管理
云原生与微服务 兼容性差,扩展成本高 天然适配,支持跨云存储

 2025,每天10分钟,跟我学K8S(三十四)- 对象属性 - Volume - Longhorn _longhron nfs-CSDN博客

 

        前面学习了动态PV,确实帮助我们省略了创建和删除的步骤,但还是觉得麻烦,先要创建RBAC,再创建NFS的客户端的pod,再创建pvc,最后才能应用到pod里面。能不能更简化一点?今天介绍一款软件 Longhorn 他来帮我们再减轻一些操作。

        可能提起Longhorn有些人不熟悉,但是他的出厂公司Rancher则大大有名。帮助了不少同学来学习K8S。Longhorn是一个轻量级且功能强大的云原生Kubernetes分布式存储平台,可以在任意基础设施上运行。

        官网地址:Longhorn | 强大的云原生Kubernetes储存平台 | RancherLonghorn 是由Rancher研发的容器存储解决方案,Longhorn 已作为沙箱(Sandbox)项目加入CNCF社区。Longhorn 提供了一种简单、轻量、极适用于容器和K8S的持久化存储解决方案,Longhorn 同时极大地简化了用户部署、使用和管理的工作。https://www.rancher.cn/products/longhorn/

        github地址:https://github.com/longhorn/longhornhttps://github.com/longhorn/longhorn

 

部署longhorn

1.安装插件

 
  1.  
    # CentOS/RHEL
  2.  
    yum install -y iscsi-initiator-utils
  3.  
    systemctl enable iscsid --now
  4.  
     
  5.  
    # Ubuntu/Debian
  6.  
    apt-get install -y open-iscsi
  7.  
    systemctl enable open-iscsi --now
  8.  
     
  9.  
    # 验证安装
  10.  
    which iscsiadm # 应输出:/usr/sbin/iscsiadm
 

 

2.下载yaml文件并修改

 
  1.  
    # 下载yaml文件 (202503月最新版)
  2.  
    # wget https://github.com/longhorn/longhorn/releases/download/v1.8.1/longhorn.yaml
  3.  
     
  4.  
     
  5.  
     
  6.  
     
  7.  
    # 修改标注内容,开放longhron-ui对外,方便访问管理
  8.  
    ---
  9.  
    kind: Service
  10.  
    apiVersion: v1
  11.  
    metadata:
  12.  
    labels:
  13.  
    app: longhorn-ui
  14.  
    name: longhorn-frontend
  15.  
    namespace: longhorn-system
  16.  
    spec:
  17.  
    type: NodePort #这里改为nodeport
  18.  
    selector:
  19.  
    app: longhorn-ui
  20.  
    ports:
  21.  
    - name: http
  22.  
    port: 80
  23.  
    targetPort: http
  24.  
    nodePort: 30080 #修改nodeport对外端口
  25.  
    ---
  26.  
     
  27.  
     
  28.  
     
  29.  
    # 修改镜像地址1
  30.  
    # cat longhorn.yaml |grep "image:"
  31.  
    image: longhornio/longhorn-manager:master-head
  32.  
    image: longhornio/longhorn-share-manager:master-head
  33.  
    image: longhornio/longhorn-manager:master-head
  34.  
    image: longhornio/longhorn-manager:master-head
  35.  
    image: longhornio/longhorn-ui:master-head
  36.  
    修改为
  37.  
     
  38.  
    image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
  39.  
    image: m.daocloud.io/docker.io/longhornio/longhorn-share-manager:master-head
  40.  
    image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
  41.  
    image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
  42.  
    image: m.daocloud.io/docker.io/longhornio/longhorn-ui:master-head
  43.  
     
  44.  
     
  45.  
    # 修改镜像地址2
  46.  
    command:
  47.  
    - longhorn-manager
  48.  
    - -d
  49.  
    - daemon
  50.  
    - --engine-image
  51.  
    - "longhornio/longhorn-engine:v1.8.1"
  52.  
    - --instance-manager-image
  53.  
    - "longhornio/longhorn-instance-manager:v1.8.1"
  54.  
    - --share-manager-image
  55.  
    - "longhornio/longhorn-share-manager:v1.8.1"
  56.  
    - --backing-image-manager-image
  57.  
    - "longhornio/backing-image-manager:v1.8.1"
  58.  
    - --support-bundle-manager-image
  59.  
    - "longhornio/support-bundle-kit:v0.0.52"
  60.  
    - --manager-image
  61.  
    - "longhornio/longhorn-manager:v1.8.1"
  62.  
     
  63.  
    修改为
  64.  
    command:
  65.  
    - longhorn-manager
  66.  
    - -d
  67.  
    - daemon
  68.  
    - --engine-image
  69.  
    - "m.daocloud.io/docker.io/longhornio/longhorn-engine:v1.8.1"
  70.  
    - --instance-manager-image
  71.  
    - "m.daocloud.io/docker.io/longhornio/longhorn-instance-manager:v1.8.1"
  72.  
    - --share-manager-image
  73.  
    - "m.daocloud.io/docker.io/longhornio/longhorn-share-manager:v1.8.1"
  74.  
    - --backing-image-manager-image
  75.  
    - "m.daocloud.io/docker.io/longhornio/backing-image-manager:v1.8.1"
  76.  
    - --support-bundle-manager-image
  77.  
    - "m.daocloud.io/docker.io/longhornio/support-bundle-kit:v0.0.52"
  78.  
    - --manager-image
  79.  
    - "m.daocloud.io/docker.io/longhornio/longhorn-manager:v1.8.1"
  80.  
     
  81.  
     
  82.  
    # 修改镜像地址3
  83.  
    - name: CSI_ATTACHER_IMAGE
  84.  
    value: "longhornio/csi-attacher:v4.8.1"
  85.  
    - name: CSI_PROVISIONER_IMAGE
  86.  
    value: "longhornio/csi-provisioner:v5.2.0"
  87.  
    - name: CSI_NODE_DRIVER_REGISTRAR_IMAGE
  88.  
    value: "longhornio/csi-node-driver-registrar:v2.13.0"
  89.  
    - name: CSI_RESIZER_IMAGE
  90.  
    value: "longhornio/csi-resizer:v1.13.2"
  91.  
    - name: CSI_SNAPSHOTTER_IMAGE
  92.  
    value: "longhornio/csi-snapshotter:v8.2.0"
  93.  
    - name: CSI_LIVENESS_PROBE_IMAGE
  94.  
    value: "longhornio/livenessprobe:v2.15.0"
  95.  
    修改为
  96.  
    - name: CSI_ATTACHER_IMAGE
  97.  
    value: "m.daocloud.io/docker.io/longhornio/csi-attacher:v4.8.1"
  98.  
    - name: CSI_PROVISIONER_IMAGE
  99.  
    value: "m.daocloud.io/docker.io/longhornio/csi-provisioner:v5.2.0"
  100.  
    - name: CSI_NODE_DRIVER_REGISTRAR_IMAGE
  101.  
    value: "m.daocloud.io/docker.io/longhornio/csi-node-driver-registrar:v2.13.0"
  102.  
    - name: CSI_RESIZER_IMAGE
  103.  
    value: "m.daocloud.io/docker.io/longhornio/csi-resizer:v1.13.2"
  104.  
    - name: CSI_SNAPSHOTTER_IMAGE
  105.  
    value: "m.daocloud.io/docker.io/longhornio/csi-snapshotter:v8.2.0"
  106.  
    - name: CSI_LIVENESS_PROBE_IMAGE
  107.  
    value: "m.daocloud.io/docker.io/longhornio/livenessprobe:v2.15.0"
 

2.应用yaml文件

可以看到创建了一个 longhorn-system 的namespace和一大堆的资源

如果使用的是VMware虚拟机,可能会有个报错

 
  1.  
    # journalctl -u multipathd -f
  2.  
    -- Logs begin at Thu 2025-02-06 18:06:45 CST. --
  3.  
    Mar 28 18:02:54 k8s-master multipathd[741]: sda: failed to get sysfs uid: Invalid argument
  4.  
    Mar 28 18:02:54 k8s-master multipathd[741]: sda: failed to get sgio uid: No such file or directory
  5.  
    Mar 28 18:02:59 k8s-master multipathd[741]: sda: add missing path
  6.  
    Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get udev uid: Invalid argument
  7.  
    Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get sysfs uid: Invalid argument
  8.  
    Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get sgio uid: No such file or directory
  9.  
    Mar 28 18:03:04 k8s-master multipathd[741]: sda: add missing path
  10.  
     
  11.  
     
  12.  
    # 解决办法 编辑配置文件
  13.  
    sudo vi /etc/multipath.conf
  14.  
     
  15.  
    # 添加以下内容
  16.  
    blacklist {
  17.  
    devnode "^sda"
  18.  
    }
 

3.验证longhorn

pod验证

如果所有pod都正常启动,正常显示应该如下图,如果发现只在部分节点运行,则查看是否有污染的情况

# kubectl describe nodes <node> | grep Taint

 

 

web页面验证

masterIP:30080  记得这里是开启了NodePort,需要做好安全策略,以防入侵

下图可知目前创建了0个卷,2个节点,合计有38G的可用空间。

 

注意:

  • longhorn是分布式块存储,与分布式文件系统不同(mfs,lizardfs),不同超过pv设置的存储大小
  • 使用dd命令测试(bs=1m,count=1024或者bs=500k,count=2048),发现longhorn的存储性能不及本地磁盘
  • longhorn性能要远超nfs-client-provisioner提供的存储性能(2-3倍)

 

 

举例验证

        在日常使用中,运行数据库的Pod,如果发生故障,相关业务也无法继续,这时你会失去客户、失去订单。在这里,就以一个mysql的pod举例,为它配置一个新的Longhorn持久卷

 

1.创建pvc.yaml

 
  1.  
    apiVersion: v1
  2.  
    kind: PersistentVolumeClaim
  3.  
    metadata:
  4.  
    name: mysql-pv-claim
  5.  
    labels:
  6.  
    type: longhorn
  7.  
    app: example
  8.  
    spec:
  9.  
    storageClassName: longhorn #类型为longhorn
  10.  
    accessModes:
  11.  
    - ReadWriteOnce
  12.  
    resources:
  13.  
    requests:
  14.  
    storage: 5Gi
 

2.创建一个mysql.yaml

 
  1.  
    apiVersion: apps/v1
  2.  
    kind: Deployment
  3.  
    metadata:
  4.  
    name: my-mysql
  5.  
    labels:
  6.  
    app: example
  7.  
    spec:
  8.  
    selector:
  9.  
    matchLabels:
  10.  
    app: example
  11.  
    tier: mysql
  12.  
    strategy:
  13.  
    type: Recreate
  14.  
    template:
  15.  
    metadata:
  16.  
    labels:
  17.  
    app: example
  18.  
    tier: mysql
  19.  
    spec:
  20.  
    containers:
  21.  
    - image: m.daocloud.io/docker.io/mysql:5.6
  22.  
    name: mysql
  23.  
    env:
  24.  
    - name: MYSQL_ROOT_PASSWORD
  25.  
    value: password
  26.  
    ports:
  27.  
    - containerPort: 3306
  28.  
    name: mysql
  29.  
    volumeMounts:
  30.  
    - name: mysql-persistent-storage
  31.  
    mountPath: /var/lib/mysql
  32.  
    volumes:
  33.  
    - name: mysql-persistent-storage
  34.  
    persistentVolumeClaim:
  35.  
    claimName: mysql-pv-claim #对应pvc的名字
 

应用后查看pod,pv,pvc

通过下图可以看到,pvc已经绑定成功

mysql写入数据后,删除pod

 
  1.  
    root@k8s-master:~/longhorn# kubectl exec -it my-mysql-7f8f897d85-4zmpx -- /bin/bash
  2.  
    root@my-mysql-7f8f897d85-4zmpx:/# mysql -u root -p mysql
  3.  
    Enter password: #密码为yaml文件中设置的password
  4.  
    Reading table information for completion of table and column names
  5.  
    You can turn off this feature to get a quicker startup with -A
  6.  
     
  7.  
    Welcome to the MySQL monitor. Commands end with ; or \g.
  8.  
    Your MySQL connection id is 1
  9.  
    Server version: 5.6.51 MySQL Community Server (GPL)
  10.  
     
  11.  
    Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
  12.  
     
  13.  
    Oracle is a registered trademark of Oracle Corporation and/or its
  14.  
    affiliates. Other names may be trademarks of their respective
  15.  
    owners.
  16.  
     
  17.  
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  18.  
     
  19.  
    mysql> create database k8s; #创建一个K8s的数据库
  20.  
    Query OK, 1 row affected (0.00 sec)
  21.  
     
  22.  
    mysql> exit
  23.  
    Bye
  24.  
    root@my-mysql-7f8f897d85-4zmpx:/# exit
  25.  
    exit
 

删除这个mysql pod

 
  1.  
    root@k8s-master:~/longhorn# kubectl delete pod my-mysql-7f8f897d85-4zmpx
  2.  
    pod "my-mysql-7f8f897d85-4zmpx" deleted
 

大约一分钟之后,我们将再次寻找新的容器名称,连接到该容器名称,看看我们的数据库是否仍然存在,发现新的pod依然使用了之前的存储卷,并且数据还在。

 
  1.  
    root@k8s-master:~/longhorn# kubectl get pods | grep mysql
  2.  
    my-mysql-7f8f897d85-hkrp9 1/1 Running 0 27s
  3.  
    root@k8s-master:~/longhorn# kubectl exec -it my-mysql-7f8f897d85-hkrp9 -- /bin/bash
  4.  
    root@my-mysql-7f8f897d85-hkrp9:/# mysql -u root -p mysql
  5.  
    Enter password:
  6.  
    Reading table information for completion of table and column names
  7.  
    You can turn off this feature to get a quicker startup with -A
  8.  
     
  9.  
    Welcome to the MySQL monitor. Commands end with ; or \g.
  10.  
    Your MySQL connection id is 1
  11.  
    Server version: 5.6.51 MySQL Community Server (GPL)
  12.  
     
  13.  
    Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
  14.  
     
  15.  
    Oracle is a registered trademark of Oracle Corporation and/or its
  16.  
    affiliates. Other names may be trademarks of their respective
  17.  
    owners.
  18.  
     
  19.  
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  20.  
     
  21.  
    mysql> show databases;
  22.  
    +---------------------+
  23.  
    | Database |
  24.  
    +---------------------+
  25.  
    | information_schema |
  26.  
    | k8s |
  27.  
    | #mysql50#lost+found |
  28.  
    | mysql |
  29.  
    | performance_schema |
  30.  
    +---------------------+
  31.  
    5 rows in set (0.00 sec)
  32.  
     
  33.  
    mysql>
 

 

卸载longhorn

参考官网文档

Longhorn | Documentationhttps://longhorn.io/docs/1.8.1/deploy/uninstall/#uninstalling-longhorn-using-kubectl具体步骤如下,记得切换版本号,保持和安装的版本一致

Uninstalling Longhorn using kubectl

  1. Create the uninstallation job to clean up CRDs from the system and wait for success:

     
    1.  
      kubectl create -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/uninstall/uninstall.yaml
    2.  
      kubectl get job/longhorn-uninstall -n longhorn-system -w
     

    Example output:

     
    1.  
      $ kubectl create -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/uninstall/uninstall.yaml
    2.  
      serviceaccount/longhorn-uninstall-service-account created
    3.  
      clusterrole.rbac.authorization.k8s.io/longhorn-uninstall-role created
    4.  
      clusterrolebinding.rbac.authorization.k8s.io/longhorn-uninstall-bind created
    5.  
      job.batch/longhorn-uninstall created
    6.  
       
    7.  
      $ kubectl get job/longhorn-uninstall -n longhorn-system -w
    8.  
      NAME COMPLETIONS DURATION AGE
    9.  
      longhorn-uninstall 0/1 3s 3s
    10.  
      longhorn-uninstall 1/1 20s 20s
     
  2. Remove remaining components:

     
    1.  
      kubectl delete -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/deploy/longhorn.yaml
    2.  
      kubectl delete -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/uninstall/uninstall.yaml
     

总结

        在安装了longhorn之后,我们就不需要关心底层实现是什么和实现的过程,只需要创建pvc+pod开箱即用,大大方便我们再k8s中使用存储。

以下是通过deepseek生成的 PV、StorageClass 和 Longhorn 的核心区别对比,结合 Kubernetes 存储架构与 Longhorn 的特性整理:

区别对照表:

维度 PV (PersistentVolume) StorageClass Longhorn
定位 集群级别的存储资源实体,如 NFS 卷、云盘等 存储策略模板,用于动态生成 PV 云原生分布式块存储系统,提供存储后端实现
核心功能 代表实际存储空间,与底层存储系统绑定 定义动态 PV 的创建规则(如存储类型、副本策略) 实现分布式块存储,支持快照、备份、跨集群容灾等
创建方式 管理员手动创建(静态供应) 管理员定义模板(如 provisioner 和参数) 通过 Helm 或 YAML 部署,集成到 Kubernetes 集群
生命周期 独立于 Pod,可被多个 PVC 绑定(需回收策略支持) 长期存在,用于动态生成 PV 与 Kubernetes 集群共存,通过 Operator 管理存储资源
动态供应 不支持,需预先创建 核心动态供应机制,调用存储插件(如 Longhorn)自动生成 PV 作为 StorageClass 的 provisioner,提供动态 PV 创建能力
访问模式 支持 ReadWriteOnceReadOnlyManyReadWriteMany 通过参数定义 PV 的默认访问模式 支持 RWO 和 RWX(需 NFS 或 CSI 插件)
多租户隔离 无原生隔离,依赖存储系统实现 通过不同 StorageClass 隔离存储策略(如 SSD/HDD) 提供多副本隔离,支持跨节点调度(如 nodeSelector
典型使用场景 静态分配存储资源(如固定大小的云盘) 自动化按需分配存储(如开发环境快速创建卷) 分布式有状态应用(如 MySQL 集群)、跨集群灾备
与 Kubernetes 的集成 通过 PVC 绑定使用,需手动维护 通过 provisioner 字段关联存储插件(如 driver.longhorn.io 提供 CSI 驱动,与 StorageClass 协同实现动态存储供应
高可用机制 依赖底层存储的高可用(如云盘冗余) 无直接高可用功能,依赖存储后端实现 通过多副本(3 副本默认)和分布式控制器实现跨节点容灾

关键差异总结:

1.​抽象层级 

  • PV 是具体的存储资源实体,属于静态资源;StorageClass 是动态资源模板;Longhorn 是底层存储系统的实现。
  • 三者关系:StorageClass 动态生成 PV → PVC 绑定 PV → Longhorn 提供底层存储支持。

2.运维复杂度

  • PV 需手动维护,适合固定规模场景;StorageClass 通过自动化降低运维成本;Longhorn 提供完整的存储管理界面和运维工具。

3.功能扩展性

  • Longhorn 支持高级功能(如增量快照、跨集群备份),而原生 PV/StorageClass 需依赖存储插件实现。

4.生产建议

  • 静态场景:直接使用 PV + PVC;
  • 动态场景:优先采用 StorageClass + Longhorn 组合,实现弹性扩展和高可用。

2025,每天10分钟,跟我学K8S(三十五)- 对象属性 - Volume - ConfigMap_spring cloud kubernetes 读取configmap时是键值对,如何转换成对象注入-CSDN博客

        前面学习了Volume的多种类型对象,本章将再讲解一种特殊的资源对象:ConfigMap。

  日常许多应用经常会有从配置文件、命令行参数或者环境变量中读取一些配置信息,这些配置信息我们肯定不会直接写死到应用程序中去的,例如有个应用连接redis服务,那redis做了迁移或者修改了密码,这时候还得重新去修改代码,重新制作一个镜像,这肯定是不可取的,而ConfigMap就是来解决这种情况的。

        ConfigMap 是 Kubernetes 中用于存储非敏感配置数据的资源对象,通过键值对(Key-Value)形式保存配置信息,支持纯文本、JSON、XML 等多种格式

ConfigMap的功能特性:

其主要功能包括:

  • 配置解耦:将应用配置与容器镜像分离,便于独立管理。
  • 灵活注入:支持通过环境变量、命令行参数或文件挂载方式注入配置到容器。
  • 动态更新:修改 ConfigMap 后,挂载为文件的配置可自动更新(需约 30 秒至 1 分钟),而环境变量需重启 Pod。

特性

  • 命名空间级别:仅作用于同一命名空间内的资源。
  • 大小限制:单个 ConfigMap 数据总量不超过 1 MiB。
  • 键名规范:键名仅允许字母、数字、-_ 或 .,且 data 与 binaryData 字段的键名不可重复。

1.举例说明

创建configmap

configmap的格式

 
  1.  
    kind: ConfigMap
  2.  
    apiVersion: v1
  3.  
    metadata:
  4.  
    name: cm-demo
  5.  
    namespace: default
  6.  
    data:
  7.  
    key1: value1 #单行配置文件内容1
  8.  
    key2: value2 #单行配置文件内容2
  9.  
    config.properties: | # 多行配置文件内容3
  10.  
    db.host=127.0.0.1
  11.  
    db.port=3306
 

1.通过命令行创建configmap

通过kubectl create configmap -h 的方式获取提示

 
  1.  
    Examples:
  2.  
    # Create a new config map named my-config based on folder bar
  3.  
    kubectl create configmap my-config --from-file=path/to/bar
  4.  
     
  5.  
    # Create a new config map named my-config with specified keys instead of file basenames on disk
  6.  
    kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
  7.  
     
  8.  
    # Create a new config map named my-config with key1=config1 and key2=config2
  9.  
    kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
  10.  
     
  11.  
    # Create a new config map named my-config from the key=value pairs in the file
  12.  
    kubectl create configmap my-config --from-file=path/to/bar
  13.  
     
  14.  
    # Create a new config map named my-config from an env file
  15.  
    kubectl create configmap my-config --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env
 

官方一共给了5个例子

1.创建一个名为my-config的configmap,将目录 bar 下的所有文件创建为 ConfigMap,每个文件对应一个键值对,

:文件名(如 file1.txt)​

:文件内容(如 file1.txt 的文本)

使用场景:批量挂载配置文件到容器,例如存放 Nginx 的多个虚拟主机配置

 

2.创建一个名为my-config的configmap,源文件地址为/path/to/bar/file1.txt和/path/to/bar/file2.txt

key1 和 key2(覆盖默认的文件名)

:对应文件的内容
场景:需要显式控制键名时使用,例如将多个文件映射为统一命名的配置项

 

3. 创建一个名为my-config的configmap,将目录 bar 下的所有文件创建为 ConfigMap,直接在命令行中定义键值对

key1key2

config1config2
场景:快速注入简单配置(如数据库地址、日志级别)

 

4. 同1

 

5.创建一个名为my-config的configmap,直接从外部文件(.env)内容挂载到configmap中解析 .env 文件中的键值对,合并到 ConfigMap:

.env 文件中的变量名(如 DB_HOST

:对应的变量值(如 127.0.0.1
场景:兼容传统环境变量配置方式,支持多文件合并。

 

看不懂没关系,下面有更简单的yaml格式方式来创建。

 

2.通过yaml文件创建configmap

下面例子里面一共创建了3个键值对,一个是多行配置,里面包含2个键值对,一个是单行配置文件,包含一个键值对,在使用过程中,都是将多行配置键值对通过文件的方式进行挂载,而单行直接通过环境变量的方式进行挂载

# 多行配置文件内容
    db.host=127.0.0.1
    db.port=3306

# 单行配置文件内容
  log.level: "info"      

 
  1.  
    # cat cm1.yaml
  2.  
     
  3.  
    apiVersion: v1
  4.  
    kind: ConfigMap
  5.  
    metadata:
  6.  
    name: app-config #这个configmap的名字,后面可以通过环境变量的方式挂载进入pod的yaml文件
  7.  
    data:
  8.  
    config.properties: | # 多行配置文件内容
  9.  
    db.host=127.0.0.1
  10.  
    db.port=3306
  11.  
    log.level: "info" # 单行键值对
 

创建pod识别configmap

1.环境变量的方式注入单行键值对

创建一个pod的yaml文件并且使用上面的cm变量

 
  1.  
    #cat pod1.yaml
  2.  
     
  3.  
    apiVersion: v1
  4.  
    kind: Pod
  5.  
    metadata:
  6.  
    name: app-pod
  7.  
    spec:
  8.  
    containers:
  9.  
    - name: app-container
  10.  
    image: m.daocloud.io/docker.io/nginx:latest
  11.  
    # 环境变量注入(可选,适用于单值配置)
  12.  
    env:
  13.  
    - name: LOG_LEVEL
  14.  
    valueFrom:
  15.  
    configMapKeyRef:
  16.  
    name: app-config
  17.  
    key: log.level
 

验证结果,得知$LOG_LEVEL已经注意到新的pod里面

 
  1.  
    root@k8s-master:~# kubectl get pod
  2.  
    NAME READY STATUS RESTARTS AGE
  3.  
    app-pod 1/1 Running 0 2m57s
  4.  
    testcm1-pod 0/1 CreateContainerConfigError 0 36m
  5.  
    root@k8s-master:~# kubectl exec -it app-pod -- /bin/bash
  6.  
    root@app-pod:/# echo $LOG_LEVEL
  7.  
    info
 

2.挂载配置文件的方式注入多行键值对

 
  1.  
    #cat pod2.yaml
  2.  
     
  3.  
    apiVersion: v1
  4.  
    kind: Pod
  5.  
    metadata:
  6.  
    name: app-pod
  7.  
    spec:
  8.  
    containers:
  9.  
    - name: app-container
  10.  
    image: m.daocloud.io/docker.io/nginx
  11.  
    volumeMounts:
  12.  
    - name: config-volume # 卷名称,需与 volumes 字段对应
  13.  
    mountPath: /etc/app-config # 容器内挂载路径
  14.  
    volumes:
  15.  
    - name: config-volume # 卷名称,与 volumeMounts 对应
  16.  
    configMap:
  17.  
    name: app-config # 引用的 ConfigMap 名称
  18.  
    items: # 可选:筛选并自定义文件名
  19.  
    - key: config.properties # 选择 ConfigMap 中的键
  20.  
    path: db.conf # 挂载为 /etc/app-config/db.conf
 

验证结果,发现db.conf已经挂载到指定目录

 
  1.  
    root@k8s-master:~/configmap# kubectl get pod
  2.  
    NAME READY STATUS RESTARTS AGE
  3.  
    app-pod 1/1 Running 0 41m
  4.  
    root@k8s-master:~/configmap# kubectl apply -f pod2.yaml
  5.  
    pod/app-pod2 created
  6.  
    root@k8s-master:~/configmap#
  7.  
    root@k8s-master:~/configmap# kubectl get pod
  8.  
    NAME READY STATUS RESTARTS AGE
  9.  
    app-pod 1/1 Running 0 41m
  10.  
    app-pod2 1/1 Running 0 4s
  11.  
    root@k8s-master:~/configmap# kubectl exec -it app-pod2 -- /bin/bash
  12.  
    root@app-pod2:/# cat /etc/app-config/db.conf
  13.  
    db.host=127.0.0.1
  14.  
    db.port=3306
 

3.通过command的方式注入键值对

 
  1.  
    # cat pod3.yaml
  2.  
    apiVersion: v1
  3.  
    kind: Pod
  4.  
    metadata:
  5.  
    name: app-pod3
  6.  
    spec:
  7.  
    containers:
  8.  
    - name: app-pod3
  9.  
    image: m.daocloud.io/docker.io/nginx
  10.  
    command: [ "/bin/bash", "-c", "echo $(log.level) && sleep 3600" ] #通过命令行输出环境变量显示加载的CM值
  11.  
    env:
  12.  
    - name: LOG_LEVEL
  13.  
    valueFrom:
  14.  
    configMapKeyRef:
  15.  
    name: app-config
  16.  
    key: log.level
  17.  
    envFrom:
  18.  
    - configMapRef:
  19.  
    name: app-config
 

验证结果,发现db.conf已经挂载到指定目录

 

4.对比总结

上面举例了ConfigMap 3种注入的方式,具体采用哪一种可以根据项目需求而定。

维度 环境变量注入 挂载配置文件 Command 注入
数据格式 单行键值对 多行文本/完整文件 单行键值对
动态更新支持 需重启 Pod 自动更新 需重启 Pod
配置复杂度 高(支持嵌套结构) 中(依赖脚本处理)
适用场景 简单参数(端口、开关) 复杂配置(JSON、XML) 动态生成启动命令
性能影响 文件 I/O 可能影响性能

脚本执行可能增加启动耗时

 

5.选择建议

  1. 优先挂载配置文件:适用于需动态更新或复杂配置的场景。
  2. 慎用 Command 注入:仅在必须通过命令拼接参数时使用,避免过度依赖 Shell 脚本。
  3. 环境变量用于简单配置:如开关、基础参数等无需频繁更新的场景。

通过合理组合这三种方式,可高效管理 Kubernetes 应用的配置,同时平衡灵活性与性能。

 

 

2. 高级功能与注意事项

2.1 热更新机制

  • Volume 挂载:ConfigMap 更新后,容器内文件自动同步(约 30 秒延迟)。
  • 环境变量:需删除并重建 Pod 以生效。

2.2 不可变 ConfigMap

在 Kubernetes 中,将 ConfigMap 设置为不可变(immutable: true)是一种优化配置管理和提升集群稳定性的重要手段。设置了这个字段,就不能通过热更新或者edit的方式去修改更新配置,只能通过删除重建更新配置。

举例:

 
  1.  
    apiVersion: v1
  2.  
    kind: ConfigMap
  3.  
    metadata:
  4.  
    name: immutable-config
  5.  
    immutable: true
  6.  
    data:
  7.  
    key: "value"
 

 2025,每天10分钟,跟我学K8S(三十六)- 对象属性 - Volume - Secret-CSDN博客

        上节课学习了ConfigMap,了解了ConfigMap这个资源对象是K8S当中非常重要的一个对象,ConfigMap一般情况下是用来存储一些非安全的配置信息,如果涉及到一些安全相关的数据的话用ConfigMap就不适合了,因为ConfigMap是明文存储的,如果需要加密存储,就需要用到另外一个资源对象了:SecretSecret用来保存敏感信息,例如密码、API 密钥、TLS 证书等等,将这些信息放在Secret中比放在Pod的定义中或者docker镜像中来说更加安全和灵活。

        

Secret 

        Secret 是 Kubernetes 中用于管理敏感信息(如密码、API 密钥、TLS 证书等)的核心资源。其设计目标是避免敏感数据硬编码到 Pod 或镜像中,提升安全性与可维护性。

一、Secret 的核心特性

  1. 数据安全

    • Base64 编码存储:Secret 中的数据默认以 Base64 编码形式保存于 etcd 中,但需注意这并非加密,仅提供基础防护。
    • 动态注入:支持通过环境变量或文件挂载方式注入到 Pod 中,无需重启容器即可更新(需重新创建 Pod)。
    • 类型化支持:预定义多种类型适配不同场景,例如:
      • ​**Opaque**:通用键值对存储(如用户名、密码)。
      • ​**kubernetes.io/tls**:存储 HTTPS 证书和私钥。
      • ​**kubernetes.io/dockerconfigjson**:私有镜像仓库认证信息。

 

二、Secret 的创建与使用

1. 创建方式

  • 命令行创建

 
  1.  
    # 通用类型(键值对)
  2.  
    kubectl create secret generic my-secret --from-literal=username=root --from-literal=password=password
  3.  
     
  4.  
    # TLS 证书类型
  5.  
    kubectl create secret tls my-tls-secret --cert=path/to/cert.pem --key=path/to/key.pem
 
  • YAML 文件定义

 
  1.  
    apiVersion: v1
  2.  
    kind: Secret
  3.  
    metadata:
  4.  
    name: db-secret
  5.  
    data:
  6.  
    username: cm9vdA== # "root" 的 Base64 编码
  7.  
    password: cGFzc3dvcmQ= # "password" 的 Base64 编码
 

2.挂载方式

  • 环境变量注入

 
  1.  
    env:
  2.  
    - name: DB_PASSWORD
  3.  
    valueFrom:
  4.  
    secretKeyRef:
  5.  
    name: db-secret
  6.  
    key: password
 
  • 文件挂载

 
  1.  
    volumes:
  2.  
    - name: secret-volume
  3.  
    secret:
  4.  
    secretName: db-secret
  5.  
    containers:
  6.  
    - volumeMounts:
  7.  
    - name: secret-volume
  8.  
    mountPath: "/etc/secrets"
 

3. 数据查看与验证

  • 查看 Secret 详情

 
  1.  
    kubectl get secret my-secret -o yaml # 显示编码后的数据
  2.  
     
  3.  
    # kubectl get secret my-secret -o yaml
  4.  
    apiVersion: v1
  5.  
    data:
  6.  
    password: cGFzc3dvcmQ=
  7.  
    username: cm9vdA==
  8.  
    kind: Secret
  9.  
    metadata:
  10.  
    creationTimestamp: "2025-04-02T03:24:44Z"
  11.  
    name: my-secret
  12.  
    namespace: default
  13.  
    resourceVersion: "224361"
  14.  
    uid: be74cf70-d200-40de-b064-d3b99340f83f
  15.  
    type: Opaque
  16.  
     
  17.  
     
  18.  
     
  19.  
    echo "cm9vdA==" | base64 -d # 解码示例
  20.  
     
  21.  
    # echo "cm9vdA==" | base64 -d
  22.  
    root
 

 

三、举例说明

1.常规案例

1.创建secret
 
  1.  
    # cat secret.yaml
  2.  
    apiVersion: v1
  3.  
    kind: Secret
  4.  
    metadata:
  5.  
    name: db-secret
  6.  
    data:
  7.  
    username: cm9vdA== # "root" 的 Base64 编码
  8.  
    password: cGFzc3dvcmQ= # "password" 的 Base64 编码
 

 

2. 创建deployment.yaml
 
  1.  
    # cat deployment.yaml
  2.  
    apiVersion: apps/v1
  3.  
    kind: Deployment
  4.  
    metadata:
  5.  
    name: webapp-deployment-secret
  6.  
    labels:
  7.  
    app: webapp
  8.  
    spec:
  9.  
    replicas: 3
  10.  
    selector:
  11.  
    matchLabels:
  12.  
    app: webapp
  13.  
    template:
  14.  
    metadata:
  15.  
    labels:
  16.  
    app: webapp
  17.  
    spec:
  18.  
    containers:
  19.  
    - name: webapp
  20.  
    image: m.daocloud.io/docker.io/nginx
  21.  
    # 方式一:环境变量注入
  22.  
    env:
  23.  
    - name: DB_USERNAME
  24.  
    valueFrom:
  25.  
    secretKeyRef:
  26.  
    name: db-secret
  27.  
    key: username
  28.  
    - name: DB_PASSWORD
  29.  
    valueFrom:
  30.  
    secretKeyRef:
  31.  
    name: db-secret
  32.  
    key: password
  33.  
     
  34.  
    # 方式二:文件挂载
  35.  
    volumeMounts:
  36.  
    - name: secret-volume
  37.  
    mountPath: "/etc/db-credentials"
  38.  
    readOnly: true
  39.  
    volumes:
  40.  
    - name: secret-volume
  41.  
    secret:
  42.  
    secretName: db-secret
 
3.应用并验证

通过下图可以看出来,两种方式的secret都使用成功

①② 应用2个yaml文件

③ 查看pod

④ 进入任意一个pod

⑤⑥ 查看通过环境变量方式挂载secret 显示  用户密码

⑦⑧ 查看通过文件方式挂载secret 显示 现在用户密码

2.登录私有仓库的案例

上面举例说明了secret的使用,下面再举例一个用的最多的,也就是通过secret登录自己的私有仓库下载镜像

1. 创建 Docker Hub 认证 Secret
 
  1.  
    #方式1, 通过kubectl create 创建一个secret
  2.  
    kubectl create secret docker-registry dockerhub-secret \
  3.  
    --docker-server=https://index.docker.io/v1/ \
  4.  
    --docker-username=your-username \
  5.  
    --docker-password=your-password \
  6.  
    --docker-email=your-email@example.com
  7.  
     
  8.  
     
  9.  
    #方式2,通过yaml文件创建
  10.  
    apiVersion: v1
  11.  
    kind: Secret
  12.  
    metadata:
  13.  
    name: dockerhub-secret
  14.  
    namespace: default
  15.  
    type: kubernetes.io/dockerconfigjson
  16.  
    data:
  17.  
    .dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ5b3VyLXVzZXJuYW1lIiwicGFzc3dvcmQiOiJ5b3VyLXBhc3N3b3JkIiwiZW1haWwiOiJ5b3VyLWVtYWlsQGV4YW1wbGUuY29tIiwiYXV0aCI6ImVXOTFjaTExYzJWeWJtRnRaVHA1YjNWeUxYQmhjM04zYjNKayJ9fX0=
  18.  
     
 

上面方式2 .dockerconfigjson后面一大截可能看起来会不知道什么意思,其实解码后能知道,是一串json键值对,包含方式1里面的仓库地址,用户密码等信息

 
  1.  
    #解码
  2.  
    # echo "eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ5b3VyLXVzZXJuYW1lIiwicGFzc3dvcmQiOiJ5b3VyLXBhc3N3b3JkIiwiZW1haWwiOiJ5b3VyLWVtYWlsQGV4YW1wbGUuY29tIiwiYXV0aCI6ImVXOTFjaTExYzJWeWJtRnRaVHA1YjNWeUxYQmhjM04zYjNKayJ9fX0=" |base64  -d
  3.  
    {"auths":{"https://index.docker.io/v1/":{"username":"your-username","password":"your-password","email":"your-email@example.com","auth":"eW91ci11c2VybmFtZTp5b3VyLXBhc3N3b3Jk"}}}
 
2.创建deployment来使用这个secret

      imagePullSecrets:  # 关键配置:声明拉取镜像的凭证
      - name: dockerhub-secret  # 必须与 Secret 名称一致

 
  1.  
    apiVersion: apps/v1
  2.  
    kind: Deployment
  3.  
    metadata:
  4.  
    name: private-image-deployment
  5.  
    spec:
  6.  
    replicas: 2
  7.  
    selector:
  8.  
    matchLabels:
  9.  
    app: private-app
  10.  
    template:
  11.  
    metadata:
  12.  
    labels:
  13.  
    app: private-app
  14.  
    spec:
  15.  
    containers:
  16.  
    - name: app-container
  17.  
    image: your-dockerhub-username/private-image:latest # 私有镜像地址
  18.  
    ports:
  19.  
    - containerPort: 8080
  20.  
    imagePullSecrets: # 关键配置:声明拉取镜像的凭证
  21.  
    - name: dockerhub-secret # 必须与 Secret 名称一致
 
3.验证

由于这里的用户信息都是为了举例填写的,会登录失败,所以结果会拉取失败,大家在日常使用中修改为自己的仓库地址信息即可。

 

四、常见问题与解决方案

  1. Secret 更新后未生效

    • 原因:已运行的 Pod 不会自动同步 Secret 变更。
    • 解决:重建 Pod 或使用支持热加载的应用框架(如 Nginx Reload)。
  2. Base64 编码错误

    • 注意点:使用 echo -n 避免换行符干扰编码结果。
    • 验证命令kubectl get secret <name> -o jsonpath='{.data}' | jq . 检查数据完整性。
  3. Secret 挂载权限问题

    • 设置文件权限:在 Volume 挂载时指定 defaultMode 参数限制文件访问权限。

 

五、与 ConfigMap 的对比

维度 Secret ConfigMap
数据安全 Base64 编码 明文存储
适用场景 密码、密钥、证书等 配置文件、环境变量等
加密支持 需配合 KMS 或 Vault 无原生加密
存储限制 1MB 1MB

2025,每天10分钟,跟我学K8S(三十七)- RBAC_pod-reader-cluster-CSDN博客

        我们在前面的章节,讲解了许多K8S中的对象,例如Pods、ConfigMaps、Deployments、Nodes、Secrets、Namespaces等,那如何对他们进行权限管理呢?

        假设我们有一个名为 zhangsan 的用户,想相对这些资源拥有权限,首先想到的就是针对每个资源针对用户进行赋权,例如create、get、delete、list、update、edit、watch、exec各种权限,那这时候又来了一个 lisi 的用户,需要想同的权限,那上述操作是不是需要再重复一次。有没有更简单的方法?当然有,首先创建一个用户 zhangsan(User), 然后创建一个角色(Role),最后将它们2个绑定到一次(RoleBinding)。这样后面想创建 lisi 的角色,也只需要创建完用户后,继续绑定到这个角色上即可。

 

一、RBAC 核心概念与架构

        RBAC 是 Kubernetes 中实现细粒度权限管理的核心机制,通过 ​角色(Role/ClusterRole)​ 和 ​绑定(RoleBinding/ClusterRoleBinding)​ 控制用户、服务账户等主体对集群资源的访问权限,允许管理员通过 Kubernetes API 动态配置策略,要启用RBAC,需要在 apiserver 中添加参数--authorization-mode=RBAC,如果使用的kubeadm安装的集群,目前版本都默认开启了RBAC,可以通过查看 Master 节点上 kube-apiserver.yaml查看是否启用:

cat /etc/kubernetes/manifests/kube-apiserver.yaml 

资源列表:

  • Pods
  • ConfigMaps
  • Deployments
  • Nodes
  • Secrets
  • Namespaces

操作权限:

  • create
  • get
  • delete
  • list
  • update
  • edit
  • watch
  • exec

 

角色讲解:

1.角色(Role)​

  • 作用范围:限定在单个命名空间内,定义对特定资源的操作权限(如 Pod 的增删改查)。
  • 示例配置
 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: Role
  3.  
    metadata:
  4.  
    namespace: default
  5.  
    name: pod-reader
  6.  
    rules:
  7.  
    - apiGroups: [""] # 核心 API 组(如 Pod、Node 等)
  8.  
    resources: ["pods"]
  9.  
    verbs: ["get", "list", "watch"] # 允许的操作类型
 

 

​2.角色绑定(RoleBinding)​


将 ​Role 或 ​ClusterRole 绑定到主体(如用户、服务账户),限定在特定命名空间内生效。

  • 示例:将 pod-reader 角色绑定至服务账户 cicd-sa
 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: RoleBinding
  3.  
    metadata:
  4.  
    name: cicd-pod-access
  5.  
    namespace: default
  6.  
    subjects:
  7.  
    - kind: ServiceAccount
  8.  
    name: cicd-sa
  9.  
    roleRef:
  10.  
    kind: Role
  11.  
    name: pod-reader
 

 

3.集群角色(ClusterRole)​

  1. 作用范围:全局生效,适用于跨命名空间或集群级资源(如节点、存储卷)。
  2. 典型场景:授予跨命名空间的 Deployment 只读权限。
  3. 示例配置
 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: ClusterRole
  3.  
    metadata:
  4.  
    name: cluster-pod-reader
  5.  
    rules:
  6.  
    - apiGroups: [""] # 核心 API 组(如 Pod、Node 等)
  7.  
    resources: ["pods", "nodes"]
  8.  
    verbs: ["get", "list", "watch"] # 允许的操作类型
 

4.​集群角色绑定(ClusterRoleBinding)​

赋予主体集群级权限(如管理所有命名空间的 Secrets)。

示例:将 cluster-pod-reader 角色绑定至服务账户 dev-team

 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: ClusterRoleBinding
  3.  
    metadata:
  4.  
    name: cluster-pod-reader-binding
  5.  
    subjects:
  6.  
    - kind: Group
  7.  
    name: dev-team # 用户组名称(需与认证系统集成)
  8.  
    apiGroup: rbac.authorization.k8s.io
  9.  
    roleRef:
  10.  
    kind: ClusterRole
  11.  
    name: cluster-pod-reader # 引用的 ClusterRole 名称
  12.  
    apiGroup: rbac.authorization.k8s.io
 

        通过上面的觉得讲解可以看出来,有两种类型的角色和绑定,一种是Role&RoleBinding,一种是c&ClsterRoleBinding,这两者有什么区别?

        其实从字面就可以看出来,前者是角色,后者是集群角色,那后者权限一定是大于前者的。我们将在后面进行讲解。

 

二、RBAC 应用场景与最佳实践

1.普通用户dev-team,赋予指定权限

场景:企业中存在开发、测试和运维团队,需确保各团队仅能访问其所属命名空间内的资源。这里创建一个dev-team的用户,规定只能访问名为dev的namespace下的pods和services,并且权限只有"get", "list", "create", "delete"
实现方案

1.创建普通用户:dev-team

  •  生成用户私钥与证书签名请求(CSR)
 
  1.  
    # 生成私钥(2048位RSA密钥)
  2.  
    openssl genrsa -out dev-team.key 2048
  3.  
     
  4.  
    # 创建证书签名请求(CN为用户标识,O为用户组)
  5.  
    openssl req -new -key dev-team.key -out dev-team.csr -subj "/CN=dev-team/O=dev-group"
 
  • 使用集群 CA 签发用户证书
 
  1.  
    # 使用 Kubernetes 集群 CA 签发证书(有效期 365 天)
  2.  
    openssl x509 -req -in dev-team.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out dev-team.crt -days 365
 
  • 生成 kubeconfig 文件
 
  1.  
    # 设置集群信息
  2.  
    kubectl config set-cluster kubernetes \
  3.  
    --certificate-authority=/etc/kubernetes/pki/ca.crt \
  4.  
    --embed-certs=true \
  5.  
    --server=https://<API-Server-IP>:6443 \
  6.  
    --kubeconfig=dev-team.kubeconfig
  7.  
     
  8.  
    # 添加用户凭证
  9.  
    kubectl config set-credentials dev-team \
  10.  
    --client-certificate=dev-team.crt \
  11.  
    --client-key=dev-team.key \
  12.  
    --embed-certs=true \
  13.  
    --kubeconfig=dev-team.kubeconfig
  14.  
     
  15.  
    # 创建上下文并设为默认
  16.  
    kubectl config set-context dev-team-context \
  17.  
    --cluster=kubernetes \
  18.  
    --user=dev-team \
  19.  
    --kubeconfig=dev-team.kubeconfig
  20.  
    kubectl config use-context dev-team-context --kubeconfig=dev-team.kubeconfig
 

2.创建Role:dev-team-role

 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: Role
  3.  
    metadata:
  4.  
    namespace: dev
  5.  
    name: dev-team-role
  6.  
    rules:
  7.  
    - apiGroups: [""]
  8.  
    resources: ["pods", "services"] # 允许访问 Pod 和 Service
  9.  
    verbs: ["get", "list", "watch"] # 仅授予只读权限
 

3.创建RoleBinging:dev-team-binding

 
  1.  
    apiVersion: rbac.authorization.k8s.io/v1
  2.  
    kind: RoleBinding
  3.  
    metadata:
  4.  
    name: dev-team-binding
  5.  
    namespace: dev
  6.  
    subjects:
  7.  
    - kind: User
  8.  
    name: dev-team # 绑定对应的用户名
  9.  
    apiGroup: rbac.authorization.k8s.io
  10.  
    roleRef:
  11.  
    kind: Role
  12.  
    name: dev-team-role #绑定对应的role名称
  13.  
    apiGroup: rbac.authorization.k8s.io
 

4. 应用配置

 
  1.  
    kubectl apply -f dev-team-role.yaml
  2.  
    kubectl apply -f dev-team-binding.yaml
 

5.权限验证

1. 验证权限范围
 
  1.  
    # 检查 dev 命名空间 Pod/Service 访问权限
  2.  
    kubectl auth can-i get pods --namespace=dev --kubeconfig=dev-team.kubeconfig # 预期返回 yes
  3.  
    kubectl auth can-i create pods --namespace=dev --kubeconfig=dev-team.kubeconfig # 预期返回 no
  4.  
     
  5.  
    # 检查其他命名空间权限
  6.  
    kubectl auth can-i get pods --namespace=prod --kubeconfig=dev-team.kubeconfig # 预期返回 no
 
2. 实际操作测试
 
  1.  
    # 查看 dev 命名空间的 Pod 和 Service(成功)
  2.  
    kubectl get pods,svc -n dev --kubeconfig=dev-team.kubeconfig
  3.  
     
  4.  
    # 尝试删除 Pod(失败)
  5.  
    kubectl delete pod -n dev nginx-6b9f9cd485-456jb --kubeconfig=dev-team.kubeconfig
  6.  
    Error from server (Forbidden): pods "nginx-6b9f9cd485-456jb" is forbidden: User "dev-team" cannot delete resource "pods" in API group "" in the namespace "dev"
 

2.超级账号Boss用户,赋予最大权限

场景:老板看大伙办事不力,准备亲自下场,现在要求给他创建一个最大权限的的账号。

1. ​生成用户Boss

 
  1.  
    # 生成私钥(RSA 2048位)
  2.  
    openssl genrsa -out boss.key 2048
  3.  
     
  4.  
    # 创建证书签名请求(CN 必须与用户名一致)
  5.  
    openssl req -new -key boss.key -out boss.csr -subj "/CN=boss/O=admin-group"
  6.  
     
  7.  
    # 使用集群 CA 签发证书(有效期 365 天)
  8.  
    openssl x509 -req -in boss.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out boss.crt -days 365
  9.  
     
  10.  
    # 生成 kubeconfig 文件
  11.  
    kubectl config set-cluster kubernetes \
  12.  
    --certificate-authority=/etc/kubernetes/pki/ca.crt \
  13.  
    --embed-certs=true \
  14.  
    --server=https://172.21.176.3:6443 \
  15.  
    --kubeconfig=boss.kubeconfig
  16.  
     
  17.  
    kubectl config set-credentials boss \
  18.  
    --client-certificate=boss.crt \
  19.  
    --client-key=boss.key \
  20.  
    --embed-certs=true \
  21.  
    --kubeconfig=boss.kubeconfig
  22.  
     
  23.  
    kubectl config set-context boss-context \
  24.  
    --cluster=kubernetes \
  25.  
    --user=boss \
  26.  
    --kubeconfig=boss.kubeconfig
  27.  
    kubectl config use-context boss-context --kubeconfig=boss.kubeconfig
 

2、创建ClusterRole和ClusterRoleClusterRoleBinging

这里可以有两种方式来操作,两种方式任选一种即可

1.创建一个新的new-cluster-admin集群角色,并且手动赋予最大权限

2.选择Kubernetes 默认提供 cluster-admin 集群角色,拥有对所有资源的完全控制权。

 

2.1 手动创建:

1、创建一个名为new-cluster-admin的最大权限

 
  1.  
    # cat new-cluster-admin.yaml
  2.  
     
  3.  
    apiVersion: rbac.authorization.k8s.io/v1
  4.  
    kind: ClusterRole
  5.  
    metadata:
  6.  
    name: new-cluster-admin
  7.  
    rules:
  8.  
    - apiGroups: ["*"] # 覆盖所有 API 组(包括核心组、apps、networking 等)
  9.  
    resources: ["*"] # 所有资源类型(如 pods、nodes、secrets、services 等)
  10.  
    verbs: ["*"] # 允许所有操作(get、list、create、delete、patch 等)
  11.  
    - nonResourceURLs: ["*"] # 非资源端点(如 /healthz、/metrics、/api 等)
  12.  
    verbs: ["*"] # 允许访问所有非资源 URL
 

2、绑定new-cluster-admin

 
  1.  
    # cluster-admin-binding.yaml
  2.  
    apiVersion: rbac.authorization.k8s.io/v1
  3.  
    kind: ClusterRoleBinding
  4.  
    metadata:
  5.  
    name: boss-cluster-admin
  6.  
    subjects:
  7.  
    - kind: User
  8.  
    name: boss
  9.  
    apiGroup: rbac.authorization.k8s.io
  10.  
    roleRef:
  11.  
    kind: ClusterRole
  12.  
    name: new-cluster-admin # 预置超级管理员角色
  13.  
    apiGroup: rbac.authorization.k8s.io
 

3、绑定

 
  1.  
    # kubectl apply -f new-cluster-admin.yaml
  2.  
    clusterrole.rbac.authorization.k8s.io/new-cluster-admin unchanged
  3.  
    # kubectl apply -f new-cluster-admin-binding.yaml
  4.  
    clusterrolebinding.rbac.authorization.k8s.io/boss-cluster-admin created
 
2.2 绑定内置ClusterRole,通过 ​ClusterRoleBinding 直接关联用户:

1、直接绑定 cluster-admin-binding

 
  1.  
    # cluster-admin-binding.yaml
  2.  
    apiVersion: rbac.authorization.k8s.io/v1
  3.  
    kind: ClusterRoleBinding
  4.  
    metadata:
  5.  
    name: boss-cluster-admin
  6.  
    subjects:
  7.  
    - kind: User
  8.  
    name: boss
  9.  
    apiGroup: rbac.authorization.k8s.io
  10.  
    roleRef:
  11.  
    kind: ClusterRole
  12.  
    name: cluster-admin # 预置超级管理员角色
  13.  
    apiGroup: rbac.authorization.k8s.io
 

2、绑定cluster-admin-binding

kubectl apply -f cluster-admin-binding.yaml

3、权限验证

3.1. ​基础权限检查
 
  1.  
    # 验证集群级权限
  2.  
    kubectl auth can-i '*' '*' --kubeconfig=boss.kubeconfig # 预期返回 yes
  3.  
     
  4.  
    # 验证跨命名空间操作
  5.  
    kubectl auth can-i delete pods -n kube-system --kubeconfig=boss.kubeconfig # 预期返回 yes
 
3.2. ​实际操作测试
 
  1.  
    # 创建/删除集群级资源(如 Node 查看)
  2.  
    kubectl get nodes --kubeconfig=boss.kubeconfig
  3.  
     
  4.  
    # 操作敏感资源(如 Secrets)
  5.  
    kubectl get secrets -n kube-system --kubeconfig=boss.kubeconfig
  6.  
    kubectl delete pod <pod-name> -n kube-system --kubeconfig=boss.kubeconfig
 

 

3.两者的区别:

Role:

作用范围:Role 的作用范围限定在特定的命名空间内,例如 dev 或 prod,仅能控制该命名空间内的资源(如 Pod、Service)的访问权限

可授权的资源类型:授权同一命名空间内的资源操作,例如在 dev 命名空间中管理 Pod 的增删改查

绑定方式与权限复用: RoleBinding 引用 ClusterRole:如网页所述,ClusterRole 可以通过 RoleBinding 绑定到特定命名空间,此时其权限仅在该命名空间生效(例如将集群级角色限制在 prod 命名空间使用)

典型应用场景:授权 dev 命名空间的 ServiceAccount 管理 Deployment(仅限该命名空间)

 

ClusterRole:

作用范围:ClusterRole 的权限覆盖整个集群,包括所有命名空间、集群级资源(如 Node、PersistentVolume)和非资源端点(如 /healthz

可授权的资源类型:可授权集群级资源(如 Node、ClusterRole)和跨命名空间资源(如所有 Secrets),同时支持对非 RESTful API 端点的访问

绑定方式与权限复用: 直接赋予全局权限,例如授权用户查看所有命名空间的 Pod(kubectl get pods --all-namespaces

典型应用场景:予全局 Secret 读取权限,或跨命名空间 Pod 监控权限

 

总结:

  • Role:适用于单一命名空间内的细粒度权限控制,例如开发团队的资源隔离。
  • ClusterRole:用于全局或跨命名空间的权限需求,如集群管理员、监控工具或跨团队资源共享。
  • 选择原则:优先使用 Role 满足最小权限原则,仅在需要跨命名空间或集群级操作时使用 ClusterRole

 

二、RBAC 工作原理与授权流程

  1. 权限校验流程

    • 请求接收:用户或服务账户通过 kubectl 或 API 发起操作请求。
    • 鉴权匹配:API Server 根据 RBAC 规则验证主体是否具备执行操作的权限。
    • 权限决策:若权限匹配则放行,否则拒绝并记录审计日志。
  2. 规则定义逻辑

    • 资源与操作:通过 apiGroupsresourcesverbs 字段精确控制可访问的 API 资源及操作类型。
    • 例外控制:通过 resourceNames 限制对特定资源实例的操作(如禁止删除 critical-config ConfigMap)。
 

三、RBAC 应用场景与最佳实践

  1. 典型应用场景

    • CI/CD 流水线权限:授予服务账户管理 Pod 的 get/list/watch 权限,支持自动化部署。
    • 多团队协作:通过命名空间隔离不同团队的资源访问权限。
    • 安全合规:限制运维人员仅能查看日志,禁止修改生产环境资源。
  2. 最佳实践

    • 最小权限原则:避免使用 verbs: ["*"],明确列出所需操作。
    • 使用内置角色:优先选择 view(只读)、edit(编辑)等预定义角色。
    • 定期审计:通过 kubectl auth can-i 检查权限有效性。
    • 服务账户管理:为每个微服务创建独立服务账户,避免共享默认 default 账户。

2025,每天10分钟,跟我学K8S(三十八)- Helm (一)什么是Helm _helm国内仓库-CSDN博客

 

        之前章节学习了K8S中各种各样的资源对象,现在提出一个问题,让你来创建一个可以对外提供访问的MYSQL服务,你会怎么做?我想了下大概有5个步骤如下:

  • 创建一个mysql-secret.yaml 用于定义mysql的账号密码
  • 创建一个mysql-volume.yaml 创建pv/pvc用于存储mysql持久化的数据
  • 创建一个mysql-deployment.yaml 用于创建mysql的pod服务
  • 创建一个mysql-service.yaml 用于提供对外服务
  • 使用kubectl apply -f 命令依次去应用上述yaml文件

        看起来都头大,为什么用了K8S,比在物理机上安装要麻烦这么多?而且这还只是一个mysql应用,当环境中有100个应用,那该怎么办?难道每个应用都要按照上述流程走一次?能不能使用一个 apt install mysql-server 就安装好一个服务呢?答案当然是有,Helm就相当于kubernetes环境下的apt包管理工具。

 

什么是HELM

        Helm 是 Kubernetes 生态中的核心包管理工具,旨在简化应用的打包、部署和生命周期管理。

一、Helm 的核心概念

  1. Chart

    • 定义:Helm 的“软件包”,包含应用部署所需的所有 Kubernetes 资源模板(如 Deployment、Service)及默认配置(values.yaml)。
    • 目录结构
      • Chart.yaml:元数据文件(名称、版本、依赖等)。
      • templates/:存放 Kubernetes 资源模板(支持 Go 模板语法)。
      • values.yaml:默认配置参数,支持动态注入。
  2. Release

    • 实例化:每次通过 Helm 安装 Chart 会生成唯一的 Release,记录版本状态和配置差异。
    • 版本追踪:支持查看历史版本及回滚(如 helm rollback <release> <version>)。
  3. Repository

    • 仓库类型:公共仓库(如 stablebitnami)和私有仓库(如 Harbor),用于存储和分发 Chart。
    • 仓库管理:通过 helm repo add/update 添加或同步仓库索引。

二、Helm 的核心功能与优势

  1. 简化复杂应用部署

    • 模板化配置:通过变量替换(如 {{ .Values.image.tag }})实现多环境配置复用。
    • 依赖管理:支持定义子 Chart(charts/ 目录)及版本约束。
  2. 生命周期管理

    • 安装/升级:使用 helm install/upgrade 部署或更新应用,自动处理资源顺序。
    • 回滚机制:基于版本快照快速恢复至历史状态(依赖 helm history 和 helm rollback)。
  3. 动态资源生成

    • 钩子(Hooks)​:在部署生命周期中插入自定义操作(如预检查、数据库迁移)。
    • 条件渲染:根据参数动态生成资源(如 if .Values.ingress.enabled 控制 Ingress 创建)。

三、Helm 的安装与使用

1.​安装 Helm

Helm现在主要使用v3版:

  • Helm官方网址:https://helm.sh/zh/
  • Helm国内镜像:http://mirror.rancher.cn/ 或 http://mirror.cnrancher.com/

本章采用最新版3.17.2(202503最新版)

  • 下载Helm
 
  1.  
    # 创建临时目录并下载
  2.  
    root@k8s-master:~# mkdir -vp helm
  3.  
    mkdir: created directory 'helm'
  4.  
    root@k8s-master:~# cd helm/
  5.  
    root@k8s-master:~/helm# wget https://rancher-mirror.rancher.cn/helm/v3.17.2/helm-v3.17.2-linux-amd64.tar.gz
  6.  
     
  7.  
    # 解压并将二进制文件移至/usr/local/bin
  8.  
    root@k8s-master:~/helm# tar zxvf helm-v3.17.2-linux-amd64.tar.gz
  9.  
    linux-amd64/
  10.  
    linux-amd64/LICENSE
  11.  
    linux-amd64/helm
  12.  
    linux-amd64/README.md
  13.  
     
  14.  
     
  15.  
    root@k8s-master:~/helm# cd linux-amd64/
  16.  
    root@k8s-master:~/helm/linux-amd64# ls
  17.  
    helm LICENSE README.md
  18.  
    root@k8s-master:~/helm/linux-amd64# mv helm /usr/local/bin/
  19.  
     
  20.  
    # 版本验证
  21.  
    root@k8s-master:~/helm/linux-amd64# helm version
  22.  
    version.BuildInfo{Version:"v3.17.2", GitCommit:"cc0bbbd6d6276b83880042c1ecb34087e84d41eb", GitTreeState:"clean", GoVersion:"go1.23.7"}
  23.  
     
 
  • 更换国内仓库

由于helm默认仓库是使用国外镜像,所以会导致很多时候速度慢甚至无法下载,将镜像仓库修改为阿里云仓库

 
  1.  
    # 查看仓库源 为空
  2.  
    helm repo list
  3.  
    # 新增仓库源,可以添加多个地址,
  4.  
    helm repo add azure http://mirror.azure.cn/kubernetes/charts/
  5.  
    helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
  6.  
     
  7.  
    # 配置国内Chart仓库
  8.  
     
  9.  
    阿里云仓库(https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts) #已经很久不更新
  10.  
    微软仓库(http://mirror.azure.cn/kubernetes/charts/) #推荐
  11.  
    官方仓库(https://hub.kubeapps.com/charts/incubator)官方chart仓库,国内有点不好使。
  12.  
     
  13.  
     
  14.  
    # 搜索redis镜像
  15.  
    # helm search repo redis
  16.  
    NAME CHART VERSION APP VERSION DESCRIPTION
  17.  
    aliyun/redis 1.1.15 4.0.8 Open source, advanced key-value store. It is of...
  18.  
    aliyun/redis-ha 2.0.1 Highly available Redis cluster with multiple se...
  19.  
    azure/prometheus-redis-exporter 3.5.1 1.3.4 DEPRECATED Prometheus exporter for Redis metrics
  20.  
    azure/redis 10.5.7 5.0.7 DEPRECATED Open source, advanced key-value stor...
  21.  
    azure/redis-ha 4.4.6 5.0.6 DEPRECATED - Highly available Kubernetes implem...
  22.  
    aliyun/sensu 0.2.0 Sensu monitoring framework backed by the Redis ...
  23.  
    azure/sensu 0.2.5 0.28 DEPRECATED Sensu monitoring framework backed by...
  24.  
     
  25.  
     
 

2.使用Helm

创建一个新的helm Chart

 
  1.  
    # 创建一个myapp的自定义应用
  2.  
    root@k8s-master:~/helm# helm create myapp
  3.  
    Creating myapp
  4.  
     
  5.  
    # 进入目录
  6.  
    root@k8s-master:~/helm# cd myapp/
  7.  
     
  8.  
    # 查看目录结构
  9.  
    root@k8s-master:~/helm/myapp# tree
  10.  
    .
  11.  
    ├── charts
  12.  
    ├── Chart.yaml
  13.  
    ├── templates
  14.  
    │   ├── deployment.yaml
  15.  
    │   ├── _helpers.tpl
  16.  
    │   ├── hpa.yaml
  17.  
    │   ├── ingress.yaml
  18.  
    │   ├── NOTES.txt
  19.  
    │   ├── serviceaccount.yaml
  20.  
    │   ├── service.yaml
  21.  
    │   └── tests
  22.  
    │   └── test-connection.yaml
  23.  
    └── values.yaml
  24.  
     
  25.  
    3 directories, 10 files
 

这里从目录结构可以看出来,可以总共分为3大部分:

  • Chart.yaml、
  • values.yaml
  • templates目录下的其他yaml文件

这些文件有什么作用,会在后面的章节详细讲解,现在首先编辑values.yaml,发现默认是一个nginx的镜像,由于默认dockerhub仓库国内无法访问,将nginx镜像修改为镜像仓库。为了后面访问方便,将Service 的类型也改成 NodePort。

修改镜像地址:



修改service类型为NodePort:

3.创建首个helm应用

        在myapp目录的上一层,使用命令 helm install myapp myapp 安装,这里第一个myapp 为创建后的deployments的名字,第二个myapp为刚create的目录名。

        在install后,提示我们可以运行后续命令,可以获取对应的服务暴露IP和端口,也就是可以通过  $NODE_IP:$NODE_PORT 来访问myapp这个服务。

 
  1.  
    root@k8s-master:~/helm# ls
  2.  
    helm-v3.17.2-linux-amd64.tar.gz linux-amd64 myapp
  3.  
    root@k8s-master:~/helm# helm install myapp myapp
  4.  
    NAME: myapp
  5.  
    LAST DEPLOYED: Thu Apr 3 14:28:31 2025
  6.  
    NAMESPACE: default
  7.  
    STATUS: deployed
  8.  
    REVISION: 1
  9.  
    NOTES:
  10.  
    1. Get the application URL by running these commands:
  11.  
    export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services myapp)
  12.  
    export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  13.  
    echo http://$NODE_IP:$NODE_PORT
 

查看helm 下的应用,查看deployment,查看pod

 
  1.  
    root@k8s-master:~/helm# helm list
  2.  
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
  3.  
    myapp default 1 2025-04-03 14:33:46.58464117 +0800 CST deployed myapp-0.1.0 1.16.0
  4.  
    root@k8s-master:~/helm# kubectl get deployments,pod
  5.  
    NAME READY UP-TO-DATE AVAILABLE AGE
  6.  
    deployment.apps/myapp 1/1 1 1 21s
  7.  
     
  8.  
    NAME READY STATUS RESTARTS AGE
  9.  
    pod/myapp-6c5df5768-nvvcg 1/1 Running 0 21s
 

查看nginx服务是否对外正常

 
  1.  
    # 获取端口
  2.  
    root@k8s-master:~/helm# echo $(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services myapp)
  3.  
    32117
  4.  
     
  5.  
    # 获取IP
  6.  
    root@k8s-master:~/helm# echo $(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  7.  
    172.21.176.3
  8.  
     
  9.  
    # 通过curl 访问测试
  10.  
    root@k8s-master:~/helm# curl 172.21.176.3:32117
  11.  
    <!DOCTYPE html>
  12.  
    <html>
  13.  
    <head>
  14.  
    <title>Welcome to nginx!</title>
  15.  
    ......
 

4.载这个helm 应用

使用命令 helm uninstall myapp 即可卸载,这里只需要有应用名即可。不需要带目录名,卸载后发现pod也消失了。

 
  1.  
    root@k8s-master:~/helm# helm uninstall myapp
  2.  
    release "myapp" uninstalled
  3.  
    root@k8s-master:~/helm# helm list
  4.  
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
  5.  
    root@k8s-master:~/helm# kubectl get deployments,pod
  6.  
    No resources found in default namespace.
 

 2025,每天10分钟,跟我学K8S(三十九)- Helm (二)Helm的结构和案例_helm案例-CSDN博客

        前面一章,大概了解了下helm的安装,和创建自定义的应用,本章节,来完整演示一下通过helm安装一个mysql应用的方式,了解一下helm的目录结构及作用。

 

helm的目录结构

        上一章,我们创建了一个myapp的自定义应用,并且知道了他的目录结构

 
  1.  
    # 创建一个myapp的自定义应用
  2.  
    root@k8s-master:~/helm# helm create myapp
  3.  
    Creating myapp
  4.  
     
  5.  
    # 进入目录
  6.  
    root@k8s-master:~/helm# cd myapp/
  7.  
     
  8.  
    # 查看目录结构
  9.  
    root@k8s-master:~/helm/myapp# tree
  10.  
    .
  11.  
    ├── charts
  12.  
    ├── Chart.yaml
  13.  
    ├── templates
  14.  
    │   ├── deployment.yaml
  15.  
    │   ├── _helpers.tpl
  16.  
    │   ├── hpa.yaml
  17.  
    │   ├── ingress.yaml
  18.  
    │   ├── NOTES.txt
  19.  
    │   ├── serviceaccount.yaml
  20.  
    │   ├── service.yaml
  21.  
    │   └── tests
  22.  
    │   └── test-connection.yaml
  23.  
    └── values.yaml
  24.  
     
  25.  
    3 directories, 10 files
 

Chart.yaml 

YAML 文件,描述 chart 的概要信息。

name和version是必须得,其他为选填

values.yaml

helm的核心文件,定义了对象的制化配置(镜像地址、容器检查、容器数量、卷、资源限制、pvpvc等等),chart 支持在安装的时根据参数进行定制化配置,而 values.yaml 就是提供了这些配置参数的默认值。services,deployment,configmap等配置都是从这个地方取值,然后进行渲染生成

templates 目录 

        各种 Kubernetes 对象资源的配置模板都放置在这里。Helm 会将 values.yaml 中的参数值注入到模板中进行渲染,最后生成标准的 YAML 配置文件。例如渲染成deployment.yaml,svc.yaml,ingress.yaml等等。

        模板是 chart 最重要的部分,也是 Helm 最强大的地方。模板增加了应用部署的灵活性,能够适用不同的环境。

 

动态字段详解​

​变量引用​

以 templates/deployment.yaml 为例:

        单独一眼扫过,其实和之前创建pod时候,自己手动写的deployment.yaml差不多,只是之前我们都是写死,但是这里是通过 {{ include "myapp.fullname" . }} 这种模板方式来定义,这其实是Go 语言的模板来编写 chart。        


 

① {{ include "myapp.fullname" . }} 定义 Deployment 的 name。这个fullname。是在 templates/_helpers.tpl 文件中定义的。​从下图可以看到,定义fmyapp.fullname又是做了一些判断,如果上一层的Values.yaml文件中有定义fullnameOverride,那就采用这个,如果没定义则继续下面的判断。

② image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 定义了deployment.yaml下的镜像下载地址,.Values.image.repository和.Values.image.tag,从

values.yaml 中取值,如果没有定义,则为空。也就是下面的内容

 
  1.  
    repository: m.daocloud.io/docker.io/nginx
  2.  
    # This sets the pull policy for images.
  3.  
    pullPolicy: IfNotPresent
  4.  
    # Overrides the image tag whose default is the chart appVersion.
  5.  
    tag: ""
  6.  
     
  7.  
    拼接后内容为
  8.  
    image: m.daocloud.io/docker.io/nginx
 

③ imagePullSecrets: {{- toYaml . | nindent 8 }}  将输入的数据结构转换为 YAML 格式字符串,并且换行后缩进 8 个空格

 
  1.  
    如果 values.yaml 中的 imagePullSecrets: [] 有值
  2.  
    则渲染成
  3.  
    spec:
  4.  
    imagePullSecretsxx
 
条件判断​

以 templates/hpa.yaml 为例:

这里的if判断语法以 {{ if xxx }}开始,以最近的{{ end }}结尾

 
  1.  
    # 下面的语句就是判断.Values.autoscaling.targetCPUUtilizationPercentage是否存在,如果存在则渲染下面几行的内容
  2.  
     
  3.  
    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
  4.  
    - type: Resource
  5.  
    resource:
  6.  
    name: cpu
  7.  
    target:
  8.  
    type: Utilization
  9.  
    averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
  10.  
    {{- end }}
  11.  
     
 

 

​循环与列表处理​

以 templates/ingress.yaml 为例:

这里的if判断语法以 {{ range xxx }}开始,以最近的{{ end }}结尾

 
  1.  
    # 下面的循环是根据.Values.ingress.tls下的内容焕然出一个hosts的列表
  2.  
    {{- range .Values.ingress.tls }}
  3.  
    - hosts:
  4.  
    {{- range .hosts }}
  5.  
    - {{ . | quote }}
  6.  
    {{- end }}
  7.  
     
 

 

 

 

helm安装mysql演示

上面讲解了许多,还是以一个具体的例子来实践展示,由于helm使用的镜像都是默认从docker.io下载,国内网络可能无法访问,所以还是先下载下来演示

1.helm安装前的准备

安装之前,先通过 helm inspect values azure/mysql 命令查看安装之前需要做哪些准备。其中有一部分是关于存储的。

 
  1.  
    root@k8s-master:~/longhorn# helm inspect values azure/mysql
  2.  
    ## mysql image version
  3.  
    ## ref: https://hub.docker.com/r/library/mysql/tags/
  4.  
    ....
  5.  
    ## Persist data to a persistent volume
  6.  
    persistence:
  7.  
    enabled: true
  8.  
    ## database data Persistent Volume Storage Class
  9.  
    ## If defined, storageClassName: <storageClass>
  10.  
    ## If set to "-", storageClassName: "", which disables dynamic provisioning
  11.  
    ## If undefined (the default) or set to null, no storageClassName spec is
  12.  
    ## set, choosing the default provisioner. (gp2 on AWS, standard on
  13.  
    ## GKE, AWS & OpenStack)
  14.  
    ##
  15.  
    # storageClass: "-"
  16.  
    accessMode: ReadWriteOnce
  17.  
    size: 8Gi
  18.  
    annotations: {}
  19.  
    ....
 

上从面的内容得知,chart 定义了一个 PersistentVolumeClaim,申请 8G 的 PersistentVolume。由于我们的实验环境不支持动态供给,所以得预先创建好相应的 PV
看出来需要8G的磁盘空间。这里可以通过pv/pvc,也可以使用之前演示的longhorn。本文中就直接采用longhorn作为后端来演示。

2.手动创建pv

之前已经在k8s-node01这台服务器安装了nfs服务器,安装步骤可以看之前的pv/pvc章节。

        1.创建一个新的文件夹当做mysql的挂载点

 
  1.  
    # 创建共享目录
  2.  
    sudo mkdir -p /data/my_mysql
  3.  
    sudo chmod 777 /data/my_mysql
  4.  
     
  5.  
    # 配置导出规则(/etc/exports)
  6.  
    echo "/data/my_mysql *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
  7.  
     
  8.  
    # 应用配置
  9.  
    sudo exportfs -a
  10.  
    sudo systemctl restart nfs-kernel-server
 

        2.编写pv的yaml文件

 
  1.  
    # 查看pv.yaml
  2.  
    root@k8s-master:~/helm/my_mysql# cat pv.yaml
  3.  
    apiVersion: v1
  4.  
    kind: PersistentVolume
  5.  
    metadata:
  6.  
    name: mysql-pv
  7.  
    spec:
  8.  
    capacity:
  9.  
    storage: 10Gi
  10.  
    accessModes:
  11.  
    - ReadWriteMany
  12.  
    # storageClassName: nfs
  13.  
    persistentVolumeReclaimPolicy: Retain
  14.  
    nfs:
  15.  
    path: /data/my_mysql
  16.  
    server: 172.21.176.4
  17.  
    readOnly: false
  18.  
     
  19.  
     
  20.  
     
  21.  
    root@k8s-master:~/helm# kubectl apply -f pv.yaml
  22.  
    persistentvolume/mysql-pv created
  23.  
     
  24.  
    # 查看创建的pv
  25.  
    root@k8s-master:~/helm# kubectl get pv
  26.  
    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
  27.  
    mysql-pv 10Gi RWX Retain Available <unset> 14s
  28.  
    root@k8s-master:~/helm#
 

 

3.下载并修改mysql的helm文件

下载并install

 
  1.  
    # 在线搜索mysql源
  2.  
    root@k8s-master:~/helm# helm search repo mysql
  3.  
    NAME CHART VERSION APP VERSION DESCRIPTION
  4.  
    azure/mysql 1.6.9 5.7.30 DEPRECATED - Fast, reliable, scalable, and easy...
  5.  
     
  6.  
    ...
  7.  
     
  8.  
    # 默认在线mysql安装命令
  9.  
    # helm install my-mysql azure/mysql #镜像原因,国内无法拉取镜像
  10.  
     
  11.  
    # 由于镜像源默认都是用的docker.io,在线安装无法拉去镜像,所以先将azure源下的mysql pull下来到本地
  12.  
    root@k8s-master:~/helm# helm pull azure/mysql
  13.  
    root@k8s-master:~/helm# ls
  14.  
    mysql-1.6.9.tgz
  15.  
     
  16.  
    # 解压
  17.  
    root@k8s-master:~/helm# tar -xzvf mysql-1.6.9.tgz
  18.  
    mysql/Chart.yaml
  19.  
    mysql/values.yaml
  20.  
    mysql/templates/NOTES.txt
  21.  
    mysql/templates/_helpers.tpl
  22.  
    mysql/templates/configurationFiles-configmap.yaml
  23.  
    mysql/templates/deployment.yaml
  24.  
    mysql/templates/initializationFiles-configmap.yaml
  25.  
    mysql/templates/pvc.yaml
  26.  
    mysql/templates/secrets.yaml
  27.  
    mysql/templates/serviceaccount.yaml
  28.  
    mysql/templates/servicemonitor.yaml
  29.  
    mysql/templates/svc.yaml
  30.  
    mysql/templates/tests/test-configmap.yaml
  31.  
    mysql/templates/tests/test.yaml
  32.  
    mysql/.helmignore
  33.  
    mysql/README.md
  34.  
     
  35.  
     
  36.  
     
  37.  
    # 修改values.yaml中镜像地址
  38.  
    image: "mysql"
  39.  
    imageTag: "5.7.30"
  40.  
     
  41.  
    busybox:
  42.  
    image: "busybox"
  43.  
    tag: "1.32"
  44.  
     
  45.  
    ======修改为======
  46.  
     
  47.  
    image: "m.daocloud.io/docker.io/mysql"
  48.  
    imageTag: "5.7.30"
  49.  
     
  50.  
    busybox:
  51.  
    image: "m.daocloud.io/docker.io/busybox"
  52.  
    tag: "1.32"
  53.  
     
  54.  
     
  55.  
    # 修改service部分ClusterIP改为NodePort
  56.  
    service:
  57.  
    annotations: {}
  58.  
    ## Specify a service type
  59.  
    ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
  60.  
    type: ClusterIP
  61.  
    port: 3306
  62.  
    # nodePort: 32000
  63.  
    ======修改为=========
  64.  
    service:
  65.  
    annotations: {}
  66.  
    ## Specify a service type
  67.  
    ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
  68.  
    type: NodePort
  69.  
    port: 3306
  70.  
    nodePort: 32000
  71.  
     
  72.  
     
  73.  
     
  74.  
     
  75.  
    # helm install my-mysql mysql命令开始安装
  76.  
    root@k8s-master:~/helm# helm install my-mysql mysql
  77.  
    WARNING: This chart is deprecated
  78.  
    NAME: my-mysql
  79.  
    LAST DEPLOYED: Mon Apr 7 14:41:03 2025
  80.  
    NAMESPACE: default
  81.  
    STATUS: deployed
  82.  
    REVISION: 1
  83.  
    NOTES:
  84.  
    MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
  85.  
    my-mysql.default.svc.cluster.local
  86.  
     
  87.  
    To get your root password run:
  88.  
     
  89.  
    MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)
  90.  
     
  91.  
    To connect to your database:
  92.  
     
  93.  
    1. Run an Ubuntu pod that you can use as a client:
  94.  
     
  95.  
    kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il
  96.  
     
  97.  
    2. Install the mysql client:
  98.  
     
  99.  
    $ apt-get update && apt-get install mysql-client -y
  100.  
     
  101.  
    3. Connect using the mysql cli, then provide your password:
  102.  
    $ mysql -h my-mysql -p
  103.  
     
  104.  
    To connect to your database directly from outside the K8s cluster:
  105.  
    MYSQL_HOST=127.0.0.1
  106.  
    MYSQL_PORT=3306
  107.  
     
  108.  
    # Execute the following command to route the connection:
  109.  
    kubectl port-forward svc/my-mysql 3306
  110.  
     
  111.  
    mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
  112.  
     
  113.  
     
  114.  
    # 通过helm list 查看状态
  115.  
    root@k8s-master:~/helm# helm list
  116.  
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
  117.  
    my-mysql default 1 2025-04-08 16:42:20.457513002 +0800 CST deployed mysql-1.6.9 5.7.30
  118.  
     
  119.  
     
  120.  
    # 通过kubectl查看状态
  121.  
    root@k8s-master:~/helm# kubectl get pod
  122.  
    NAME READY STATUS RESTARTS AGE
  123.  
    my-mysql-578494b569-8dwst 1/1 Running 0 68s
  124.  
     
  125.  
     
  126.  
     
 

4.验证mysql

根据helm的提示查看密码

 
  1.  
    # 查看mysql密码
  2.  
    root@k8s-master:~/helm# echo $(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)
  3.  
    cFF8cfv3ke
  4.  
     
  5.  
     
  6.  
    # 进入容器查看mysql状态
  7.  
    root@k8s-master:~/helm# kubectl exec -it my-mysql-578494b569-8dwst -- /bin/bash
  8.  
    Defaulted container "my-mysql" out of: my-mysql, remove-lost-found (init)
  9.  
    root@my-mysql-578494b569-8dwst:/# mysql -uroot -p
  10.  
    Enter password:
  11.  
    Welcome to the MySQL monitor. Commands end with ; or \g.
  12.  
    Your MySQL connection id is 29
  13.  
    Server version: 5.7.30 MySQL Community Server (GPL)
  14.  
     
  15.  
    Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
  16.  
     
  17.  
    Oracle is a registered trademark of Oracle Corporation and/or its
  18.  
    affiliates. Other names may be trademarks of their respective
  19.  
    owners.
  20.  
     
  21.  
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  22.  
     
  23.  
    mysql> show databases;
  24.  
    +--------------------+
  25.  
    | Database |
  26.  
    +--------------------+
  27.  
    | information_schema |
  28.  
    | mysql |
  29.  
    | performance_schema |
  30.  
    | sys |
  31.  
    +--------------------+
  32.  
    4 rows in set (0.01 sec)
  33.  
     
  34.  
    mysql>
 

 

 

5.验证helm的渲染

        在上面的例子中,修改过了镜像地址,现在通过 kubectl get deployments.apps -oyaml 命令将deployment生成yaml格式。查看刚才的values.yaml中的值是否渲染到了deployment.yaml中.

 
  1.  
    root@k8s-master:~/helm# kubectl get deployments.apps -oyaml
  2.  
    apiVersion: v1
  3.  
    items:
  4.  
    - apiVersion: apps/v1
  5.  
    kind: Deployment
  6.  
    .....
  7.  
    image: m.daocloud.io/docker.io/mysql:5.7.30
  8.  
    .....
 

再查看的values.yaml中的service的端口修改是否渲染到了svc.yaml中.是否渲染出了NodePort类型的32000端口

 
  1.  
    root@k8s-master:~/helm# kubectl get svc
  2.  
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3.  
    kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
  4.  
    my-mysql NodePort 10.102.63.219 <none> 3306:32000/TCP 4s
 

 2025,每天10分钟,跟我学K8S(四十)- Helm (三)- 创建一个自己的helm应用_helm 安装自己应用-CSDN博客

        前面讲解了很多helm的知识点,今天创建一个自己的helm案例,在实操中进一步熟悉helm的使用。

        httpbin.org是我在工作中经常用的到一个网站,它可以显示返回用户的IP等一系列主机头想要的信息。官方也很贴心的制作了镜像,方便我们在本地使用,本次将用它为例,通过helm创建一个本地的httpbin的pod。

创建httpbin的heml例子

1.创建目录,并且创建一个默认的helm目录结构

 
  1.  
    root@k8s-master:~/helm# mkdir -vp helmtest
  2.  
    mkdir: created directory 'helmtest'
  3.  
    root@k8s-master:~/helm# cd helmtest/
  4.  
    root@k8s-master:~/helm/helmtest# helm create myapp01
  5.  
    Creating myapp01
  6.  
    root@k8s-master:~/helm/helmtest# tree myapp01/
  7.  
    myapp01/
  8.  
    ├── charts
  9.  
    ├── Chart.yaml
  10.  
    ├── templates
  11.  
    │   ├── deployment.yaml
  12.  
    │   ├── _helpers.tpl
  13.  
    │   ├── hpa.yaml
  14.  
    │   ├── ingress.yaml
  15.  
    │   ├── NOTES.txt
  16.  
    │   ├── serviceaccount.yaml
  17.  
    │   ├── service.yaml
  18.  
    │   └── tests
  19.  
    │   └── test-connection.yaml
  20.  
    └── values.yaml
 

2.修改配置文件

修改 myapp01/value.yaml

(镜像、ingress、server等信息)

 
  1.  
    image:
  2.  
    repository: nginx #镜像地址
  3.  
    # This sets the pull policy for images.
  4.  
    pullPolicy: IfNotPresent
  5.  
    # Overrides the image tag whose default is the chart appVersion.
  6.  
    tag: " "
  7.  
    ====修改为====
  8.  
    image:
  9.  
    repository: m.daocloud.io/docker.io/kennethreitz/httpbin #镜像地址
  10.  
    # This sets the pull policy for images.
  11.  
    pullPolicy: IfNotPresent
  12.  
    # Overrides the image tag whose default is the chart appVersion.
  13.  
    tag: "latest"
  14.  
     
  15.  
    ...
  16.  
     
  17.  
    service:
  18.  
    type: ClusterIP
  19.  
    port: 80
  20.  
    ====修改为====
  21.  
    service:
  22.  
    type: NodePort #这里不改也可以
  23.  
    port: 80 #容器的端口
  24.  
    targetPort: 80 #暴露容器80对应server的端口
  25.  
     
  26.  
    ...
  27.  
     
  28.  
    ingress:
  29.  
    enabled: false
  30.  
    className: ""
  31.  
    annotations: {}
  32.  
    # kubernetes.io/ingress.class: nginx
  33.  
    # kubernetes.io/tls-acme: "true"
  34.  
    hosts:
  35.  
    - host: chart-example.local
  36.  
    paths:
  37.  
    - path: /
  38.  
    pathType: ImplementationSpecific
  39.  
    tls: []
  40.  
    # - secretName: chart-example-tls
  41.  
    # hosts:
  42.  
    # - chart-example.local
  43.  
     
  44.  
    ====修改为====
  45.  
    ingress:
  46.  
    enabled: true #修改了这里
  47.  
    className: ""
  48.  
    annotations: {}
  49.  
    kubernetes.io/ingress.class: nginx #修改了这里
  50.  
    # 开启use-regex,启用path的正则匹配
  51.  
    nginx.ingress.kubernetes.io/use-regex: "true" #修改了这里
  52.  
     
  53.  
    # kubernetes.io/tls-acme: "true"
  54.  
    hosts:
  55.  
    - host: www.2025helm.com #修改了这里
  56.  
    paths:
  57.  
    - path: /
  58.  
    pathType: ImplementationSpecific
  59.  
    tls: []
  60.  
    # - secretName: chart-example-tls
  61.  
    # hosts:
  62.  
    # - chart-example.local
  63.  
     
  64.  
    ...
  65.  
     
  66.  
     
  67.  
    由于一般镜像没有自检功能,所以这一段注释
  68.  
    livenessProbe:
  69.  
    httpGet:
  70.  
    path: /
  71.  
    port: http
  72.  
    readinessProbe:
  73.  
    httpGet:
  74.  
    path: /
  75.  
    port: http
  76.  
    ====修改为====
  77.  
    #livenessProbe:
  78.  
    # httpGet:
  79.  
    # path: /
  80.  
    # port: http
  81.  
    #readinessProbe:
  82.  
    # httpGet:
  83.  
    # path: /
  84.  
    # port: http
 

修改 myapp01/Chart.yaml

(版本号等信息)

 
  1.  
    # 这里可以修改名字,这里就不做修改了
  2.  
    name: myapp01
  3.  
     
  4.  
    # 修改版本号
  5.  
    appVersion: "1.16.0"
  6.  
    ====修改为====
  7.  
    appVersion: "202503"
 

修改 myapp01/templates/service.yaml

(servers的targetPort信息)

 
  1.  
    spec:
  2.  
    type: {{ .Values.service.type }}
  3.  
    ports:
  4.  
    - port: {{ .Values.service.port }}
  5.  
    targetPort: http
  6.  
    protocol: TCP
  7.  
    name: http
  8.  
    ====修改为====
  9.  
    spec:
  10.  
    type: {{ .Values.service.type }}
  11.  
    ports:
  12.  
    - port: {{ .Values.service.port }}
  13.  
    targetPort: {{ .Values.service.targetPort}} #修改这里
  14.  
    protocol: TCP
  15.  
    name: http
 

 

 

修改 myapp01/templates/NOTES.txt 

(安装后,显示的提示)

由于启用了ingress,如果跑成功会显示下面输入的内容

3.干跑一下看下配置是否正确

 

 
  1.  
    root@k8s-master:~/helm/helmtest# helm install --dry-run --debug myapp01 myapp01/
  2.  
    install.go:225: 2025-04-08 18:50:56.924811149 +0800 CST m=+0.204651618 [debug] Original chart version: ""
  3.  
    install.go:242: 2025-04-08 18:50:56.925029701 +0800 CST m=+0.204870168 [debug] CHART PATH: /root/helm/helmtest/myapp01
  4.  
     
  5.  
    NAME: myapp01
  6.  
    LAST DEPLOYED: Tue Apr 8 18:50:56 2025
  7.  
    NAMESPACE: default
  8.  
    STATUS: pending-install
  9.  
    REVISION: 1
  10.  
    USER-SUPPLIED VALUES:
  11.  
    {}
  12.  
     
  13.  
    ...
  14.  
     
  15.  
    NOTES:
  16.  
    1. Get the application URL by running these commands:
  17.  
    http://www.2025helm.com/
  18.  
    "If successful, you will see this message" #修改了这里
 

4.使用命令开始安装

 
  1.  
    root@k8s-master:~/helm/helmtest# helm install myapp01 myapp01/
  2.  
    NAME: myapp01
  3.  
    LAST DEPLOYED: Tue Apr 8 19:27:34 2025
  4.  
    NAMESPACE: default
  5.  
    STATUS: deployed
  6.  
    REVISION: 1
  7.  
    NOTES:
  8.  
    1. Get the application URL by running these commands:
  9.  
    http://www.2025helm.com/
  10.  
    "If successful, you will see this message" #修改了这里
 

5.测试

查看helm状态和版本号

 
  1.  
    root@k8s-master:~/helm/helmtest# helm list
  2.  
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
  3.  
    myapp01 default 1 2025-04-08 19:27:34.588330558 +0800 CST deployed myapp01-0.1.0 202503
 

查看svc端口

 
  1.  
    root@k8s-master:~/helm/helmtest# kubectl get svc
  2.  
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3.  
    kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
  4.  
    myapp01 NodePort 10.96.228.21 <none> 80:30680/TCP 39s
 

查看ingress

 
  1.  
    root@k8s-master:~/helm/helmtest# kubectl get ingress
  2.  
    NAME CLASS HOSTS ADDRESS PORTS AGE
  3.  
    myapp01 <none> www.2025helm.com 80 30s
 

修改hosts后测试

 
  1.  
    root@k8s-master:~/helm/helmtest# curl http://www.2025helm.com/ip
  2.  
    {
  3.  
    "origin": "172.21.176.3"
  4.  
    }
 

6.升级版本和回滚

升级版本

修改myapp01/Chart.yaml

 
  1.  
    appVersion: "202503"
  2.  
    ====修改为====
  3.  
    appVersion: "202504"
 

升级命令  helm upgrade myapp01 myapp01

版本变成了202504

 
  1.  
    root@k8s-master:~/helm/helmtest# helm upgrade myapp01 myapp01
  2.  
    Release "myapp01" has been upgraded. Happy Helming!
  3.  
    NAME: myapp01
  4.  
    LAST DEPLOYED: Tue Apr 8 20:15:19 2025
  5.  
    NAMESPACE: default
  6.  
    STATUS: deployed
  7.  
    REVISION: 2
  8.  
    NOTES:
  9.  
    1. Get the application URL by running these commands:
  10.  
    http://www.2025helm.com/
  11.  
    "If successful, you will see this message" #修改了这里
  12.  
    root@k8s-master:~/helm/helmtest#
  13.  
    root@k8s-master:~/helm/helmtest# helm list
  14.  
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
  15.  
    myapp01 default 2 2025-04-08 20:15:19.996340164 +0800 CST deployed myapp01-0.1.0 202504
 

查看历史版本

可以看到现在已经有2个版本了

 
  1.  
    root@k8s-master:~/helm/helmtest# helm history myapp01
  2.  
    REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
  3.  
    1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
  4.  
    2 Tue Apr 8 20:15:19 2025 deployed myapp01-0.1.0 202504 Upgrade complete
 

回滚版本

helm rollback myapp01 <REVISION>

 
  1.  
    # 查看目前REVISION版本为2, APP VERSION为202504
  2.  
    root@k8s-master:~/helm/helmtest# helm history myapp01
  3.  
    REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
  4.  
    1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
  5.  
    2 Tue Apr 8 20:15:19 2025 deployed myapp01-0.1.0 202504 Upgrade complete
  6.  
     
  7.  
    # 这里的1为通过history 查看到的REVISION
  8.  
    root@k8s-master:~/helm/helmtest# helm rollback myapp01 1
  9.  
    Rollback was a success! Happy Helming!
  10.  
     
  11.  
    # 查看目前REVISION版本为3, APP VERSION又回滚为202503
  12.  
    root@k8s-master:~/helm/helmtest# helm history myapp01
  13.  
    REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
  14.  
    1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
  15.  
    2 Tue Apr 8 20:15:19 2025 superseded myapp01-0.1.0 202504 Upgrade complete
  16.  
    3 Tue Apr 8 20:17:53 2025 deployed myapp01-0.1.0 202503 Rollback to 1
 

 

        至此我们自己创建的Helm案例讲解告一段落,现在helm的使用越来越多,甚至很多第三方都已经只支持helm安装,所以学好helm很重要,后面我们也会继续在实战中再次使用!

 

posted @ 2025-07-17 11:29  CharyGao  阅读(22)  评论(0)    收藏  举报