Helm Chart 管理

Helm Chart 管理

Helm 是 Kubernetes 的包管理器,简化应用部署和版本管理。

Chart 结构

myapp/
├── Chart.yaml              # Chart 元数据
├── values.yaml             # 默认配置值
├── values-dev.yaml         # 开发环境配置
├── values-prod.yaml        # 生产环境配置
├── charts/                 # 依赖的子 Chart
├── templates/              # Kubernetes 资源模板
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   ├── hpa.yaml
│   ├── _helpers.tpl       # 模板辅助函数
│   └── NOTES.txt          # 安装后提示信息
└── README.md

Chart.yaml

apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 1.0.0          # Chart 版本
appVersion: "1.0.0"     # 应用版本
keywords:
  - kubernetes
  - microservices
home: https://github.com/example/myapp
sources:
  - https://github.com/example/myapp
maintainers:
  - name: DevOps Team
    email: devops@example.com
dependencies:
  - name: mongodb
    version: "13.0.0"
    repository: https://charts.bitnami.com/bitnami
    condition: mongodb.enabled
  - name: redis
    version: "17.0.0"
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled

values.yaml

# 副本数
replicaCount: 3

# 镜像配置
image:
  repository: myapp
  pullPolicy: IfNotPresent
  tag: ""  # 默认使用 Chart.appVersion

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

# Service Account
serviceAccount:
  create: true
  annotations: {}
  name: ""

# Pod 注解和标签
podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "8080"

podLabels:
  version: v1

# 安全上下文
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
    - ALL

# Service 配置
service:
  type: ClusterIP
  port: 80
  targetPort: 8080
  annotations: {}

# Ingress 配置
ingress:
  enabled: false
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: chart-example-tls
      hosts:
        - chart-example.local

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

# HPA 自动扩缩容
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

# 健康检查
livenessProbe:
  httpGet:
    path: /health
    port: http
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: http
  initialDelaySeconds: 5
  periodSeconds: 5

# 环境变量
env:
  - name: APP_ENV
    value: "production"
  - name: LOG_LEVEL
    value: "info"

# ConfigMap
configMap:
  enabled: true
  data:
    app.json: |
      {
        "port": 8080,
        "logLevel": "info"
      }

# Secret
secret:
  enabled: true
  data: {}

# 持久化存储
persistence:
  enabled: false
  storageClass: ""
  accessMode: ReadWriteOnce
  size: 10Gi

# MongoDB 依赖
mongodb:
  enabled: true
  auth:
    rootPassword: "password"
    database: myapp

# Redis 依赖
redis:
  enabled: true
  auth:
    password: "password"

模板示例

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "myapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
      labels:
        {{- include "myapp.selectorLabels" . | nindent 8 }}
        {{- with .Values.podLabels }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "myapp.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.targetPort }}
          protocol: TCP
        {{- with .Values.env }}
        env:
          {{- toYaml . | nindent 12 }}
        {{- end }}
        livenessProbe:
          {{- toYaml .Values.livenessProbe | nindent 12 }}
        readinessProbe:
          {{- toYaml .Values.readinessProbe | nindent 12 }}
        resources:
          {{- toYaml .Values.resources | nindent 12 }}

_helpers.tpl

{{/*
扩展 Chart 名称
*/}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
创建完整名称
*/}}
{{- define "myapp.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 }}

{{/*
Chart 标签
*/}}
{{- define "myapp.labels" -}}
helm.sh/chart: {{ include "myapp.chart" . }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
选择器标签
*/}}
{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

CI/CD 中使用 Helm

GitHub Actions

- name: Install Helm
  uses: azure/setup-helm@v3
  with:
    version: '3.13.0'

- name: Deploy with Helm
  run: |
    helm upgrade --install myapp ./helm/myapp \
      --namespace production \
      --create-namespace \
      --set image.tag=${{ github.sha }} \
      --values helm/myapp/values-prod.yaml \
      --wait \
      --timeout 5m

GitLab CI

deploy:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm upgrade --install myapp ./helm/myapp
        --namespace production
        --set image.tag=$CI_COMMIT_SHA
        --values helm/myapp/values-prod.yaml

小结

Chart 结构:标准目录布局和文件组织
values.yaml:配置管理和参数化
模板:动态生成 Kubernetes 资源
CI/CD 集成:自动化部署流程

下一节介绍发布策略和最佳实践。