Helm 部署 K8s 集群完整笔记
一、整体架构图
plain
┌─────────────────────────────────────────────────────────────────┐
│ 用户层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Docker CLI │ │ kubectl │ │ helm │ │
│ │ (构建镜像) │ │ (管理K8s) │ │ (包管理器) │ │
│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
└─────────┼────────────────┼─────────────────────┼────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ minikube 层 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Docker Desktop (宿主机) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ minikube 容器 (K8s 控制平面) │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ kube-apiserver │ │ kube-scheduler │ │ kube-controller │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ etcd (数据库) │ │ kubelet │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 (Pod) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ camp-auth │ │ camp-web │ │ camp-backend │ │
│ │ (Nginx) │ │ (Nginx) │ │ (FastAPI + SQLite) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
二、文件结构与调用关系
2.1 项目目录结构
plain
kubernetes-microservices/
│
├── docker-compose.yml # Docker Compose 配置(本地开发)
├── docker-compose.ghcr.yml # 使用预构建镜像的 Compose 配置
│
├── helm/ # Helm Chart 目录
│ ├── deploy-helm.sh # Helm 部署脚本(Shell)
│ ├── values-dev.yaml # 开发环境配置
│ ├── values-prod.yaml # 生产环境配置
│ ├── values-local.yaml # 本地自定义配置(我们创建的)
│ │
│ └── camp/ # Helm Chart 包
│ ├── Chart.yaml # Chart 元数据(名称、版本、依赖)
│ ├── values.yaml # 默认配置值
│ │
│ └── templates/ # K8s 资源模板目录
│ ├── _helpers.tpl # 辅助模板函数(镜像名、标签生成)
│ ├── deployment.yaml # Deployment 资源模板
│ ├── service.yaml # Service 资源模板
│ ├── ingress.yaml # Ingress 资源模板
│ ├── configmap.yaml # ConfigMap 资源模板
│ ├── secret.yaml # Secret 资源模板
│ ├── pvc.yaml # PVC 资源模板
│ ├── hpa.yaml # HPA 资源模板
│ ├── resourcequota.yaml # ResourceQuota 资源模板
│ ├── networkpolicy.yaml # NetworkPolicy 资源模板
│ ├── monitoring.yaml # 监控资源模板
│ ├── serviceaccount.yaml # ServiceAccount 资源模板
│ └── notes.txt # 部署后提示信息
│
├── k8s/ # 原生 K8s YAML(手动部署用)
│ ├── deploy.sh # AKS 部署脚本
│ ├── cleanup.sh # AKS 清理脚本
│ ├── namespace.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── persistent-volumes.yaml
│ ├── backend-deployment.yaml
│ ├── web-frontend-deployment.yaml
│ ├── auth-frontend-deployment.yaml
│ ├── ingress.yaml
│ ├── horizontal-pod-autoscaler.yaml
│ ├── resource-quota.yaml
│ ├── network-policy.yaml
│ ├── monitoring.yaml
│ └── kustomization.yaml # Kustomize 配置
│
└── .github/workflows/ # CI/CD
└── build-and-deploy.yml # GitHub Actions 工作流
2.2 Helm 文件调用关系
plain
values-local.yaml (用户自定义配置)
│
▼
┌─────────────────┐
│ helm install │ ──► 读取 Chart.yaml(Chart 元数据)
│ helm upgrade │
└────────┬────────┘
│
▼
┌─────────────────┐
│ values.yaml │ ──► 默认值(被 values-local.yaml 覆盖)
│ (默认值) │
└────────┬────────┘
│
▼
┌─────────────────────────────────────────┐
│ templates/ 目录 │
│ ┌─────────────────────────────────────┐ │
│ │ _helpers.tpl │ │
│ │ ├─ camp.fullname │ │
│ │ ├─ camp.backend.image │ │
│ │ ├─ camp.web.image │ │
│ │ └─ camp.auth.image │ │
│ └─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ deployment.yaml │ │
│ │ ├─ 引用 _helpers.tpl 中的函数 │ │
│ │ ├─ 引用 .Values.backend.resources │ │
│ │ └─ 引用 .Values.config.databaseUrl │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ service.yaml │ │
│ │ ├─ 引用 .Values.backend.service │ │
│ │ └─ 引用 selectorLabels │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ configmap.yaml │ │
│ │ └─ 引用 .Values.config.* │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ secret.yaml │ │
│ │ └─ 引用 .Values.secrets.* │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ ... 其他模板文件 │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ 渲染后的 YAML │ ──► 提交给 kubectl → kube-apiserver
│ (K8s 资源清单) │
└─────────────────┘
2.3 关键文件详解
Chart.yaml --- Chart 元数据
yaml
apiVersion: v2 # Helm 3 使用 v2
name: camp # Chart 名称
description: CAMP Helm Chart
type: application # 应用类型(application/library)
version: 0.1.0 # Chart 版本
appVersion: "1.0" # 应用版本
values.yaml --- 默认值
yaml
# 全局配置
global:
imageRegistry: ""
# 镜像配置
image:
registry: docker.io
repository: nginx
pullPolicy: IfNotPresent
tag: ""
# 副本数
replicaCount:
backend: 2
web: 2
auth: 2
# 后端配置
backend:
name: backend
service:
port: 8000
targetPort: 8000
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
livenessProbe:
httpGet:
path: /test
port: http
readinessProbe:
httpGet:
path: /health
port: http
autoscaling:
enabled: false
persistence:
uploads:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
mountPath: /app/uploads
database:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
mountPath: /app/camp.db
subPath: camp.db
# 前端配置(web/auth 类似)
web:
name: web
service:
port: 80
targetPort: 80
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
# 应用配置
config:
databaseUrl: "sqlite:///app/camp.db"
debug: false
logLevel: info
# 密钥
secrets:
secretKey: ""
jwtSecret: ""
defaultPassword: "admin123"
# 安全上下文
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
podSecurityContext:
fsGroup: 2000
# 资源配额
resourceQuota:
enabled: true
# 网络策略
networkPolicy:
enabled: true
# 监控
monitoring:
enabled: false
_helpers.tpl --- 辅助函数
yaml
{{/*
生成完整名称
*/}}
{{- define "camp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
生成后端镜像名
*/}}
{{- define "camp.backend.image" -}}
{{- $registry := .Values.global.imageRegistry | default .Values.image.registry }}
{{- $repository := .Values.backend.image.repository }}
{{- $tag := .Values.image.tag | default .Chart.AppVersion }}
{{- printf "%s/%s:%s" $registry $repository $tag }}
{{- end }}
三、工具链调用关系
3.1 完整工具链
plain
用户操作
│
├─► docker build ──► 本地镜像
│ │
│ ▼
│ docker images
│ │
│ ▼
│ minikube image load ──► 加载到 minikube
│ │
│ ▼
└─► helm install/upgrade ──► 渲染模板
│
├─► 读取 values.yaml
├─► 读取 values-local.yaml(覆盖)
├─► 渲染 templates/*.yaml
│ │
│ ├─► _helpers.tpl(函数调用)
│ ├─► deployment.yaml
│ ├─► service.yaml
│ └─► ...
│
▼
kubectl apply ──► 提交到 kube-apiserver
│
▼
kube-apiserver ──► 写入 etcd
│
├─► kube-scheduler ──► 选择节点
│
▼
kubelet ──► 创建 Pod
│
▼
containerd/docker ──► 拉取/运行镜像
3.2 各工具职责
Table
| 工具 | 职责 | 类比 |
|---|---|---|
| Docker | 构建、管理容器镜像 | 工厂(生产产品) |
| minikube | 本地运行 K8s 集群 | 迷你数据中心 |
| kubectl | 与 K8s 集群交互 | 遥控器 |
| helm | K8s 包管理器 | apt/yum(软件包管理) |
| kube-apiserver | K8s 控制平面入口 | 前台接待 |
| kube-scheduler | 调度 Pod 到节点 | 调度员 |
| kubelet | 节点上的代理 | 车间主任 |
| etcd | K8s 数据存储 | 数据库 |
四、部署流程详解
4.1 标准部署流程
powershell
# 1. 启动 minikube
minikube start --driver=docker --memory=4096 --cpus=2
# 2. 构建/准备镜像
docker compose build
# 3. 加载镜像到 minikube
minikube image load <image-name>
# 4. 创建命名空间
kubectl create namespace camp
# 5. Helm 部署
helm upgrade --install camp ./camp --values values-local.yaml -n camp
# 6. 验证
kubectl get pods -n camp
helm status camp -n camp
# 7. 端口转发访问
kubectl port-forward svc/camp-auth-service 3000:80 -n camp
4.2 配置覆盖优先级
plain
values.yaml (最低优先级)
│
▼
values-dev.yaml / values-prod.yaml
│
▼
values-local.yaml (最高优先级)
│
▼
--set 命令行参数 (临时最高)
五、所有错误及解决方案
5.1 Helm 安装问题
Table
| 错误 | 原因 | 解决 |
|---|---|---|
helm : 无法将"helm"项识别 |
Helm 未安装或未加入 PATH | 下载安装并添加到 PATH,或使用完整路径 C:\tools\helm\windows-amd64\helm.exe |
5.2 Chart 语法错误
Table
| 错误 | 原因 | 解决 |
|---|---|---|
unexpected <.> in operand |
动态 key 语法不支持 $.Values.(.service).service.port |
改为固定值 number: 80 |
undefined variable "$Values" |
变量名错误,应为 $.Values |
修改为 $.Values |
failed to find unique target for patch |
patch 未指定 namespace | 添加 namespace: camp |
yaml: line 27: mapping values are not allowed |
YAML 缩进错误 | 检查空格/Tab 混用,确保正确缩进 |
5.3 模板渲染错误
Table
| 错误 | 原因 | 解决 |
|---|---|---|
nil pointer evaluating interface {}.Namespace |
循环内部 . 上下文改变 |
使用 $ 引用根上下文:$.Release.Namespace |
error converting YAML to JSON |
模板渲染后 YAML 格式错误 | 检查条件渲染的缩进和结构 |
duplicate "Container" type |
LimitRange 中重复定义 | 合并为单个 type: Container |
5.4 镜像问题
Table
| 错误 | 原因 | 解决 |
|---|---|---|
ImagePullBackOff |
镜像不存在或无法拉取 | 确认镜像名正确,使用 minikube image load 加载本地镜像 |
ErrImagePull |
镜像拉取失败 | 检查网络、镜像仓库权限 |
ErrImageNeverPull |
imagePullPolicy: Never 但镜像不存在 |
确保镜像已加载到 minikube |
| 镜像名重复路径 | _helpers.tpl 中 printf 格式错误 |
修复为 printf "%s/%s:%s" $registry $repository $tag |
5.5 运行时错误
Table
| 错误 | 原因 | 解决 |
|---|---|---|
mkdir() failed (13: Permission denied) |
Nginx 无写入权限 | 禁用 securityContext:securityContext: null |
sqlite3.OperationalError: unable to open database file |
数据库路径错误或权限不足 | 使用默认路径 sqlite:///app/camp.db,禁用 PVC |
container's runAsUser breaks non-root policy |
securityContext 冲突 | 完全禁用 securityContext 和 podSecurityContext |
CreateContainerConfigError |
容器配置错误 | 检查 securityContext、镜像名、环境变量 |
CrashLoopBackOff |
应用启动失败 | 查看日志 kubectl logs,检查健康检查路径 |
Pending |
资源不足或 PVC 未绑定 | 检查节点资源、StorageClass、PVC 状态 |
5.6 存储问题
Table
| 错误 | 原因 | 解决 |
|---|---|---|
storageclass.storage.k8s.io "default" not found |
StorageClass 不存在 | 创建 default StorageClass 或使用 standard |
pod has unbound immediate PersistentVolumeClaims |
PVC 未绑定 | 检查 StorageClass、手动创建 PV、或禁用 PVC |
not a directory: Are you trying to mount a directory onto a file |
subPath 挂载文件到目录 |
去掉 subPath,改为挂载目录 |
六、关键配置文件
6.1 最终可用的 values-local.yaml
yaml
# ============================================
# Helm Values - 本地 minikube 部署配置
# ============================================
# 全局配置
global:
imageRegistry: ghcr.io
# 镜像配置
image:
registry: ghcr.io
repository: kubernetes-microservices # 镜像仓库路径
pullPolicy: Never # 使用本地镜像,不拉取
tag: "latest"
# 副本数配置
replicaCount:
backend: 2
web: 2
auth: 2
# Ingress 配置
ingress:
enabled: false # 禁用 Ingress(本地用端口转发)
# 后端服务配置
backend:
name: backend
service:
port: 8000
targetPort: 8000
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
livenessProbe:
httpGet:
path: /test
port: http
readinessProbe:
httpGet:
path: /health
port: http
autoscaling:
enabled: false # 禁用 HPA(需要 Metrics Server)
persistence:
uploads:
enabled: false # 禁用 PVC,使用 emptyDir
database:
enabled: false # 禁用 PVC,使用 emptyDir
# Web 前端配置
web:
name: web
service:
port: 80
targetPort: 80
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
autoscaling:
enabled: false
# Auth 前端配置
auth:
name: auth
service:
port: 80
targetPort: 80
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
autoscaling:
enabled: false
# 应用配置
config:
databaseUrl: "sqlite:///app/camp.db" # 默认数据库路径
debug: true
logLevel: info
apiV1Prefix: "/api/v1"
appName: "Cloud Asset Management Platform"
appVersion: "1.0.0"
storageType: local
localStoragePath: "/app/uploads"
maxFileSize: "52428800"
corsOrigins: "http://localhost:3004,http://localhost:3000"
pythonUnbuffered: "1"
pythonpath: "/app"
# 密钥配置
secrets:
secretKey: "dev-secret-key"
jwtSecret: "dev-jwt-secret"
defaultPassword: "admin123"
# 安全上下文(本地学习禁用)
securityContext: null
podSecurityContext: null
# 资源配额
resourceQuota:
enabled: false
# 限制范围
limitRange:
enabled: false
# 网络策略
networkPolicy:
enabled: false
# 监控
monitoring:
enabled: false
# 节点选择
nodeSelector: {}
# 容忍
tolerations: []
# 亲和性
affinity: {}
七、常用命令速查
7.1 minikube 管理
bash
# 启动
minikube start --driver=docker --memory=4096 --cpus=2
# 停止
minikube stop
# 删除
minikube delete
# 查看状态
minikube status
# 获取 IP
minikube ip
# 加载镜像
minikube image load <image-name>
# 查看 minikube 中的镜像
minikube ssh -- docker images
# 启用插件
minikube addons enable ingress
minikube addons enable metrics-server
minikube addons enable storage-provisioner
7.2 Helm 管理
bash
# 安装/升级
helm upgrade --install <release-name> ./<chart-path> --values <values-file> -n <namespace>
# 卸载
helm uninstall <release-name> -n <namespace>
# 查看状态
helm status <release-name> -n <namespace>
# 查看历史
helm history <release-name> -n <namespace>
# 回滚
helm rollback <release-name> <revision> -n <namespace>
# 预览渲染
helm template <release-name> ./<chart-path> --values <values-file>
# 检查语法
helm lint ./<chart-path>
7.3 kubectl 管理
bash
# 查看资源
kubectl get pods -n <namespace>
kubectl get deployment -n <namespace>
kubectl get svc -n <namespace>
kubectl get pvc -n <namespace>
kubectl get hpa -n <namespace>
kubectl get all -n <namespace>
# 查看详情
kubectl describe pod <pod-name> -n <namespace>
kubectl describe deployment <deployment-name> -n <namespace>
# 查看日志
kubectl logs <pod-name> -n <namespace>
kubectl logs -f deployment/<deployment-name> -n <namespace>
# 进入容器
kubectl exec -it <pod-name> -n <namespace> -- sh
# 端口转发
kubectl port-forward svc/<service-name> <local-port>:<service-port> -n <namespace>
# 扩缩容
kubectl scale deployment <deployment-name> --replicas=<count> -n <namespace>
# 删除资源
kubectl delete pod <pod-name> -n <namespace>
kubectl delete deployment <deployment-name> -n <namespace>
kubectl delete namespace <namespace>
八、学习路径建议
plain
第一阶段:Docker 基础
├─ Docker 镜像构建
├─ Docker Compose 编排
└─ 容器网络与存储
第二阶段:K8s 核心概念
├─ Pod、Deployment、Service
├─ ConfigMap、Secret
├─ PVC、StorageClass
└─ Ingress、HPA
第三阶段:Helm 包管理
├─ Chart 结构与模板语法
├─ Values 配置与覆盖
├─ 模板函数与管道
└─ Helm 安装、升级、回滚
第四阶段:生产级部署
├─ GitOps (ArgoCD/Flux)
├─ CI/CD (GitHub Actions/GitLab CI)
├─ 多集群管理
└─ 监控与告警 (Prometheus/Grafana)