4. 编写第一个 Helm Chart:创建 Chart、定义 Deployment 模板、定义 Service 模板、使用 helm install 部署

本章将带领你从零开始编写第一个 Helm Chart。你将掌握 helm create 命令生成的目录结构,理解核心模板文件(Deployment 与 Service)的编写逻辑,并最终通过 helm install 将应用部署到 Kubernetes 集群中。这是后续学习升级、回滚与配置管理的基础。

4.1 使用 helm create 创建 Chart 骨架

Helm 提供了 helm create 命令,可以快速生成一个符合最佳实践的 Chart 目录结构。执行以下命令创建一个名为 my-first-app 的 Chart:

helm create my-first-app

执行后,Helm 会在当前目录下生成如下结构:

my-first-app/
├── Chart.yaml          # Chart 元数据(名称、版本、描述等)
├── charts/             # 存放子 Chart(依赖包)
├── templates/          # Kubernetes 资源模板目录
│   ├── NOTES.txt       # 部署后的使用说明
│   ├── _helpers.tpl    # 模板辅助函数
│   ├── deployment.yaml # Deployment 模板
│   ├── hpa.yaml        # 水平自动扩缩容模板
│   ├── ingress.yaml    # Ingress 模板
│   ├── service.yaml    # Service 模板
│   ├── serviceaccount.yaml # 服务账户模板
│   └── tests/          # 测试模板
│       └── test-connection.yaml
└── values.yaml         # 默认配置值文件
关键点:初学者应重点关注 templates/deployment.yaml、templates/service.yaml 和 values.yaml 三个文件。它们是定义应用运行形态的核心。

4.2 理解 Chart 的核心文件

在开始修改模板之前,需要先了解两个关键文件的作用:

文件 作用 必填
Chart.yaml 定义 Chart 的名称、版本、API 版本、描述等元数据 是
values.yaml 提供默认配置值,模板通过 .Values 对象引用 是
templates/ 存放 Go 模板文件,渲染后生成 Kubernetes 资源清单 是
charts/ 存放子 Chart 的目录(依赖管理) 否
NOTES.txt 部署成功后打印给用户的使用提示 否

4.3 定义 Deployment 模板

Deployment 是 Kubernetes 中最常用的工作负载资源,负责管理 Pod 的副本、更新策略和自愈能力。下面是一个精简且完整的 Deployment 模板示例,位于 templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-first-app.fullname" . }}
  labels:
    {{- include "my-first-app.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-first-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "my-first-app.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "my-first-app.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.port }}
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
模板语法要点:
  • {{ .Values.replicaCount }}:从 values.yaml 中读取副本数。
  • {{ include "my-first-app.fullname" . }}:调用 _helpers.tpl 中定义的命名模板,生成统一的资源名称。
  • {{- with .Values.imagePullSecrets }}:条件判断,仅在配置了拉取密钥时才渲染该字段。
  • nindent:在换行后添加指定数量的缩进,保持 YAML 格式正确。

4.4 定义 Service 模板

Service 为 Pod 提供稳定的网络访问入口。以下是一个 ClusterIP 类型的 Service 模板,位于 templates/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: {{ include "my-first-app.fullname" . }}
  labels:
    {{- include "my-first-app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "my-first-app.selectorLabels" . | nindent 4 }}
注意:targetPort: http 引用了 Deployment 模板中定义的端口名称 name: http。使用命名端口可以避免硬编码端口号,增强模板的可读性和可维护性。

4.5 配置 values.yaml

values.yaml 是 Chart 的配置中心。以下是与上述模板匹配的默认值配置:

# 副本数
replicaCount: 1

# 镜像配置
image:
  repository: nginx
  tag: "1.25.3"
  pullPolicy: IfNotPresent

# 服务配置
service:
  type: ClusterIP
  port: 80

# 资源限制
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

# 自动扩缩容(默认关闭)
autoscaling:
  enabled: false

# 其他配置(节点选择、容忍、亲和性等)
nodeSelector: {}
tolerations: []
affinity: {}

4.6 使用 helm install 部署 Chart

完成模板和 values 文件的编写后,即可使用 helm install 命令将 Chart 部署到 Kubernetes 集群。基本语法如下:

helm install [RELEASE_NAME] [CHART_PATH] [flags]

部署 my-first-app Chart 的示例:

# 使用默认 values.yaml 部署
helm install my-release ./my-first-app

# 使用自定义 values 文件覆盖默认配置
helm install my-release ./my-first-app -f custom-values.yaml

# 通过命令行直接设置单个参数
helm install my-release ./my-first-app --set replicaCount=3 --set image.tag=1.26.0
常见错误:
  • Release 名称冲突:在同一命名空间下,Release 名称必须唯一。如果已存在同名 Release,需先卸载或使用不同的名称。
  • 模板语法错误:使用 helm lint ./my-first-app 预先检查模板语法,避免部署时失败。
  • values 类型不匹配:确保 values.yaml 中的值与模板中期望的类型一致(例如端口号应为数字,而非字符串)。

4.7 验证部署结果

部署完成后,可以通过以下命令验证资源是否正常创建:

# 查看 Release 状态
helm list

# 查看 Release 详细信息
helm status my-release

# 查看 Kubernetes 资源
kubectl get pods,svc -l app.kubernetes.io/instance=my-release

如果一切正常,你将看到类似如下的输出:

NAME                                        READY   STATUS    RESTARTS   AGE
pod/my-release-my-first-app-7d8f9c6b9-abcde   1/1     Running   0          30s

NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/my-release-my-first-app     ClusterIP   10.96.123.45    <none>        80/TCP    30s

4.8 第一个 Chart 的完整工作流程

下图展示了从创建 Chart 到部署完成的完整流程:

第一个 Helm Chart 部署流程 1. helm create 生成 Chart 骨架 2. 编辑模板 Deployment + Service 3. 配置 values 镜像、副本、端口 4. helm install 部署到集群 5. 模板渲染 Go 模板 → YAML 6. K8s 创建资源 Pod + Service 7. 验证部署 helm status / kubectl 8. 应用运行 Nginx 提供服务 💡 核心概念 Release = Chart + Values helm install 将 Chart 渲染为 Kubernetes 资源并创建 Release

4.9 本章小结

通过本章的学习,你已经完成了以下关键任务:

  • 使用 helm create 快速生成标准 Chart 目录结构。
  • 编写了 Deployment 模板,定义了 Pod 的副本数、镜像、探针和资源限制。
  • 编写了 Service 模板,为应用提供了稳定的 ClusterIP 访问入口。
  • 配置了 values.yaml,实现了配置与模板的分离。
  • 使用 helm install 成功将 Chart 部署到 Kubernetes 集群。