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文件演示
-
apiVersion: v1
-
kind: Pod
-
metadata:
-
name: hostpath-demo
-
spec:
-
containers:
-
- name: nginx
-
image: m.daocloud.io/docker.io/nginx
-
command: ["sh", "-c", "tail -f /dev/null"]
-
volumeMounts:
-
- name: node-logs
-
mountPath: /host-logs
-
volumes:
-
- name: node-logs
-
hostPath:
-
path: /var/log # 节点上的路径
-
type: DirectoryOrCreate # 路径类型(见下文说明)
2. 路径类型(type 字段)
| 类型 | 说明 |
|---|---|
Directory |
路径必须为已存在的目录,否则 Pod 启动失败 |
DirectoryOrCreate |
路径不存在时自动创建目录(权限默认为 0755,属主为 kubelet) |
File |
路径必须为已存在的文件,否则 Pod 启动失败 |
FileOrCreate |
路径不存在时自动创建空文件(权限 0644,属主为 kubelet) |
Socket |
路径必须为已存在的 Unix 套接字 |
CharDevice |
路径必须为已存在的字符设备 |
BlockDevice |
路径必须为已存在的块设备 |
3. 结果验证

三、典型使用场景
1. 收集节点日志
启动一个日志收集的pod,共享节点的/var/log,并且将这个目录进行收集
-
volumes:
-
- name: node-log
-
hostPath:
-
path: /var/log
-
type: Directory
- 用途:Sidecar 容器读取节点日志并上传到日志系统(如 ELK)。
2. 硬件监控
启动一个监控的pod,共享节点的/sys,并且将这个目录下的指标进行收集
-
volumes:
-
- name: sys-dir
-
hostPath:
-
path: /sys
-
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 的关系
-
Admin[管理员创建 PV/StorageClass] --> PV
-
User[用户创建 PVC] -->|匹配条件| PVC
-
PVC -->|动态绑定| PV((动态生成的 PV))
-
Pod -->|挂载| PVC
二、配置示例
为了演示方便,采用 NFS 这种存储资源作为后端存储,在k8s-node01(172.21.176.4)这个节点上安装NFS
需要注意的是,虽然只是在k8s-node01一台服务器上挂载NFS,但是所有的节点都是需要安装NFS服务的。也就是需要(apt-get install nfs-kernel-server)
-
# 安装 NFS 服务端 这一步需要所有服务器运行
-
sudo apt-get install nfs-kernel-server
-
-
# 创建共享目录
-
sudo mkdir -p /data/nfs_share
-
sudo chmod 777 /data/nfs_share
-
-
# 配置导出规则(/etc/exports)
-
echo "/data/nfs_share *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
-
-
# 应用配置
-
sudo exportfs -a
-
sudo systemctl restart nfs-kernel-server
1. 静态供给示例
创建 PV:
-
apiVersion: v1
-
kind: PersistentVolume
-
metadata:
-
name: nfs-pv
-
spec:
-
capacity:
-
storage: 10Gi
-
accessModes:
-
- ReadWriteMany
-
storageClassName: nfs
-
persistentVolumeReclaimPolicy: Retain
-
nfs:
-
path: /data/nfs_share
-
server: 172.21.176.4
-
readOnly: false
创建 PVC:
-
apiVersion: v1
-
kind: PersistentVolumeClaim
-
metadata:
-
name: nfs-pvc
-
spec:
-
storageClassName: nfs
-
accessModes:
-
- ReadWriteMany
-
resources:
-
requests:
-
storage: 5Gi
Pod 挂载 PVC:
-
apiVersion: v1
-
kind: Pod
-
metadata:
-
name: web-server
-
spec:
-
containers:
-
- name: nginx
-
image: m.daocloud.io/docker.io/nginx
-
volumeMounts:
-
- name: data
-
mountPath: /usr/share/nginx/html
-
volumes:
-
- name: data
-
persistentVolumeClaim:
-
claimName: nfs-pvc
查看演示结果:

① 创建pv
② 创建pvc
③ 创建pod挂载pvc
④ 查看pv,pvc 这里面包含一些pv,pvc的属性参数具体查看下文
⑤ 查看创建成功的pod
三、关键配置参数
1. PV 配置参数
| 参数 | 说明 |
|---|---|
capacity.storage |
存储容量(如 10Gi) |
|
访问模式
|
|
|
|
|
|
RWX 存储卷可被多个节点上的多个 Pod 以读写模式挂载 多 Pod 并发读写(如日志共享目录) |
|
|
回收策略
|
保留 PV 和底层存储数据,需手动清理。PV 状态变为 |
|
随着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 权限)
-
# rbac.yaml
-
# ServiceAccount 权限
-
apiVersion: v1
-
kind: ServiceAccount
-
metadata:
-
name: nfs-provisioner
-
namespace: default
-
---
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRole
-
metadata:
-
name: nfs-provisioner-runner
-
rules:
-
- apiGroups: [""]
-
resources: ["endpoints"]
-
verbs: ["get", "list", "watch", "create", "update", "patch"]
-
- apiGroups: [""]
-
resources: ["persistentvolumes"]
-
verbs: ["get", "list", "watch", "create", "delete"]
-
- apiGroups: [""]
-
resources: ["persistentvolumeclaims"]
-
verbs: ["get", "list", "watch", "update"]
-
- apiGroups: ["storage.k8s.io"]
-
resources: ["storageclasses"]
-
verbs: ["get", "list", "watch"]
-
---
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRoleBinding
-
metadata:
-
name: run-nfs-provisioner
-
subjects:
-
- kind: ServiceAccount
-
name: nfs-provisioner
-
namespace: default
-
roleRef:
-
kind: ClusterRole
-
name: nfs-provisioner-runner
-
apiGroup: rbac.authorization.k8s.io
上面是一个RBAC的创建过程,后面会有具体章节进行讲解,这里只做简单的说明。总共分为3部分。
-
1.创建一个SA,名为nfs-provisioner
-
-
2.创建一个ClusterRole,名为nfs-provisioner-role,他有以下权限
-
-
对resources: ["endpoints"] 拥有["get", "list", "watch", "create", "update", "patch"]的权限
-
对resources: ["persistentvolumes"] 拥有["get", "list", "watch", "create", "delete"]的权限
-
对resources: ["persistentvolumeclaims"]用有["get", "list", "watch", "update"]的权限
-
对resources: ["storageclasses"]拥有["get", "list", "watch"]的权限
-
-
3.创建一个ClusterRoleBinding,名为nfs-provisioner-binding,它将nfs-provisioner这个SA绑定到nfs-provisioner-role的权限上。
2. NFS Provisioner 控制器
由于原生 NFS 不支持动态卷分配,需使用 nfs-subdir-external-provisioner 实现动态 PV 创建。
-
# nfs-provisioner.yaml
-
apiVersion: apps/v1
-
kind: Deployment
-
metadata:
-
name: nfs-provisioner
-
namespace: default
-
spec:
-
replicas: 1
-
selector:
-
matchLabels:
-
app: nfs-provisioner
-
strategy:
-
type: Recreate
-
template:
-
metadata:
-
labels:
-
app: nfs-provisioner
-
spec:
-
serviceAccount: nfs-provisioner
-
containers:
-
- name: nfs-provisioner
-
image: k8s.m.daocloud.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
-
volumeMounts:
-
- name: nfs-client-root
-
mountPath: /persistentvolumes
-
env:
-
- name: PROVISIONER_NAME
-
value: k8s-sigs.io/nfs-subdir-external-provisioner # 注意这里的值要和StorageClass里面的provisioner: nfs-provisioner保持一致
-
- name: NFS_SERVER
-
value: 172.21.176.4 # 替换为你的NFS服务器IP
-
- name: NFS_PATH
-
value: /data/nfs_share # 替换为NFS共享路径
-
volumes:
-
- name: nfs-client-root
-
nfs:
-
server: 172.21.176.4 # 同上
-
path: /data/nfs_share # 同上
3. StorageClass 定义
-
# storageclass.yaml
-
apiVersion: storage.k8s.io/v1
-
kind: StorageClass
-
metadata:
-
name: nfs-storage
-
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 注意这里的值要和上面的里面的name: PROVISIONER_NAME 的值保持一致
-
parameters:
-
archiveOnDelete: "false" # 删除PVC时是否保留数据目录
-
reclaimPolicy: Delete # 或 Retain
4. PVC 申请存储
-
# pvc.yaml
-
apiVersion: v1
-
kind: PersistentVolumeClaim
-
metadata:
-
name: nfs-pvc
-
spec:
-
storageClassName: nfs-storage # 必须与StorageClass名称匹配
-
accessModes:
-
- ReadWriteMany
-
resources:
-
requests:
-
storage: 10Gi
5. Deployment 挂载 PVC
-
# deployment.yaml
-
apiVersion: apps/v1
-
kind: Deployment
-
metadata:
-
name: nfs-web-app
-
spec:
-
replicas: 2
-
selector:
-
matchLabels:
-
app: nfs-web
-
template:
-
metadata:
-
labels:
-
app: nfs-web
-
spec:
-
containers:
-
- name: web
-
image: m.daocloud.io/docker.io/nginx:alpine
-
volumeMounts:
-
- name: nfs-volume
-
mountPath: /usr/share/nginx/html
-
volumes:
-
- name: nfs-volume
-
persistentVolumeClaim:
-
claimName: nfs-pvc
二、部署流程说明
1. 部署 NFS 服务器
确保 /data/nfs 目录已通过 rw,sync,no_subtree_check 参数导出
上一章节已经在k8s-node01的服务器上面设置好了

