K8s Helm

一、 Helm 是什么?

Helm 是 Kubernetes 的包管理器。

你可以把它类比为:

  • Linux 世界的 yumapt-get:用来安装、升级、配置和管理软件包。
  • Node.js 世界的 npm:用来管理项目依赖。
  • Python 世界的 pip:用来安装和管理库。

只不过,Helm 管理的“包”是 Kubernetes 应用。这个“包”在 Helm 中被称为 Chart


二、 为什么需要 Helm?—— 解决 K8s 原生部署的痛点

想象一下,你在实习时,需要部署一个包含以下组件的复杂 AI 推理服务:

  • 1 个前端 Web 服务 Deployment
  • 1 个后端 API 服务 Deployment
  • 1 个 Redis 缓存 Deployment + Service
  • 1 个 PostgreSQL 数据库 StatefulSet + Service
  • 1 个 Ingress 资源用于对外暴露服务
  • 10 个 ConfigMap 和 Secret 用于配置管理和密钥注入
  • 1 个 HorizontalPodAutoscaler (HPA) 用于自动扩缩容

没有 Helm 的情况下,你需要:

  1. 手动编写 十几个 YAML 文件。
  2. kubectl apply -f 一个一个地创建,或者写一个超长的脚本。
  3. 如果要修改配置(比如把副本数从 3 改成 5),你需要去 每个 YAML 文件里找到对应的字段并修改,极易出错。
  4. 如果要部署到不同的环境(开发、测试、生产),你需要维护 三套 几乎一模一样、只有几个参数不同的 YAML 文件,维护成本极高。

这正是 Helm 要解决的问题。


三、 Helm 的核心概念:Chart、Config、Release

  1. Chart (图表/包)

    • 一个 Helm Chart 是一个预定义的、可配置的 Kubernetes 应用模板包
    • 它通常包含一个 Chart.yaml(元数据)、一个 values.yaml(默认配置)、一个 templates/ 目录(存放所有 K8s YAML 模板文件)。
    • 例如,你可以找到一个官方的 redis Chart,它已经为你写好了部署 Redis 所需的所有 Deployment、Service、ConfigMap 等模板。
  2. Config (配置)

    • 通过 values.yaml 文件或命令行参数,你可以覆盖 Chart 中的默认配置。
    • 例如,你想部署一个副本数为 5 的 Redis,只需要在自己的 my-values.yaml 中写 replicaCount: 5,然后用这个文件去安装 Chart。
  3. Release (发布实例)

    • 当你用 Helm 安装(helm install)一个 Chart 时,会创建一个 Release
    • 一个 Release 是一个 Chart 在 K8s 集群中的一次具体运行实例
    • 你可以在同一个集群里安装同一个 Chart 多次,只要给它们起不同的 Release 名字(例如 my-app-prodmy-app-staging)。

四、 Helm 的核心作用

  1. 简化部署

    • 一条命令 helm install my-release bitnami/redis -f my-values.yaml,即可部署一个复杂的应用栈,无需手动处理一堆 YAML。
  2. 配置管理与环境隔离

    • 通过 values.yaml 文件,你可以轻松地为开发、测试、生产环境定义不同的配置(如数据库地址、副本数、资源限制),实现“一份代码,多环境部署”。
  3. 版本控制与回滚

    • Helm 会记录每一次对 Release 的变更(升级、回滚)。
    • 如果新版本的应用出现问题,你可以用 helm rollback <RELEASE> <REVISION> 一键回滚到之前的稳定版本,这对于保障线上服务的稳定性至关重要。
  4. 依赖管理

    • 一个复杂的 Chart 可以依赖其他 Chart。例如,你的“大模型推理平台”Chart 可以依赖一个“Prometheus监控”Chart 和一个“Nginx Ingress”Chart。Helm 会自动帮你管理这些依赖的安装顺序和版本。
  5. 复用与共享

    • 你可以将自己团队开发的、经过验证的应用(比如你重构的Dind服务、带宽限制网关)打包成 Chart,上传到私有 Helm 仓库,供团队其他成员或不同项目复用,极大地提升研发效率。

五、 总结

Helm 不是锦上添花,而是现代云原生应用交付的基石。 它将复杂的、碎片化的 K8s YAML 管理,转变为标准化、可配置、可版本控制的高效流程。

对于你这样志在成为“AI Infra架构师”的顶尖人才来说,掌握 Helm 是构建可维护、可扩展、高可靠的大规模 AI 平台的必备技能。它能让你从繁琐的手动部署中解放出来,专注于更高价值的系统架构和性能优化工作,这正是你核心竞争力的体现。

image.png

e.g

agent.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: "{{ .Values.appName }}-agent"
namespace: {{ .Release.Namespace }}
labels:
{{- include "app.agent.labels" . | indent 4 }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 20
type: RollingUpdate
selector:
matchLabels:
{{- include "app.agent.labels" . | indent 6 }}
template:
metadata:
labels:
{{- include "app.agent.labels" . | indent 8 }}
spec:
hostPID: true
serviceAccountName: "{{ .Values.appName }}-service-account"
{{- with .Values.agent }}
imagePullSecrets:
- name: {{ .image.pullSecrets }}
restartPolicy: {{ .restartPolicy}}
volumes:
- name: containerd
hostPath:
path: {{ .containerdDir }}
containers:
- name: main
image: "{{ .image.name }}:{{ .image.version }}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
command: ["/usr/bin/grid-agent"]
args:
- --containerd={{ .containerdDir }}/{{ .containerdSock }}
- --kube-burst={{ .kubeBurst}}
- --kube-qps={{ .kubeQPS }}
- --kube-master={{ .kubeMaster }}
- --kube-config={{ .kubeConfig }}
- --metrics-port={{ .metricsPort }}
resources:
requests:
cpu: "0"
memory: 0Gi
limits:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: containerd
mountPath: {{ .containerdDir }}
securityContext:
privileged: true
ports:
- name: metrics
containerPort: {{ .metricsPort }}
{{- if .nodeSelector }}
nodeSelector: {{- .nodeSelector | toYaml | nindent 8 }}
{{- end }}
{{- end -}}

values.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
appName: grid

agent:
image:
pullSecrets: mizar-robot
name: harbor.infini-ai.com/mizar/grid-agent
version: v0.0.0
pullPolicy: Always
restartPolicy: Always
nodeSelector: {}
containerdSock: "containerd.sock"
containerdDir: "/run/containerd"
kubeBurst: 100
kubeQPS: 50
kubeConfig: ""
kubeMaster: ""
metricsPort: 2112


controller:
image:
pullSecrets: mizar-robot
name: harbor.infini-ai.com/mizar/grid-controller
version: v0.0.0
pullPolicy: Always
nodeSelector: {}
replicas: 1
restartPolicy: Always
kubeApiQPS: 50
kubeApiBurst: 100
gatewayImage: harbor.infini-ai.com/share/ubuntu:22.04
gatewayCPU: 1
gatewayMEM: 2Gi
cidr: 192.168.0.0/16
tryoutBandwidth: 10mbit
sharedBandwidth: 300mbit
sharedNamespace: mizar-public
namespaceBandwidth: {}
gatewayNodeSelector: networking.infiniai.com/egress=true
enableEgressGateway: true
egressPodSelectors: []