microservices

Создание и использование Helm-чартов в Kubernetes

Полное руководство по работе с Helm для управления приложениями в Kubernetes

#microservices #kubernetes #helm #devops #infrastructure

Создание и использование Helm-чартов в Kubernetes

Helm — это пакетный менеджер для Kubernetes, который упрощает развертывание и управление приложениями в кластере.

Что такое Helm?

Helm позволяет определить, установить и обновить даже самые сложные Kubernetes приложения. Чарты (charts) — это пакеты предварительно сконфигурированных ресурсов Kubernetes.

Структура Helm Chart

my-microservice/
├── Chart.yaml          # Метаданные чарта
├── values.yaml         # Значения по умолчанию
├── charts/            # Зависимости
├── templates/         # Шаблоны Kubernetes манифестов
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   └── _helpers.tpl
└── .helmignore        # Игнорируемые файлы

Создание Chart

Chart.yaml

apiVersion: v2
name: order-service
description: Order management microservice
type: application
version: 1.0.0
appVersion: "1.0.0"
keywords:
  - microservices
  - orders
maintainers:
  - name: DevOps Team
    email: devops@example.com
dependencies:
  - name: postgresql
    version: "12.1.0"
    repository: "https://charts.bitnami.com/bitnami"

values.yaml

# Настройки по умолчанию
replicaCount: 3

image:
  repository: myregistry/order-service
  tag: "1.0.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80
  targetPort: 3000

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: orders.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: orders-tls
      hosts:
        - orders.example.com

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

env:
  - name: NODE_ENV
    value: production
  - name: DATABASE_HOST
    value: postgresql
  - name: DATABASE_PORT
    value: "5432"

secrets:
  DATABASE_PASSWORD: ""
  JWT_SECRET: ""

healthCheck:
  liveness:
    path: /health
    initialDelaySeconds: 30
    periodSeconds: 10
  readiness:
    path: /ready
    initialDelaySeconds: 10
    periodSeconds: 5

Шаблоны манифестов

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "order-service.fullname" . }}
  labels:
    {{- include "order-service.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "order-service.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
      labels:
        {{- include "order-service.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - name: http
          containerPort: {{ .Values.service.targetPort }}
          protocol: TCP
        env:
        {{- range .Values.env }}
        - name: {{ .name }}
          value: {{ .value | quote }}
        {{- end }}
        {{- range $key, $value := .Values.secrets }}
        - name: {{ $key }}
          valueFrom:
            secretKeyRef:
              name: {{ include "order-service.fullname" $ }}-secrets
              key: {{ $key }}
        {{- end }}
        livenessProbe:
          httpGet:
            path: {{ .Values.healthCheck.liveness.path }}
            port: http
          initialDelaySeconds: {{ .Values.healthCheck.liveness.initialDelaySeconds }}
          periodSeconds: {{ .Values.healthCheck.liveness.periodSeconds }}
        readinessProbe:
          httpGet:
            path: {{ .Values.healthCheck.readiness.path }}
            port: http
          initialDelaySeconds: {{ .Values.healthCheck.readiness.initialDelaySeconds }}
          periodSeconds: {{ .Values.healthCheck.readiness.periodSeconds }}
        resources:
          {{- toYaml .Values.resources | nindent 12 }}

templates/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ include "order-service.fullname" . }}
  labels:
    {{- include "order-service.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "order-service.selectorLabels" . | nindent 4 }}

templates/_helpers.tpl

{{/*
Expand the name of the chart.
*/}}
{{- define "order-service.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
*/}}
{{- define "order-service.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 }}

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

{{/*
Selector labels
*/}}
{{- define "order-service.selectorLabels" -}}
app.kubernetes.io/name: {{ include "order-service.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

Использование Helm

Установка чарта

# Установка с дефолтными значениями
helm install order-service ./order-service

# Установка с кастомными значениями
helm install order-service ./order-service \
  --values values-production.yaml \
  --set image.tag=1.2.0 \
  --set replicaCount=5

# Установка в конкретный namespace
helm install order-service ./order-service \
  --namespace production \
  --create-namespace

Обновление релиза

# Обновление с новыми значениями
helm upgrade order-service ./order-service \
  --values values-production.yaml \
  --set image.tag=1.3.0

# Обновление или установка (если не существует)
helm upgrade --install order-service ./order-service

# Откат к предыдущей версии
helm rollback order-service 1

Управление релизами

# Список установленных релизов
helm list

# История релиза
helm history order-service

# Удаление релиза
helm uninstall order-service

# Удаление с сохранением истории
helm uninstall order-service --keep-history

Переопределение значений

values-production.yaml

replicaCount: 5

image:
  tag: "1.3.0"

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: true
  minReplicas: 5
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70

env:
  - name: NODE_ENV
    value: production
  - name: LOG_LEVEL
    value: info

Использование секретов

# Создание секретов из файла
kubectl create secret generic order-service-secrets \
  --from-literal=DATABASE_PASSWORD=secret123 \
  --from-literal=JWT_SECRET=jwt-secret-key

# Или через Helm
helm install order-service ./order-service \
  --set secrets.DATABASE_PASSWORD=secret123 \
  --set secrets.JWT_SECRET=jwt-secret-key

Тестирование чарта

# Проверка синтаксиса
helm lint ./order-service

# Dry-run установки
helm install order-service ./order-service --dry-run --debug

# Рендеринг шаблонов
helm template order-service ./order-service

# Тестирование установленного релиза
helm test order-service

Упаковка и публикация

# Упаковка чарта
helm package ./order-service

# Создание индекса репозитория
helm repo index .

# Добавление репозитория
helm repo add myrepo https://charts.example.com

# Обновление репозиториев
helm repo update

# Установка из репозитория
helm install order-service myrepo/order-service

Hooks

templates/hooks/pre-install-job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "order-service.fullname" . }}-migration
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "-5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migration
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["npm", "run", "migrate"]
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: {{ include "order-service.fullname" . }}-secrets
              key: DATABASE_URL

Best Practices

  1. Используйте values.yaml — все конфигурируемые параметры должны быть в values
  2. Версионируйте чарты — следуйте semantic versioning
  3. Документируйте параметры — добавляйте комментарии в values.yaml
  4. Тестируйте перед деплоем — используйте helm lint и --dry-run
  5. Используйте зависимости — не дублируйте чарты для общих сервисов
  6. Применяйте hooks — для миграций и других задач
  7. Храните секреты безопасно — используйте external secrets или sealed secrets

Заключение

Helm значительно упрощает управление Kubernetes приложениями, обеспечивая переиспользование конфигураций, версионирование и простое обновление микросервисов.