2.应用 RBAC 和 Provisioner
-
kubectl apply -f rbac.yaml
-
kubectl apply -f nfs-provisioner.yaml
-
-
# 通过 # kubectl get pod 查看pod,如果有报错可以通过describe或者log来查看报错内容
-
NAME READY STATUS RESTARTS AGE
-
nfs-provisioner-d7cc848df-xspjz 1/1 Running 0 15m
3.创建 StorageClass
-
kubectl apply -f storageclass.yaml
-
-
-
# 通过下面命令查看是否创建成功
-
# kubectl get storageclasses.storage.k8s.io
-
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
-
nfs-storage k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 47m
4.申请 PVC
-
kubectl apply -f pvc.yaml
-
-
-
# 通过命令得到pvc,此时应该是Bound 的状态,pv也自动创建成功
-
# kubectl get pvc,pv
-
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
-
persistentvolumeclaim/nfs-pvc Bound pvc-fd38b271-06b1-497b-a2dc-dafe82d45d72 10Gi RWX nfs-storage <unset> 52m
-
-
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
-
persistentvolume/pvc-fd38b271-06b1-497b-a2dc-dafe82d45d72 10Gi RWX Delete Bound default/nfs-pvc nfs-storage <unset> 16m
5.部署应用
-
kubectl apply -f deployment.yaml
-
-
# 通过命令查看新创建的pod
-
# kubectl get pod
-
NAME READY STATUS RESTARTS AGE
-
nfs-provisioner-d7cc848df-xspjz 1/1 Running 0 17m
-
nfs-web-app-7b7cf4454-bhlrn 1/1 Running 0 41m
-
nfs-web-app-7b7cf4454-dktj8 1/1 Running 0 41m
三、验证数据持久化
1.进入任意 Pod 写入测试文件:
-
kubectl exec -it <pod-name> -- sh -c "echo 'Hello NFS' > /usr/share/nginx/html/test.txt"
-
-
# kubectl exec -it nfs-web-app-7b7cf4454-bhlrn -- sh -c "echo 'Hello NFS' > /usr/share/nginx/html/test.txt"
2.删除 Pod 后重新进入另外一个 Pod查看:
-
kubectl exec -it <new-pod-name> -- cat /usr/share/nginx/html/test.txt # 应看到文件内容
-
-
# kubectl exec -it nfs-web-app-7b7cf4454-dktj8 -- cat /usr/share/nginx/html/test.txt
-
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分布式存储平台,可以在任意基础设施上运行。
github地址:https://github.com/longhorn/longhorn
https://github.com/longhorn/longhorn
部署longhorn
1.安装插件
-
# CentOS/RHEL
-
yum install -y iscsi-initiator-utils
-
systemctl enable iscsid --now
-
-
# Ubuntu/Debian
-
apt-get install -y open-iscsi
-
systemctl enable open-iscsi --now
-
-
# 验证安装
-
which iscsiadm # 应输出:/usr/sbin/iscsiadm
2.下载yaml文件并修改
-
# 下载yaml文件 (202503月最新版)
-
# wget https://github.com/longhorn/longhorn/releases/download/v1.8.1/longhorn.yaml
-
-
-
-
-
# 修改标注内容,开放longhron-ui对外,方便访问管理
-
---
-
kind: Service
-
apiVersion: v1
-
metadata:
-
labels:
-
app: longhorn-ui
-
name: longhorn-frontend
-
namespace: longhorn-system
-
spec:
-
type: NodePort #这里改为nodeport
-
selector:
-
app: longhorn-ui
-
ports:
-
- name: http
-
port: 80
-
targetPort: http
-
nodePort: 30080 #修改nodeport对外端口
-
---
-
-
-
-
# 修改镜像地址1
-
# cat longhorn.yaml |grep "image:"
-
image: longhornio/longhorn-manager:master-head
-
image: longhornio/longhorn-share-manager:master-head
-
image: longhornio/longhorn-manager:master-head
-
image: longhornio/longhorn-manager:master-head
-
image: longhornio/longhorn-ui:master-head
-
修改为
-
-
image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
-
image: m.daocloud.io/docker.io/longhornio/longhorn-share-manager:master-head
-
image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
-
image: m.daocloud.io/docker.io/longhornio/longhorn-manager:master-head
-
image: m.daocloud.io/docker.io/longhornio/longhorn-ui:master-head
-
-
-
# 修改镜像地址2
-
command:
-
- longhorn-manager
-
- -d
-
- daemon
-
- --engine-image
-
- "longhornio/longhorn-engine:v1.8.1"
-
- --instance-manager-image
-
- "longhornio/longhorn-instance-manager:v1.8.1"
-
- --share-manager-image
-
- "longhornio/longhorn-share-manager:v1.8.1"
-
- --backing-image-manager-image
-
- "longhornio/backing-image-manager:v1.8.1"
-
- --support-bundle-manager-image
-
- "longhornio/support-bundle-kit:v0.0.52"
-
- --manager-image
-
- "longhornio/longhorn-manager:v1.8.1"
-
-
修改为
-
command:
-
- longhorn-manager
-
- -d
-
- daemon
-
- --engine-image
-
- "m.daocloud.io/docker.io/longhornio/longhorn-engine:v1.8.1"
-
- --instance-manager-image
-
- "m.daocloud.io/docker.io/longhornio/longhorn-instance-manager:v1.8.1"
-
- --share-manager-image
-
- "m.daocloud.io/docker.io/longhornio/longhorn-share-manager:v1.8.1"
-
- --backing-image-manager-image
-
- "m.daocloud.io/docker.io/longhornio/backing-image-manager:v1.8.1"
-
- --support-bundle-manager-image
-
- "m.daocloud.io/docker.io/longhornio/support-bundle-kit:v0.0.52"
-
- --manager-image
-
- "m.daocloud.io/docker.io/longhornio/longhorn-manager:v1.8.1"
-
-
-
# 修改镜像地址3
-
- name: CSI_ATTACHER_IMAGE
-
value: "longhornio/csi-attacher:v4.8.1"
-
- name: CSI_PROVISIONER_IMAGE
-
value: "longhornio/csi-provisioner:v5.2.0"
-
- name: CSI_NODE_DRIVER_REGISTRAR_IMAGE
-
value: "longhornio/csi-node-driver-registrar:v2.13.0"
-
- name: CSI_RESIZER_IMAGE
-
value: "longhornio/csi-resizer:v1.13.2"
-
- name: CSI_SNAPSHOTTER_IMAGE
-
value: "longhornio/csi-snapshotter:v8.2.0"
-
- name: CSI_LIVENESS_PROBE_IMAGE
-
value: "longhornio/livenessprobe:v2.15.0"
-
修改为
-
- name: CSI_ATTACHER_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/csi-attacher:v4.8.1"
-
- name: CSI_PROVISIONER_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/csi-provisioner:v5.2.0"
-
- name: CSI_NODE_DRIVER_REGISTRAR_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/csi-node-driver-registrar:v2.13.0"
-
- name: CSI_RESIZER_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/csi-resizer:v1.13.2"
-
- name: CSI_SNAPSHOTTER_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/csi-snapshotter:v8.2.0"
-
- name: CSI_LIVENESS_PROBE_IMAGE
-
value: "m.daocloud.io/docker.io/longhornio/livenessprobe:v2.15.0"
2.应用yaml文件
可以看到创建了一个 longhorn-system 的namespace和一大堆的资源

如果使用的是VMware虚拟机,可能会有个报错
-
# journalctl -u multipathd -f
-
-- Logs begin at Thu 2025-02-06 18:06:45 CST. --
-
Mar 28 18:02:54 k8s-master multipathd[741]: sda: failed to get sysfs uid: Invalid argument
-
Mar 28 18:02:54 k8s-master multipathd[741]: sda: failed to get sgio uid: No such file or directory
-
Mar 28 18:02:59 k8s-master multipathd[741]: sda: add missing path
-
Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get udev uid: Invalid argument
-
Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get sysfs uid: Invalid argument
-
Mar 28 18:02:59 k8s-master multipathd[741]: sda: failed to get sgio uid: No such file or directory
-
Mar 28 18:03:04 k8s-master multipathd[741]: sda: add missing path
-
-
-
# 解决办法 编辑配置文件
-
sudo vi /etc/multipath.conf
-
-
# 添加以下内容
-
blacklist {
-
devnode "^sda"
-
}
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
-
apiVersion: v1
-
kind: PersistentVolumeClaim
-
metadata:
-
name: mysql-pv-claim
-
labels:
-
type: longhorn
-
app: example
-
spec:
-
storageClassName: longhorn #类型为longhorn
-
accessModes:
-
- ReadWriteOnce
-
resources:
-
requests:
-
storage: 5Gi
2.创建一个mysql.yaml
-
apiVersion: apps/v1
-
kind: Deployment
-
metadata:
-
name: my-mysql
-
labels:
-
app: example
-
spec:
-
selector:
-
matchLabels:
-
app: example
-
tier: mysql
-
strategy:
-
type: Recreate
-
template:
-
metadata:
-
labels:
-
app: example
-
tier: mysql
-
spec:
-
containers:
-
- image: m.daocloud.io/docker.io/mysql:5.6
-
name: mysql
-
env:
-
- name: MYSQL_ROOT_PASSWORD
-
value: password
-
ports:
-
- containerPort: 3306
-
name: mysql
-
volumeMounts:
-
- name: mysql-persistent-storage
-
mountPath: /var/lib/mysql
-
volumes:
-
- name: mysql-persistent-storage
-
persistentVolumeClaim:
-
claimName: mysql-pv-claim #对应pvc的名字
应用后查看pod,pv,pvc
通过下图可以看到,pvc已经绑定成功

