← Назад к вопросам

Helm chart для веб-приложения

1.7 Middle🔥 181 комментариев
#Kubernetes

Условие

Создайте Helm chart для деплоя веб-приложения в Kubernetes:

Структура chart

  1. Deployment с настраиваемым количеством реплик
  2. Service (ClusterIP и NodePort)
  3. Ingress с TLS
  4. ConfigMap для конфигурации приложения
  5. Secret для sensitive данных
  6. HorizontalPodAutoscaler
  7. PodDisruptionBudget

Требования

  • Все параметры должны быть настраиваемыми через values.yaml
  • Добавьте health checks (liveness и readiness probes)
  • Используйте named templates для повторяющегося кода
  • Добавьте NOTES.txt с инструкциями после установки

Вопросы

  • Чем Helm отличается от Kustomize?
  • Как откатить релиз Helm?
  • Что такое Helm hooks и когда их использовать?

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Структура Helm Chart

Helm — это менеджер пакетов для Kubernetes, обеспечивающий шаблонизацию и версионирование развертываний. Отличие от Kustomize в том, что Helm предоставляет полноценную систему управления версиями, зависимостями и репозиториями, тогда как Kustomize — это просто инструмент для наложения патчей на YAML файлы.

Создам структуру chart:

my-web-app/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   ├── hpa.yaml
│   ├── pdb.yaml
│   ├── NOTES.txt
│   └── _helpers.tpl

Chart.yaml

apiVersion: v2
name: my-web-app
description: Web application Helm chart
type: application
version: 1.0.0
appVersion: "1.0"

values.yaml

# Replica and scaling
replicaCount: 3

image:
  repository: myapp/web
  pullPolicy: IfNotPresent
  tag: "1.0.0"

service:
  type: ClusterIP
  clusterIP:
    port: 80
    targetPort: 8080
  nodePort:
    enabled: false
    port: 30080

ingress:
  enabled: true
  className: "nginx"
  hosts:
    - host: "myapp.example.com"
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts:
        - myapp.example.com

# Resource limits
resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

# Health checks
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

# ConfigMap
config:
  LOG_LEVEL: "INFO"
  ENVIRONMENT: "production"

# Secrets
secrets:
  DATABASE_PASSWORD: ""
  API_KEY: ""

# HPA
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

# PDB
podDisruptionBudget:
  enabled: true
  minAvailable: 1

templates/_helpers.tpl

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

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

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "my-web-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

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

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

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-web-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-web-app.selectorLabels" . | nindent 8 }}
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
    spec:
      serviceAccountName: {{ include "my-web-app.fullname" . }}
      containers:
      - name: app
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - name: http
          containerPort: {{ .Values.service.clusterIP.targetPort }}
          protocol: TCP
        livenessProbe:
          {{- toYaml .Values.livenessProbe | nindent 10 }}
        readinessProbe:
          {{- toYaml .Values.readinessProbe | nindent 10 }}
        resources:
          {{- toYaml .Values.resources | nindent 10 }}
        env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: {{ include "my-web-app.fullname" . }}
              key: LOG_LEVEL
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: {{ include "my-web-app.fullname" . }}
              key: DATABASE_PASSWORD
        envFrom:
        - configMapRef:
            name: {{ include "my-web-app.fullname" . }}
        - secretRef:
            name: {{ include "my-web-app.fullname" . }}

templates/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  {{- if eq .Values.service.type "ClusterIP" }}
  clusterIP: {{ .Values.service.clusterIP }}
  {{- end }}
  ports:
  - port: {{ .Values.service.clusterIP.port }}
    targetPort: http
    protocol: TCP
    name: http
  {{- if .Values.service.nodePort.enabled }}
  - port: {{ .Values.service.nodePort.port }}
    targetPort: http
    protocol: TCP
    nodePort: {{ .Values.service.nodePort.port }}
    name: nodeport
  {{- end }}
  selector:
    {{- include "my-web-app.selectorLabels" . | nindent 4 }}

templates/ingress.yaml

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
spec:
  ingressClassName: {{ .Values.ingress.className }}
  {{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
  {{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
        {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ include "my-web-app.fullname" $ }}
                port:
                  number: {{ $.Values.service.clusterIP.port }}
        {{- end }}
  {{- end }}
{{- end }}

templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
data:
  {{- range $key, $value := .Values.config }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}

templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
type: Opaque
stringData:
  {{- range $key, $value := .Values.secrets }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}

templates/hpa.yaml

{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ include "my-web-app.fullname" . }}
  minReplicas: {{ .Values.autoscaling.minReplicas }}
  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}

templates/pdb.yaml

{{- if .Values.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: {{ include "my-web-app.fullname" . }}
  labels:
    {{- include "my-web-app.labels" . | nindent 4 }}
spec:
  minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
  selector:
    matchLabels:
      {{- include "my-web-app.selectorLabels" . | nindent 6 }}
{{- end }}

templates/NOTES.txt

1. Получить статус развертывания:
  kubectl get deployment -n {{ .Release.Namespace }}

2. Проверить pods:
  kubectl get pods -n {{ .Release.Namespace }}

3. Получить доступ к приложению через сервис:
  kubectl port-forward -n {{ .Release.Namespace }} svc/{{ include "my-web-app.fullname" . }} 8080:{{ .Values.service.clusterIP.port }}

4. Просмотр логов:
  kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "my-web-app.name" . }}

5. Обновить values и перевести:
  helm upgrade {{ .Release.Name }} . -n {{ .Release.Namespace }} -f values.yaml

Ответы на вопросы

Чем Helm отличается от Kustomize?

Helm — это полнофункциональный менеджер пакетов с системой управления версиями, зависимостями и глобальными репозиториями. Kustomize — это инструмент для применения трансформаций и патчей к YAML файлам. Helm использует Go-шаблоны для генерации манифестов, Kustomize работает с наложением слоев. Helm имеет встроенную систему откатов и историю релизов, Kustomize требует дополнительных инструментов.

Как откатить релиз Helm?

Используйте команду helm rollback <release-name> <revision> или просто helm rollback <release-name> для отката к предыдущей версии. Просмотреть историю можно через helm history <release-name>.

Что такое Helm hooks и когда их использовать?

Helm hooks — это специальные аннотации, которые позволяют выполнять действия на определённых этапах жизненного цикла релиза (pre-install, post-install, pre-upgrade, post-upgrade). Используются для выполнения миграций БД перед обновлением, очистки после удаления, инициализации и валидации.

Helm chart для веб-приложения | PrepBro