mysql写入数据后,删除pod
-
root@k8s-master:~/longhorn# kubectl exec -it my-mysql-7f8f897d85-4zmpx -- /bin/bash
-
root@my-mysql-7f8f897d85-4zmpx:/# mysql -u root -p mysql
-
Enter password: #密码为yaml文件中设置的password
-
Reading table information for completion of table and column names
-
You can turn off this feature to get a quicker startup with -A
-
-
Welcome to the MySQL monitor. Commands end with ; or \g.
-
Your MySQL connection id is 1
-
Server version: 5.6.51 MySQL Community Server (GPL)
-
-
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
-
-
Oracle is a registered trademark of Oracle Corporation and/or its
-
affiliates. Other names may be trademarks of their respective
-
owners.
-
-
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-
-
mysql> create database k8s; #创建一个K8s的数据库
-
Query OK, 1 row affected (0.00 sec)
-
-
mysql> exit
-
Bye
-
root@my-mysql-7f8f897d85-4zmpx:/# exit
-
exit
删除这个mysql pod
-
root@k8s-master:~/longhorn# kubectl delete pod my-mysql-7f8f897d85-4zmpx
-
pod "my-mysql-7f8f897d85-4zmpx" deleted
大约一分钟之后,我们将再次寻找新的容器名称,连接到该容器名称,看看我们的数据库是否仍然存在,发现新的pod依然使用了之前的存储卷,并且数据还在。
-
root@k8s-master:~/longhorn# kubectl get pods | grep mysql
-
my-mysql-7f8f897d85-hkrp9 1/1 Running 0 27s
-
root@k8s-master:~/longhorn# kubectl exec -it my-mysql-7f8f897d85-hkrp9 -- /bin/bash
-
root@my-mysql-7f8f897d85-hkrp9:/# mysql -u root -p mysql
-
Enter password:
-
Reading table information for completion of table and column names
-
You can turn off this feature to get a quicker startup with -A
-
-
Welcome to the MySQL monitor. Commands end with ; or \g.
-
Your MySQL connection id is 1
-
Server version: 5.6.51 MySQL Community Server (GPL)
-
-
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
-
-
Oracle is a registered trademark of Oracle Corporation and/or its
-
affiliates. Other names may be trademarks of their respective
-
owners.
-
-
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-
-
mysql> show databases;
-
+---------------------+
-
| Database |
-
+---------------------+
-
| information_schema |
-
| k8s |
-
| #mysql50#lost+found |
-
| mysql |
-
| performance_schema |
-
+---------------------+
-
5 rows in set (0.00 sec)
-
-
mysql>
卸载longhorn
参考官网文档
Longhorn | Documentation
https://longhorn.io/docs/1.8.1/deploy/uninstall/#uninstalling-longhorn-using-kubectl具体步骤如下,记得切换版本号,保持和安装的版本一致
Uninstalling Longhorn using kubectl
-
Create the uninstallation job to clean up CRDs from the system and wait for success:
-
kubectl create -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/uninstall/uninstall.yaml
-
kubectl get job/longhorn-uninstall -n longhorn-system -w
Example output:
-
$ kubectl create -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/uninstall/uninstall.yaml
-
serviceaccount/longhorn-uninstall-service-account created
-
clusterrole.rbac.authorization.k8s.io/longhorn-uninstall-role created
-
clusterrolebinding.rbac.authorization.k8s.io/longhorn-uninstall-bind created
-
job.batch/longhorn-uninstall created
-
-
$ kubectl get job/longhorn-uninstall -n longhorn-system -w
-
NAME COMPLETIONS DURATION AGE
-
longhorn-uninstall 0/1 3s 3s
-
longhorn-uninstall 1/1 20s 20s
-
-
Remove remaining components:
-
kubectl delete -f https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/deploy/longhorn.yaml
-
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 创建能力 |
| 访问模式 | 支持 ReadWriteOnce、ReadOnlyMany、ReadWriteMany |
通过参数定义 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 组合,实现弹性扩展和高可用。
前面学习了Volume的多种类型对象,本章将再讲解一种特殊的资源对象:ConfigMap。
日常许多应用经常会有从配置文件、命令行参数或者环境变量中读取一些配置信息,这些配置信息我们肯定不会直接写死到应用程序中去的,例如有个应用连接redis服务,那redis做了迁移或者修改了密码,这时候还得重新去修改代码,重新制作一个镜像,这肯定是不可取的,而ConfigMap就是来解决这种情况的。
ConfigMap 是 Kubernetes 中用于存储非敏感配置数据的资源对象,通过键值对(Key-Value)形式保存配置信息,支持纯文本、JSON、XML 等多种格式
ConfigMap的功能特性:
其主要功能包括:
- 配置解耦:将应用配置与容器镜像分离,便于独立管理。
- 灵活注入:支持通过环境变量、命令行参数或文件挂载方式注入配置到容器。
- 动态更新:修改 ConfigMap 后,挂载为文件的配置可自动更新(需约 30 秒至 1 分钟),而环境变量需重启 Pod。
特性
- 命名空间级别:仅作用于同一命名空间内的资源。
- 大小限制:单个 ConfigMap 数据总量不超过 1 MiB。
- 键名规范:键名仅允许字母、数字、
-、_或.,且data与binaryData字段的键名不可重复。
1.举例说明
创建configmap
configmap的格式
-
kind: ConfigMap
-
apiVersion: v1
-
metadata:
-
name: cm-demo
-
namespace: default
-
data:
-
key1: value1 #单行配置文件内容1
-
key2: value2 #单行配置文件内容2
-
config.properties: | # 多行配置文件内容3
-
db.host=127.0.0.1
-
db.port=3306
1.通过命令行创建configmap
通过kubectl create configmap -h 的方式获取提示
-
Examples:
-
# Create a new config map named my-config based on folder bar
-
kubectl create configmap my-config --from-file=path/to/bar
-
-
# Create a new config map named my-config with specified keys instead of file basenames on disk
-
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
-
-
# Create a new config map named my-config with key1=config1 and key2=config2
-
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
-
-
# Create a new config map named my-config from the key=value pairs in the file
-
kubectl create configmap my-config --from-file=path/to/bar
-
-
# Create a new config map named my-config from an env file
-
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,直接在命令行中定义键值对
键:key1、key2
值:config1、config2
场景:快速注入简单配置(如数据库地址、日志级别)
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"
-
# cat cm1.yaml
-
-
apiVersion: v1
-
kind: ConfigMap
-
metadata:
-
name: app-config #这个configmap的名字,后面可以通过环境变量的方式挂载进入pod的yaml文件
-
data:
-
config.properties: | # 多行配置文件内容
-
db.host=127.0.0.1
-
db.port=3306
-
log.level: "info" # 单行键值对
创建pod识别configmap
1.环境变量的方式注入单行键值对
创建一个pod的yaml文件并且使用上面的cm变量
-
#cat pod1.yaml
-
-
apiVersion: v1
-
kind: Pod
-
metadata:
-
name: app-pod
-
spec:
-
containers:
-
- name: app-container
-
image: m.daocloud.io/docker.io/nginx:latest
-
# 环境变量注入(可选,适用于单值配置)
-
env:
-
- name: LOG_LEVEL
-
valueFrom:
-
configMapKeyRef:
-
name: app-config
-
key: log.level
验证结果,得知$LOG_LEVEL已经注意到新的pod里面
-
root@k8s-master:~# kubectl get pod
-
NAME READY STATUS RESTARTS AGE
-
app-pod 1/1 Running 0 2m57s
-
testcm1-pod 0/1 CreateContainerConfigError 0 36m
-
root@k8s-master:~# kubectl exec -it app-pod -- /bin/bash
-
root@app-pod:/# echo $LOG_LEVEL
-
info

2.挂载配置文件的方式注入多行键值对
-
#cat pod2.yaml
-
-
apiVersion: v1
-
kind: Pod
-
metadata:
-
name: app-pod
-
spec:
-
containers:
-
- name: app-container
-
image: m.daocloud.io/docker.io/nginx
-
volumeMounts:
-
- name: config-volume # 卷名称,需与 volumes 字段对应
-
mountPath: /etc/app-config # 容器内挂载路径
-
volumes:
-
- name: config-volume # 卷名称,与 volumeMounts 对应
-
configMap:
-
name: app-config # 引用的 ConfigMap 名称
-
items: # 可选:筛选并自定义文件名
-
- key: config.properties # 选择 ConfigMap 中的键
-
path: db.conf # 挂载为 /etc/app-config/db.conf
验证结果,发现db.conf已经挂载到指定目录
-
root@k8s-master:~/configmap# kubectl get pod
-
NAME READY STATUS RESTARTS AGE
-
app-pod 1/1 Running 0 41m
-
root@k8s-master:~/configmap# kubectl apply -f pod2.yaml
-
pod/app-pod2 created
-
root@k8s-master:~/configmap#
-
root@k8s-master:~/configmap# kubectl get pod
-
NAME READY STATUS RESTARTS AGE
-
app-pod 1/1 Running 0 41m
-
app-pod2 1/1 Running 0 4s
-
root@k8s-master:~/configmap# kubectl exec -it app-pod2 -- /bin/bash
-
root@app-pod2:/# cat /etc/app-config/db.conf
-
db.host=127.0.0.1
-
db.port=3306

3.通过command的方式注入键值对
-
# cat pod3.yaml
-
apiVersion: v1
-
kind: Pod
-
metadata:
-
name: app-pod3
-
spec:
-
containers:
-
- name: app-pod3
-
image: m.daocloud.io/docker.io/nginx
-
command: [ "/bin/bash", "-c", "echo $(log.level) && sleep 3600" ] #通过命令行输出环境变量显示加载的CM值
-
env:
-
- name: LOG_LEVEL
-
valueFrom:
-
configMapKeyRef:
-
name: app-config
-
key: log.level
-
envFrom:
-
- configMapRef:
-
name: app-config
验证结果,发现db.conf已经挂载到指定目录

4.对比总结
上面举例了ConfigMap 3种注入的方式,具体采用哪一种可以根据项目需求而定。
| 维度 | 环境变量注入 | 挂载配置文件 | Command 注入 |
|---|---|---|---|
| 数据格式 | 单行键值对 | 多行文本/完整文件 | 单行键值对 |
| 动态更新支持 | 需重启 Pod | 自动更新 | 需重启 Pod |
| 配置复杂度 | 低 | 高(支持嵌套结构) | 中(依赖脚本处理) |
| 适用场景 | 简单参数(端口、开关) | 复杂配置(JSON、XML) | 动态生成启动命令 |
| 性能影响 | 无 | 文件 I/O 可能影响性能 |
脚本执行可能增加启动耗时
|
5.选择建议
- 优先挂载配置文件:适用于需动态更新或复杂配置的场景。
- 慎用 Command 注入:仅在必须通过命令拼接参数时使用,避免过度依赖 Shell 脚本。
- 环境变量用于简单配置:如开关、基础参数等无需频繁更新的场景。
通过合理组合这三种方式,可高效管理 Kubernetes 应用的配置,同时平衡灵活性与性能。
2. 高级功能与注意事项
2.1 热更新机制
- Volume 挂载:ConfigMap 更新后,容器内文件自动同步(约 30 秒延迟)。
- 环境变量:需删除并重建 Pod 以生效。
2.2 不可变 ConfigMap
在 Kubernetes 中,将 ConfigMap 设置为不可变(immutable: true)是一种优化配置管理和提升集群稳定性的重要手段。设置了这个字段,就不能通过热更新或者edit的方式去修改更新配置,只能通过删除重建更新配置。
举例:
-
apiVersion: v1
-
kind: ConfigMap
-
metadata:
-
name: immutable-config
-
immutable: true
-
data:
-
key: "value"
2025,每天10分钟,跟我学K8S(三十六)- 对象属性 - Volume - Secret-CSDN博客
上节课学习了ConfigMap,了解了ConfigMap这个资源对象是K8S当中非常重要的一个对象,ConfigMap一般情况下是用来存储一些非安全的配置信息,如果涉及到一些安全相关的数据的话用ConfigMap就不适合了,因为ConfigMap是明文存储的,如果需要加密存储,就需要用到另外一个资源对象了:Secret,Secret用来保存敏感信息,例如密码、API 密钥、TLS 证书等等,将这些信息放在Secret中比放在Pod的定义中或者docker镜像中来说更加安全和灵活。
Secret
Secret 是 Kubernetes 中用于管理敏感信息(如密码、API 密钥、TLS 证书等)的核心资源。其设计目标是避免敏感数据硬编码到 Pod 或镜像中,提升安全性与可维护性。
一、Secret 的核心特性
-
数据安全
- Base64 编码存储:Secret 中的数据默认以 Base64 编码形式保存于 etcd 中,但需注意这并非加密,仅提供基础防护。
- 动态注入:支持通过环境变量或文件挂载方式注入到 Pod 中,无需重启容器即可更新(需重新创建 Pod)。
- 类型化支持:预定义多种类型适配不同场景,例如:
- **
Opaque**:通用键值对存储(如用户名、密码)。 - **
kubernetes.io/tls**:存储 HTTPS 证书和私钥。 - **
kubernetes.io/dockerconfigjson**:私有镜像仓库认证信息。
- **
二、Secret 的创建与使用
1. 创建方式
-
命令行创建:
-
# 通用类型(键值对)
-
kubectl create secret generic my-secret --from-literal=username=root --from-literal=password=password
-
-
# TLS 证书类型
-
kubectl create secret tls my-tls-secret --cert=path/to/cert.pem --key=path/to/key.pem
-
YAML 文件定义:
-
apiVersion: v1
-
kind: Secret
-
metadata:
-
name: db-secret
-
data:
-
username: cm9vdA== # "root" 的 Base64 编码
-
password: cGFzc3dvcmQ= # "password" 的 Base64 编码
2.挂载方式
-
环境变量注入:
-
env:
-
- name: DB_PASSWORD
-
valueFrom:
-
secretKeyRef:
-
name: db-secret
-
key: password
-
文件挂载:
-
volumes:
-
- name: secret-volume
-
secret:
-
secretName: db-secret
-
containers:
-
- volumeMounts:
-
- name: secret-volume
-
mountPath: "/etc/secrets"
3. 数据查看与验证
-
查看 Secret 详情:
-
kubectl get secret my-secret -o yaml # 显示编码后的数据
-
-
# kubectl get secret my-secret -o yaml
-
apiVersion: v1
-
data:
-
password: cGFzc3dvcmQ=
-
username: cm9vdA==
-
kind: Secret
-
metadata:
-
creationTimestamp: "2025-04-02T03:24:44Z"
-
name: my-secret
-
namespace: default
-
resourceVersion: "224361"
-
uid: be74cf70-d200-40de-b064-d3b99340f83f
-
type: Opaque
-
-
-
-
echo "cm9vdA==" | base64 -d # 解码示例
-
-
# echo "cm9vdA==" | base64 -d
-
root
三、举例说明
1.常规案例
1.创建secret
-
# cat secret.yaml
-
apiVersion: v1
-
kind: Secret
-
metadata:
-
name: db-secret
-
data:
-
username: cm9vdA== # "root" 的 Base64 编码
-
password: cGFzc3dvcmQ= # "password" 的 Base64 编码
2. 创建deployment.yaml
-
# cat deployment.yaml
-
apiVersion: apps/v1
-
kind: Deployment
-
metadata:
-
name: webapp-deployment-secret
-
labels:
-
app: webapp
-
spec:
-
replicas: 3
-
selector:
-
matchLabels:
-
app: webapp
-
template:
-
metadata:
-
labels:
-
app: webapp
-
spec:
-
containers:
-
- name: webapp
-
image: m.daocloud.io/docker.io/nginx
-
# 方式一:环境变量注入
-
env:
-
- name: DB_USERNAME
-
valueFrom:
-
secretKeyRef:
-
name: db-secret
-
key: username
-
- name: DB_PASSWORD
-
valueFrom:
-
secretKeyRef:
-
name: db-secret
-
key: password
-
-
# 方式二:文件挂载
-
volumeMounts:
-
- name: secret-volume
-
mountPath: "/etc/db-credentials"
-
readOnly: true
-
volumes:
-
- name: secret-volume
-
secret:
-
secretName: db-secret
3.应用并验证
通过下图可以看出来,两种方式的secret都使用成功

①② 应用2个yaml文件
③ 查看pod
④ 进入任意一个pod
⑤⑥ 查看通过环境变量方式挂载secret 显示 用户密码
⑦⑧ 查看通过文件方式挂载secret 显示 现在用户密码
2.登录私有仓库的案例
上面举例说明了secret的使用,下面再举例一个用的最多的,也就是通过secret登录自己的私有仓库下载镜像
1. 创建 Docker Hub 认证 Secret
-
#方式1, 通过kubectl create 创建一个secret
-
kubectl create secret docker-registry dockerhub-secret \
-
--docker-server=https://index.docker.io/v1/ \
-
--docker-username=your-username \
-
--docker-password=your-password \
-
--docker-email=your-email@example.com
-
-
-
#方式2,通过yaml文件创建
-
apiVersion: v1
-
kind: Secret
-
metadata:
-
name: dockerhub-secret
-
namespace: default
-
type: kubernetes.io/dockerconfigjson
-
data:
-
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ5b3VyLXVzZXJuYW1lIiwicGFzc3dvcmQiOiJ5b3VyLXBhc3N3b3JkIiwiZW1haWwiOiJ5b3VyLWVtYWlsQGV4YW1wbGUuY29tIiwiYXV0aCI6ImVXOTFjaTExYzJWeWJtRnRaVHA1YjNWeUxYQmhjM04zYjNKayJ9fX0=
-
上面方式2 .dockerconfigjson后面一大截可能看起来会不知道什么意思,其实解码后能知道,是一串json键值对,包含方式1里面的仓库地址,用户密码等信息
-
#解码
-
# echo "eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ5b3VyLXVzZXJuYW1lIiwicGFzc3dvcmQiOiJ5b3VyLXBhc3N3b3JkIiwiZW1haWwiOiJ5b3VyLWVtYWlsQGV4YW1wbGUuY29tIiwiYXV0aCI6ImVXOTFjaTExYzJWeWJtRnRaVHA1YjNWeUxYQmhjM04zYjNKayJ9fX0=" |base64 -d
-
{"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 名称一致
-
apiVersion: apps/v1
-
kind: Deployment
-
metadata:
-
name: private-image-deployment
-
spec:
-
replicas: 2
-
selector:
-
matchLabels:
-
app: private-app
-
template:
-
metadata:
-
labels:
-
app: private-app
-
spec:
-
containers:
-
- name: app-container
-
image: your-dockerhub-username/private-image:latest # 私有镜像地址
-
ports:
-
- containerPort: 8080
-
imagePullSecrets: # 关键配置:声明拉取镜像的凭证
-
- name: dockerhub-secret # 必须与 Secret 名称一致
3.验证
由于这里的用户信息都是为了举例填写的,会登录失败,所以结果会拉取失败,大家在日常使用中修改为自己的仓库地址信息即可。

四、常见问题与解决方案
-
Secret 更新后未生效
- 原因:已运行的 Pod 不会自动同步 Secret 变更。
- 解决:重建 Pod 或使用支持热加载的应用框架(如 Nginx Reload)。
-
Base64 编码错误
- 注意点:使用
echo -n避免换行符干扰编码结果。 - 验证命令:
kubectl get secret <name> -o jsonpath='{.data}' | jq .检查数据完整性。
- 注意点:使用
-
Secret 挂载权限问题
- 设置文件权限:在 Volume 挂载时指定
defaultMode参数限制文件访问权限。
- 设置文件权限:在 Volume 挂载时指定
五、与 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 的增删改查)。
- 示例配置:
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: Role
-
metadata:
-
namespace: default
-
name: pod-reader
-
rules:
-
- apiGroups: [""] # 核心 API 组(如 Pod、Node 等)
-
resources: ["pods"]
-
verbs: ["get", "list", "watch"] # 允许的操作类型
2.角色绑定(RoleBinding)
将 Role 或 ClusterRole 绑定到主体(如用户、服务账户),限定在特定命名空间内生效。
- 示例:将
pod-reader角色绑定至服务账户cicd-sa:
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: RoleBinding
-
metadata:
-
name: cicd-pod-access
-
namespace: default
-
subjects:
-
- kind: ServiceAccount
-
name: cicd-sa
-
roleRef:
-
kind: Role
-
name: pod-reader
3.集群角色(ClusterRole)
- 作用范围:全局生效,适用于跨命名空间或集群级资源(如节点、存储卷)。
- 典型场景:授予跨命名空间的 Deployment 只读权限。
- 示例配置
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRole
-
metadata:
-
name: cluster-pod-reader
-
rules:
-
- apiGroups: [""] # 核心 API 组(如 Pod、Node 等)
-
resources: ["pods", "nodes"]
-
verbs: ["get", "list", "watch"] # 允许的操作类型
4.集群角色绑定(ClusterRoleBinding)
赋予主体集群级权限(如管理所有命名空间的 Secrets)。
示例:将 cluster-pod-reader 角色绑定至服务账户 dev-team:
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRoleBinding
-
metadata:
-
name: cluster-pod-reader-binding
-
subjects:
-
- kind: Group
-
name: dev-team # 用户组名称(需与认证系统集成)
-
apiGroup: rbac.authorization.k8s.io
-
roleRef:
-
kind: ClusterRole
-
name: cluster-pod-reader # 引用的 ClusterRole 名称
-
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)
-
-
openssl genrsa -out dev-team.key 2048
-
-
-
openssl req -new -key dev-team.key -out dev-team.csr -subj "/CN=dev-team/O=dev-group"
-
使用集群 CA 签发用户证书
-
# 使用 Kubernetes 集群 CA 签发证书(有效期 365 天)
-
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 文件
-
# 设置集群信息
-
kubectl config set-cluster kubernetes \
-
--certificate-authority=/etc/kubernetes/pki/ca.crt \
-
--embed-certs=true \
-
--server=https://<API-Server-IP>:6443 \
-
--kubeconfig=dev-team.kubeconfig
-
-
# 添加用户凭证
-
kubectl config set-credentials dev-team \
-
--client-certificate=dev-team.crt \
-
--client-key=dev-team.key \
-
--embed-certs=true \
-
--kubeconfig=dev-team.kubeconfig
-
-
# 创建上下文并设为默认
-
kubectl config set-context dev-team-context \
-
--cluster=kubernetes \
-
--user=dev-team \
-
--kubeconfig=dev-team.kubeconfig
-
kubectl config use-context dev-team-context --kubeconfig=dev-team.kubeconfig
2.创建Role:dev-team-role
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: Role
-
metadata:
-
namespace: dev
-
name: dev-team-role
-
rules:
-
- apiGroups: [""]
-
resources: ["pods", "services"] # 允许访问 Pod 和 Service
-
verbs: ["get", "list", "watch"] # 仅授予只读权限
3.创建RoleBinging:dev-team-binding
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: RoleBinding
-
metadata:
-
name: dev-team-binding
-
namespace: dev
-
subjects:
-
- kind: User
-
name: dev-team # 绑定对应的用户名
-
apiGroup: rbac.authorization.k8s.io
-
roleRef:
-
kind: Role
-
name: dev-team-role #绑定对应的role名称
-
apiGroup: rbac.authorization.k8s.io
4. 应用配置
-
kubectl apply -f dev-team-role.yaml
-
kubectl apply -f dev-team-binding.yaml
5.权限验证
1. 验证权限范围
-
# 检查 dev 命名空间 Pod/Service 访问权限
-
kubectl auth can-i get pods --namespace=dev --kubeconfig=dev-team.kubeconfig # 预期返回 yes
-
kubectl auth can-i create pods --namespace=dev --kubeconfig=dev-team.kubeconfig # 预期返回 no
-
-
# 检查其他命名空间权限
-
kubectl auth can-i get pods --namespace=prod --kubeconfig=dev-team.kubeconfig # 预期返回 no
2. 实际操作测试
-
# 查看 dev 命名空间的 Pod 和 Service(成功)
-
kubectl get pods,svc -n dev --kubeconfig=dev-team.kubeconfig
-
-
# 尝试删除 Pod(失败)
-
kubectl delete pod -n dev nginx-6b9f9cd485-456jb --kubeconfig=dev-team.kubeconfig
-
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
-
# 生成私钥(RSA 2048位)
-
openssl genrsa -out boss.key 2048
-
-
# 创建证书签名请求(CN 必须与用户名一致)
-
openssl req -new -key boss.key -out boss.csr -subj "/CN=boss/O=admin-group"
-
-
# 使用集群 CA 签发证书(有效期 365 天)
-
openssl x509 -req -in boss.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out boss.crt -days 365
-
-
# 生成 kubeconfig 文件
-
kubectl config set-cluster kubernetes \
-
--certificate-authority=/etc/kubernetes/pki/ca.crt \
-
--embed-certs=true \
-
--server=https://172.21.176.3:6443 \
-
--kubeconfig=boss.kubeconfig
-
-
kubectl config set-credentials boss \
-
--client-certificate=boss.crt \
-
--client-key=boss.key \
-
--embed-certs=true \
-
--kubeconfig=boss.kubeconfig
-
-
kubectl config set-context boss-context \
-
--cluster=kubernetes \
-
--user=boss \
-
--kubeconfig=boss.kubeconfig
-
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的最大权限
-
# cat new-cluster-admin.yaml
-
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRole
-
metadata:
-
name: new-cluster-admin
-
rules:
-
- apiGroups: ["*"] # 覆盖所有 API 组(包括核心组、apps、networking 等)
-
resources: ["*"] # 所有资源类型(如 pods、nodes、secrets、services 等)
-
verbs: ["*"] # 允许所有操作(get、list、create、delete、patch 等)
-
- nonResourceURLs: ["*"] # 非资源端点(如 /healthz、/metrics、/api 等)
-
verbs: ["*"] # 允许访问所有非资源 URL
2、绑定new-cluster-admin
-
# cluster-admin-binding.yaml
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRoleBinding
-
metadata:
-
name: boss-cluster-admin
-
subjects:
-
- kind: User
-
name: boss
-
apiGroup: rbac.authorization.k8s.io
-
roleRef:
-
kind: ClusterRole
-
name: new-cluster-admin # 预置超级管理员角色
-
apiGroup: rbac.authorization.k8s.io
3、绑定
-
# kubectl apply -f new-cluster-admin.yaml
-
clusterrole.rbac.authorization.k8s.io/new-cluster-admin unchanged
-
# kubectl apply -f new-cluster-admin-binding.yaml
-
clusterrolebinding.rbac.authorization.k8s.io/boss-cluster-admin created
2.2 绑定内置ClusterRole,通过 ClusterRoleBinding 直接关联用户:
1、直接绑定 cluster-admin-binding
-
# cluster-admin-binding.yaml
-
apiVersion: rbac.authorization.k8s.io/v1
-
kind: ClusterRoleBinding
-
metadata:
-
name: boss-cluster-admin
-
subjects:
-
- kind: User
-
name: boss
-
apiGroup: rbac.authorization.k8s.io
-
roleRef:
-
kind: ClusterRole
-
name: cluster-admin # 预置超级管理员角色
-
apiGroup: rbac.authorization.k8s.io
2、绑定cluster-admin-binding
kubectl apply -f cluster-admin-binding.yaml
3、权限验证
3.1. 基础权限检查
-
# 验证集群级权限
-
kubectl auth can-i '*' '*' --kubeconfig=boss.kubeconfig # 预期返回 yes
-
-
# 验证跨命名空间操作
-
kubectl auth can-i delete pods -n kube-system --kubeconfig=boss.kubeconfig # 预期返回 yes
3.2. 实际操作测试
-
# 创建/删除集群级资源(如 Node 查看)
-
kubectl get nodes --kubeconfig=boss.kubeconfig
-
-
# 操作敏感资源(如 Secrets)
-
kubectl get secrets -n kube-system --kubeconfig=boss.kubeconfig
-
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 工作原理与授权流程
-
权限校验流程
- 请求接收:用户或服务账户通过
kubectl或 API 发起操作请求。 - 鉴权匹配:API Server 根据 RBAC 规则验证主体是否具备执行操作的权限。
- 权限决策:若权限匹配则放行,否则拒绝并记录审计日志。
- 请求接收:用户或服务账户通过
-
规则定义逻辑
- 资源与操作:通过
apiGroups、resources、verbs字段精确控制可访问的 API 资源及操作类型。 - 例外控制:通过
resourceNames限制对特定资源实例的操作(如禁止删除critical-configConfigMap)。
- 资源与操作:通过
三、RBAC 应用场景与最佳实践
-
典型应用场景
- CI/CD 流水线权限:授予服务账户管理 Pod 的
get/list/watch权限,支持自动化部署。 - 多团队协作:通过命名空间隔离不同团队的资源访问权限。
- 安全合规:限制运维人员仅能查看日志,禁止修改生产环境资源。
- CI/CD 流水线权限:授予服务账户管理 Pod 的
-
最佳实践
- 最小权限原则:避免使用
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 的核心概念
-
Chart
- 定义:Helm 的“软件包”,包含应用部署所需的所有 Kubernetes 资源模板(如 Deployment、Service)及默认配置(
values.yaml)。 - 目录结构:
Chart.yaml:元数据文件(名称、版本、依赖等)。templates/:存放 Kubernetes 资源模板(支持 Go 模板语法)。values.yaml:默认配置参数,支持动态注入。
- 定义:Helm 的“软件包”,包含应用部署所需的所有 Kubernetes 资源模板(如 Deployment、Service)及默认配置(
-
Release
- 实例化:每次通过 Helm 安装 Chart 会生成唯一的 Release,记录版本状态和配置差异。
- 版本追踪:支持查看历史版本及回滚(如
helm rollback <release> <version>)。
-
Repository
- 仓库类型:公共仓库(如
stable、bitnami)和私有仓库(如 Harbor),用于存储和分发 Chart。 - 仓库管理:通过
helm repo add/update添加或同步仓库索引。
- 仓库类型:公共仓库(如
二、Helm 的核心功能与优势
-
简化复杂应用部署
- 模板化配置:通过变量替换(如
{{ .Values.image.tag }})实现多环境配置复用。 - 依赖管理:支持定义子 Chart(
charts/目录)及版本约束。
- 模板化配置:通过变量替换(如
-
生命周期管理
- 安装/升级:使用
helm install/upgrade部署或更新应用,自动处理资源顺序。 - 回滚机制:基于版本快照快速恢复至历史状态(依赖
helm history和helm rollback)。
- 安装/升级:使用
-
动态资源生成
- 钩子(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
-
# 创建临时目录并下载
-
root@k8s-master:~# mkdir -vp helm
-
mkdir: created directory 'helm'
-
root@k8s-master:~# cd helm/
-
root@k8s-master:~/helm# wget https://rancher-mirror.rancher.cn/helm/v3.17.2/helm-v3.17.2-linux-amd64.tar.gz
-
-
# 解压并将二进制文件移至/usr/local/bin
-
root@k8s-master:~/helm# tar zxvf helm-v3.17.2-linux-amd64.tar.gz
-
linux-amd64/
-
linux-amd64/LICENSE
-
linux-amd64/helm
-
linux-amd64/README.md
-
-
-
root@k8s-master:~/helm# cd linux-amd64/
-
root@k8s-master:~/helm/linux-amd64# ls
-
helm LICENSE README.md
-
root@k8s-master:~/helm/linux-amd64# mv helm /usr/local/bin/
-
-
# 版本验证
-
root@k8s-master:~/helm/linux-amd64# helm version
-
version.BuildInfo{Version:"v3.17.2", GitCommit:"cc0bbbd6d6276b83880042c1ecb34087e84d41eb", GitTreeState:"clean", GoVersion:"go1.23.7"}
-
- 更换国内仓库
由于helm默认仓库是使用国外镜像,所以会导致很多时候速度慢甚至无法下载,将镜像仓库修改为阿里云仓库
-
# 查看仓库源 为空
-
helm repo list
-
# 新增仓库源,可以添加多个地址,
-
helm repo add azure http://mirror.azure.cn/kubernetes/charts/
-
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
-
-
# 配置国内Chart仓库
-
-
阿里云仓库(https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts) #已经很久不更新
-
微软仓库(http://mirror.azure.cn/kubernetes/charts/) #推荐
-
官方仓库(https://hub.kubeapps.com/charts/incubator)官方chart仓库,国内有点不好使。
-
-
-
# 搜索redis镜像
-
# helm search repo redis
-
NAME CHART VERSION APP VERSION DESCRIPTION
-
aliyun/redis 1.1.15 4.0.8 Open source, advanced key-value store. It is of...
-
aliyun/redis-ha 2.0.1 Highly available Redis cluster with multiple se...
-
azure/prometheus-redis-exporter 3.5.1 1.3.4 DEPRECATED Prometheus exporter for Redis metrics
-
azure/redis 10.5.7 5.0.7 DEPRECATED Open source, advanced key-value stor...
-
azure/redis-ha 4.4.6 5.0.6 DEPRECATED - Highly available Kubernetes implem...
-
aliyun/sensu 0.2.0 Sensu monitoring framework backed by the Redis ...
-
azure/sensu 0.2.5 0.28 DEPRECATED Sensu monitoring framework backed by...
-
-
2.使用Helm
创建一个新的helm Chart
-
# 创建一个myapp的自定义应用
-
root@k8s-master:~/helm# helm create myapp
-
Creating myapp
-
-
# 进入目录
-
root@k8s-master:~/helm# cd myapp/
-
-
# 查看目录结构
-
root@k8s-master:~/helm/myapp# tree
-
.
-
├── charts
-
├── Chart.yaml
-
├── templates
-
│ ├── deployment.yaml
-
│ ├── _helpers.tpl
-
│ ├── hpa.yaml
-
│ ├── ingress.yaml
-
│ ├── NOTES.txt
-
│ ├── serviceaccount.yaml
-
│ ├── service.yaml
-
│ └── tests
-
│ └── test-connection.yaml
-
└── values.yaml
-
-
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这个服务。
-
root@k8s-master:~/helm# ls
-
helm-v3.17.2-linux-amd64.tar.gz linux-amd64 myapp
-
root@k8s-master:~/helm# helm install myapp myapp
-
NAME: myapp
-
LAST DEPLOYED: Thu Apr 3 14:28:31 2025
-
NAMESPACE: default
-
STATUS: deployed
-
REVISION: 1
-
NOTES:
-
1. Get the application URL by running these commands:
-
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services myapp)
-
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
-
echo http://$NODE_IP:$NODE_PORT
查看helm 下的应用,查看deployment,查看pod
-
root@k8s-master:~/helm# helm list
-
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
-
myapp default 1 2025-04-03 14:33:46.58464117 +0800 CST deployed myapp-0.1.0 1.16.0
-
root@k8s-master:~/helm# kubectl get deployments,pod
-
NAME READY UP-TO-DATE AVAILABLE AGE
-
deployment.apps/myapp 1/1 1 1 21s
-
-
NAME READY STATUS RESTARTS AGE
-
pod/myapp-6c5df5768-nvvcg 1/1 Running 0 21s
查看nginx服务是否对外正常
-
# 获取端口
-
root@k8s-master:~/helm# echo $(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services myapp)
-
32117
-
-
# 获取IP
-
root@k8s-master:~/helm# echo $(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
-
172.21.176.3
-
-
# 通过curl 访问测试
-
root@k8s-master:~/helm# curl 172.21.176.3:32117
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<title>Welcome to nginx!</title>
-
......
4.载这个helm 应用
使用命令 helm uninstall myapp 即可卸载,这里只需要有应用名即可。不需要带目录名,卸载后发现pod也消失了。
-
root@k8s-master:~/helm# helm uninstall myapp
-
release "myapp" uninstalled
-
root@k8s-master:~/helm# helm list
-
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
-
root@k8s-master:~/helm# kubectl get deployments,pod
-
No resources found in default namespace.
2025,每天10分钟,跟我学K8S(三十九)- Helm (二)Helm的结构和案例_helm案例-CSDN博客
前面一章,大概了解了下helm的安装,和创建自定义的应用,本章节,来完整演示一下通过helm安装一个mysql应用的方式,了解一下helm的目录结构及作用。
helm的目录结构
上一章,我们创建了一个myapp的自定义应用,并且知道了他的目录结构
-
# 创建一个myapp的自定义应用
-
root@k8s-master:~/helm# helm create myapp
-
Creating myapp
-
-
# 进入目录
-
root@k8s-master:~/helm# cd myapp/
-
-
# 查看目录结构
-
root@k8s-master:~/helm/myapp# tree
-
.
-
├── charts
-
├── Chart.yaml
-
├── templates
-
│ ├── deployment.yaml
-
│ ├── _helpers.tpl
-
│ ├── hpa.yaml
-
│ ├── ingress.yaml
-
│ ├── NOTES.txt
-
│ ├── serviceaccount.yaml
-
│ ├── service.yaml
-
│ └── tests
-
│ └── test-connection.yaml
-
└── values.yaml
-
-
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 中取值,如果没有定义,则为空。也就是下面的内容
-
repository: m.daocloud.io/docker.io/nginx
-
# This sets the pull policy for images.
-
pullPolicy: IfNotPresent
-
# Overrides the image tag whose default is the chart appVersion.
-
tag: ""
-
-
拼接后内容为
-
image: m.daocloud.io/docker.io/nginx
③ imagePullSecrets: {{- toYaml . | nindent 8 }} 将输入的数据结构转换为 YAML 格式字符串,并且换行后缩进 8 个空格
-
如果 values.yaml 中的 imagePullSecrets: [] 有值
-
则渲染成
-
spec:
-
imagePullSecrets: xx
条件判断
以 templates/hpa.yaml 为例:

这里的if判断语法以 {{ if xxx }}开始,以最近的{{ end }}结尾
-
# 下面的语句就是判断.Values.autoscaling.targetCPUUtilizationPercentage是否存在,如果存在则渲染下面几行的内容
-
-
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
-
- type: Resource
-
resource:
-
name: cpu
-
target:
-
type: Utilization
-
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
-
{{- end }}
-
循环与列表处理
以 templates/ingress.yaml 为例:
这里的if判断语法以 {{ range xxx }}开始,以最近的{{ end }}结尾

-
# 下面的循环是根据.Values.ingress.tls下的内容焕然出一个hosts的列表
-
{{- range .Values.ingress.tls }}
-
- hosts:
-
{{- range .hosts }}
-
- {{ . | quote }}
-
{{- end }}
-
helm安装mysql演示
上面讲解了许多,还是以一个具体的例子来实践展示,由于helm使用的镜像都是默认从docker.io下载,国内网络可能无法访问,所以还是先下载下来演示
1.helm安装前的准备
安装之前,先通过 helm inspect values azure/mysql 命令查看安装之前需要做哪些准备。其中有一部分是关于存储的。
-
root@k8s-master:~/longhorn# helm inspect values azure/mysql
-
## mysql image version
-
## ref: https://hub.docker.com/r/library/mysql/tags/
-
....
-
## Persist data to a persistent volume
-
persistence:
-
enabled: true
-
## database data Persistent Volume Storage Class
-
## If defined, storageClassName: <storageClass>
-
## If set to "-", storageClassName: "", which disables dynamic provisioning
-
## If undefined (the default) or set to null, no storageClassName spec is
-
## set, choosing the default provisioner. (gp2 on AWS, standard on
-
## GKE, AWS & OpenStack)
-
##
-
# storageClass: "-"
-
accessMode: ReadWriteOnce
-
size: 8Gi
-
annotations: {}
-
....
上从面的内容得知,chart 定义了一个 PersistentVolumeClaim,申请 8G 的 PersistentVolume。由于我们的实验环境不支持动态供给,所以得预先创建好相应的 PV
看出来需要8G的磁盘空间。这里可以通过pv/pvc,也可以使用之前演示的longhorn。本文中就直接采用longhorn作为后端来演示。
2.手动创建pv
之前已经在k8s-node01这台服务器安装了nfs服务器,安装步骤可以看之前的pv/pvc章节。
1.创建一个新的文件夹当做mysql的挂载点
-
# 创建共享目录
-
sudo mkdir -p /data/my_mysql
-
sudo chmod 777 /data/my_mysql
-
-
# 配置导出规则(/etc/exports)
-
echo "/data/my_mysql *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
-
-
# 应用配置
-
sudo exportfs -a
-
sudo systemctl restart nfs-kernel-server
2.编写pv的yaml文件
-
# 查看pv.yaml
-
root@k8s-master:~/helm/my_mysql# cat pv.yaml
-
apiVersion: v1
-
kind: PersistentVolume
-
metadata:
-
name: mysql-pv
-
spec:
-
capacity:
-
storage: 10Gi
-
accessModes:
-
- ReadWriteMany
-
# storageClassName: nfs
-
persistentVolumeReclaimPolicy: Retain
-
nfs:
-
path: /data/my_mysql
-
server: 172.21.176.4
-
readOnly: false
-
-
-
-
root@k8s-master:~/helm# kubectl apply -f pv.yaml
-
persistentvolume/mysql-pv created
-
-
# 查看创建的pv
-
root@k8s-master:~/helm# kubectl get pv
-
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
-
mysql-pv 10Gi RWX Retain Available <unset> 14s
-
root@k8s-master:~/helm#
3.下载并修改mysql的helm文件
下载并install
-
# 在线搜索mysql源
-
root@k8s-master:~/helm# helm search repo mysql
-
NAME CHART VERSION APP VERSION DESCRIPTION
-
azure/mysql 1.6.9 5.7.30 DEPRECATED - Fast, reliable, scalable, and easy...
-
-
...
-
-
# 默认在线mysql安装命令
-
# helm install my-mysql azure/mysql #镜像原因,国内无法拉取镜像
-
-
# 由于镜像源默认都是用的docker.io,在线安装无法拉去镜像,所以先将azure源下的mysql pull下来到本地
-
root@k8s-master:~/helm# helm pull azure/mysql
-
root@k8s-master:~/helm# ls
-
mysql-1.6.9.tgz
-
-
# 解压
-
root@k8s-master:~/helm# tar -xzvf mysql-1.6.9.tgz
-
mysql/Chart.yaml
-
mysql/values.yaml
-
mysql/templates/NOTES.txt
-
mysql/templates/_helpers.tpl
-
mysql/templates/configurationFiles-configmap.yaml
-
mysql/templates/deployment.yaml
-
mysql/templates/initializationFiles-configmap.yaml
-
mysql/templates/pvc.yaml
-
mysql/templates/secrets.yaml
-
mysql/templates/serviceaccount.yaml
-
mysql/templates/servicemonitor.yaml
-
mysql/templates/svc.yaml
-
mysql/templates/tests/test-configmap.yaml
-
mysql/templates/tests/test.yaml
-
mysql/.helmignore
-
mysql/README.md
-
-
-
-
# 修改values.yaml中镜像地址
-
image: "mysql"
-
imageTag: "5.7.30"
-
-
busybox:
-
image: "busybox"
-
tag: "1.32"
-
-
======修改为======
-
-
image: "m.daocloud.io/docker.io/mysql"
-
imageTag: "5.7.30"
-
-
busybox:
-
image: "m.daocloud.io/docker.io/busybox"
-
tag: "1.32"
-
-
-
# 修改service部分ClusterIP改为NodePort
-
service:
-
annotations: {}
-
## Specify a service type
-
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
-
type: ClusterIP
-
port: 3306
-
# nodePort: 32000
-
======修改为=========
-
service:
-
annotations: {}
-
## Specify a service type
-
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
-
type: NodePort
-
port: 3306
-
nodePort: 32000
-
-
-
-
-
# helm install my-mysql mysql命令开始安装
-
root@k8s-master:~/helm# helm install my-mysql mysql
-
WARNING: This chart is deprecated
-
NAME: my-mysql
-
LAST DEPLOYED: Mon Apr 7 14:41:03 2025
-
NAMESPACE: default
-
STATUS: deployed
-
REVISION: 1
-
NOTES:
-
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
-
my-mysql.default.svc.cluster.local
-
-
To get your root password run:
-
-
MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)
-
-
To connect to your database:
-
-
1. Run an Ubuntu pod that you can use as a client:
-
-
kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il
-
-
2. Install the mysql client:
-
-
$ apt-get update && apt-get install mysql-client -y
-
-
3. Connect using the mysql cli, then provide your password:
-
$ mysql -h my-mysql -p
-
-
To connect to your database directly from outside the K8s cluster:
-
MYSQL_HOST=127.0.0.1
-
MYSQL_PORT=3306
-
-
# Execute the following command to route the connection:
-
kubectl port-forward svc/my-mysql 3306
-
-
mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
-
-
-
# 通过helm list 查看状态
-
root@k8s-master:~/helm# helm list
-
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
-
my-mysql default 1 2025-04-08 16:42:20.457513002 +0800 CST deployed mysql-1.6.9 5.7.30
-
-
-
# 通过kubectl查看状态
-
root@k8s-master:~/helm# kubectl get pod
-
NAME READY STATUS RESTARTS AGE
-
my-mysql-578494b569-8dwst 1/1 Running 0 68s
-
-
-
4.验证mysql
根据helm的提示查看密码
-
# 查看mysql密码
-
root@k8s-master:~/helm# echo $(kubectl get secret --namespace default my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)
-
cFF8cfv3ke
-
-
-
# 进入容器查看mysql状态
-
root@k8s-master:~/helm# kubectl exec -it my-mysql-578494b569-8dwst -- /bin/bash
-
Defaulted container "my-mysql" out of: my-mysql, remove-lost-found (init)
-
root@my-mysql-578494b569-8dwst:/# mysql -uroot -p
-
Enter password:
-
Welcome to the MySQL monitor. Commands end with ; or \g.
-
Your MySQL connection id is 29
-
Server version: 5.7.30 MySQL Community Server (GPL)
-
-
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
-
-
Oracle is a registered trademark of Oracle Corporation and/or its
-
affiliates. Other names may be trademarks of their respective
-
owners.
-
-
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-
-
mysql> show databases;
-
+--------------------+
-
| Database |
-
+--------------------+
-
| information_schema |
-
| mysql |
-
| performance_schema |
-
| sys |
-
+--------------------+
-
4 rows in set (0.01 sec)
-
-
mysql>

5.验证helm的渲染
在上面的例子中,修改过了镜像地址,现在通过 kubectl get deployments.apps -oyaml 命令将deployment生成yaml格式。查看刚才的values.yaml中的值是否渲染到了deployment.yaml中.
-
root@k8s-master:~/helm# kubectl get deployments.apps -oyaml
-
apiVersion: v1
-
items:
-
- apiVersion: apps/v1
-
kind: Deployment
-
.....
-
image: m.daocloud.io/docker.io/mysql:5.7.30
-
.....
再查看的values.yaml中的service的端口修改是否渲染到了svc.yaml中.是否渲染出了NodePort类型的32000端口
-
root@k8s-master:~/helm# kubectl get svc
-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
-
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
-
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目录结构
-
root@k8s-master:~/helm# mkdir -vp helmtest
-
mkdir: created directory 'helmtest'
-
root@k8s-master:~/helm# cd helmtest/
-
root@k8s-master:~/helm/helmtest# helm create myapp01
-
Creating myapp01
-
root@k8s-master:~/helm/helmtest# tree myapp01/
-
myapp01/
-
├── charts
-
├── Chart.yaml
-
├── templates
-
│ ├── deployment.yaml
-
│ ├── _helpers.tpl
-
│ ├── hpa.yaml
-
│ ├── ingress.yaml
-
│ ├── NOTES.txt
-
│ ├── serviceaccount.yaml
-
│ ├── service.yaml
-
│ └── tests
-
│ └── test-connection.yaml
-
└── values.yaml
2.修改配置文件
修改 myapp01/value.yaml
(镜像、ingress、server等信息)
-
image:
-
repository: nginx #镜像地址
-
# This sets the pull policy for images.
-
pullPolicy: IfNotPresent
-
# Overrides the image tag whose default is the chart appVersion.
-
tag: " "
-
====修改为====
-
image:
-
repository: m.daocloud.io/docker.io/kennethreitz/httpbin #镜像地址
-
# This sets the pull policy for images.
-
pullPolicy: IfNotPresent
-
# Overrides the image tag whose default is the chart appVersion.
-
tag: "latest"
-
-
...
-
-
service:
-
type: ClusterIP
-
port: 80
-
====修改为====
-
service:
-
type: NodePort #这里不改也可以
-
port: 80 #容器的端口
-
targetPort: 80 #暴露容器80对应server的端口
-
-
...
-
-
ingress:
-
enabled: false
-
className: ""
-
annotations: {}
-
# kubernetes.io/ingress.class: nginx
-
# kubernetes.io/tls-acme: "true"
-
hosts:
-
- host: chart-example.local
-
paths:
-
- path: /
-
pathType: ImplementationSpecific
-
tls: []
-
# - secretName: chart-example-tls
-
# hosts:
-
# - chart-example.local
-
-
====修改为====
-
ingress:
-
enabled: true #修改了这里
-
className: ""
-
annotations: {}
-
kubernetes.io/ingress.class: nginx #修改了这里
-
# 开启use-regex,启用path的正则匹配
-
nginx.ingress.kubernetes.io/use-regex: "true" #修改了这里
-
-
# kubernetes.io/tls-acme: "true"
-
hosts:
-
- host: www.2025helm.com #修改了这里
-
paths:
-
- path: /
-
pathType: ImplementationSpecific
-
tls: []
-
# - secretName: chart-example-tls
-
# hosts:
-
# - chart-example.local
-
-
...
-
-
-
由于一般镜像没有自检功能,所以这一段注释
-
livenessProbe:
-
httpGet:
-
path: /
-
port: http
-
readinessProbe:
-
httpGet:
-
path: /
-
port: http
-
====修改为====
-
#livenessProbe:
-
# httpGet:
-
# path: /
-
# port: http
-
#readinessProbe:
-
# httpGet:
-
# path: /
-
# port: http
修改 myapp01/Chart.yaml
(版本号等信息)
-
# 这里可以修改名字,这里就不做修改了
-
name: myapp01
-
-
# 修改版本号
-
appVersion: "1.16.0"
-
====修改为====
-
appVersion: "202503"
修改 myapp01/templates/service.yaml
(servers的targetPort信息)
-
spec:
-
type: {{ .Values.service.type }}
-
ports:
-
- port: {{ .Values.service.port }}
-
targetPort: http
-
protocol: TCP
-
name: http
-
====修改为====
-
spec:
-
type: {{ .Values.service.type }}
-
ports:
-
- port: {{ .Values.service.port }}
-
targetPort: {{ .Values.service.targetPort}} #修改这里
-
protocol: TCP
-
name: http
修改 myapp01/templates/NOTES.txt
(安装后,显示的提示)
由于启用了ingress,如果跑成功会显示下面输入的内容

3.干跑一下看下配置是否正确
-
root@k8s-master:~/helm/helmtest# helm install --dry-run --debug myapp01 myapp01/
-
install.go:225: 2025-04-08 18:50:56.924811149 +0800 CST m=+0.204651618 [debug] Original chart version: ""
-
install.go:242: 2025-04-08 18:50:56.925029701 +0800 CST m=+0.204870168 [debug] CHART PATH: /root/helm/helmtest/myapp01
-
-
NAME: myapp01
-
LAST DEPLOYED: Tue Apr 8 18:50:56 2025
-
NAMESPACE: default
-
STATUS: pending-install
-
REVISION: 1
-
USER-SUPPLIED VALUES:
-
{}
-
-
...
-
-
NOTES:
-
1. Get the application URL by running these commands:
-
http://www.2025helm.com/
-
"If successful, you will see this message" #修改了这里
4.使用命令开始安装
-
root@k8s-master:~/helm/helmtest# helm install myapp01 myapp01/
-
NAME: myapp01
-
LAST DEPLOYED: Tue Apr 8 19:27:34 2025
-
NAMESPACE: default
-
STATUS: deployed
-
REVISION: 1
-
NOTES:
-
1. Get the application URL by running these commands:
-
http://www.2025helm.com/
-
"If successful, you will see this message" #修改了这里
5.测试
查看helm状态和版本号
-
root@k8s-master:~/helm/helmtest# helm list
-
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
-
myapp01 default 1 2025-04-08 19:27:34.588330558 +0800 CST deployed myapp01-0.1.0 202503
查看svc端口
-
root@k8s-master:~/helm/helmtest# kubectl get svc
-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
-
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
-
myapp01 NodePort 10.96.228.21 <none> 80:30680/TCP 39s
查看ingress
-
root@k8s-master:~/helm/helmtest# kubectl get ingress
-
NAME CLASS HOSTS ADDRESS PORTS AGE
-
myapp01 <none> www.2025helm.com 80 30s
修改hosts后测试
-
root@k8s-master:~/helm/helmtest# curl http://www.2025helm.com/ip
-
{
-
"origin": "172.21.176.3"
-
}
6.升级版本和回滚
升级版本
修改myapp01/Chart.yaml
-
appVersion: "202503"
-
====修改为====
-
appVersion: "202504"
升级命令 helm upgrade myapp01 myapp01
版本变成了202504
-
root@k8s-master:~/helm/helmtest# helm upgrade myapp01 myapp01
-
Release "myapp01" has been upgraded. Happy Helming!
-
NAME: myapp01
-
LAST DEPLOYED: Tue Apr 8 20:15:19 2025
-
NAMESPACE: default
-
STATUS: deployed
-
REVISION: 2
-
NOTES:
-
1. Get the application URL by running these commands:
-
http://www.2025helm.com/
-
"If successful, you will see this message" #修改了这里
-
root@k8s-master:~/helm/helmtest#
-
root@k8s-master:~/helm/helmtest# helm list
-
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
-
myapp01 default 2 2025-04-08 20:15:19.996340164 +0800 CST deployed myapp01-0.1.0 202504
查看历史版本
可以看到现在已经有2个版本了
-
root@k8s-master:~/helm/helmtest# helm history myapp01
-
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
-
1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
-
2 Tue Apr 8 20:15:19 2025 deployed myapp01-0.1.0 202504 Upgrade complete
回滚版本
helm rollback myapp01 <REVISION>
-
# 查看目前REVISION版本为2, APP VERSION为202504
-
root@k8s-master:~/helm/helmtest# helm history myapp01
-
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
-
1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
-
2 Tue Apr 8 20:15:19 2025 deployed myapp01-0.1.0 202504 Upgrade complete
-
-
# 这里的1为通过history 查看到的REVISION
-
root@k8s-master:~/helm/helmtest# helm rollback myapp01 1
-
Rollback was a success! Happy Helming!
-
-
# 查看目前REVISION版本为3, APP VERSION又回滚为202503
-
root@k8s-master:~/helm/helmtest# helm history myapp01
-
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
-
1 Tue Apr 8 20:12:48 2025 superseded myapp01-0.1.0 202503 Install complete
-
2 Tue Apr 8 20:15:19 2025 superseded myapp01-0.1.0 202504 Upgrade complete
-
3 Tue Apr 8 20:17:53 2025 deployed myapp01-0.1.0 202503 Rollback to 1
至此我们自己创建的Helm案例讲解告一段落,现在helm的使用越来越多,甚至很多第三方都已经只支持helm安装,所以学好helm很重要,后面我们也会继续在实战中再次使用!


浙公网安备 33010602011771号