Gráficos de Helm: Gestión de paquetes de Kubernetes

Implementaciones de Kubernetes con gestión de paquetes Helm

Helm ha revolucionado la implementación de aplicaciones en Kubernetes al introducir conceptos de gestión de paquetes familiares de los sistemas operativos tradicionales.

A medida que aumenta la adopción de Kubernetes, gestionar aplicaciones complejas con docenas de archivos YAML se vuelve desafiante. Los Charts de Helm resuelven este problema empaquetando todos los recursos en paquetes versionados y configurables.

software-developer en la naturaleza Esta imagen agradable fue generada por modelo AI Flux 1 dev.

Entendiendo Helm: El Gestor de Paquetes de Kubernetes

Helm es para Kubernetes lo que apt es para Debian, yum para RedHat o Homebrew para macOS. Empaqueta aplicaciones de Kubernetes en Charts – colecciones de archivos que describen recursos relacionados de Kubernetes. Un solo Chart podría desplegar una pila completa de aplicaciones: servidores web, bases de datos, capas de caché, reglas de entrada y componentes de monitoreo. Para aquellos nuevos en Kubernetes, una Guía rápida de Kubernetes proporciona comandos esenciales y conceptos para comenzar.

Por qué Helm importa en DevOps moderno

Reducción de complejidad: En lugar de gestionar 20+ archivos YAML, gestionas un solo Chart con valores personalizables.

Reproducibilidad: Despliega configuraciones idénticas en desarrollo, entorno de pruebas y producción con sobrescrituras de valores específicas del entorno. Esto es especialmente valioso al desplegar arquitecturas complejas de microservicios donde la consistencia importa.

Control de versiones: Los Charts están versionados, lo que permite fácil retroceso y seguimiento de actualizaciones.

Ecosistema de la comunidad: Miles de Charts preconstruidos disponibles a través de Artifact Hub (anteriormente Helm Hub) para aplicaciones populares como PostgreSQL, Redis, NGINX, Prometheus y más.

Poder de plantillas: Las plantillas de Go permiten la generación dinámica de recursos basados en valores de entrada, reduciendo la duplicación.

Arquitectura y conceptos clave de Helm

Arquitectura de Helm 3

Helm 3 simplificó la arquitectura al eliminar Tiller, el componente problemático del lado del servidor de Helm 2:

  • Cliente Helm: Herramienta CLI que interactúa directamente con la API de Kubernetes
  • Chart: Formato de paquete que contiene plantillas y metadatos
  • Lanzamiento: Una instancia de un Chart en ejecución en un clúster de Kubernetes
  • Repositorio: Ubicación de almacenamiento para Charts (servidor HTTP o registro OCI)

Componentes clave de un Chart de Helm

my-app-chart/
├── Chart.yaml          # Metadatos y versión del Chart
├── values.yaml         # Valores de configuración predeterminados
├── charts/             # Charts dependientes
├── templates/          # Plantillas de recursos de Kubernetes
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl    # Funciones de ayuda de plantilla
│   └── NOTES.txt       # Notas posteriores a la instalación
├── .helmignore         # Archivos a ignorar al empaquetar
├── README.md
└── LICENSE

Creando tu primer Chart de Helm

Inicializar un nuevo Chart

helm create my-application
cd my-application

Esto genera un Chart inicial con plantillas de ejemplo para un despliegue, servicio e ingreso.

Chart.yaml: Definiendo metadatos

apiVersion: v2
name: my-application
description: Un chart de aplicación listo para producción
type: application
version: 1.0.0        # Versión del chart
appVersion: "2.4.1"   # Versión de la aplicación

maintainers:
  - name: Tu Equipo
    email: team@company.com

dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

values.yaml: Gestión de configuración

El archivo values.yaml define configuraciones predeterminadas que los usuarios pueden sobrescribir. Este enfoque separa la configuración de las plantillas, facilitando la gestión de diferentes entornos (desarrollo, pruebas, producción) y personalizando los despliegues sin modificar los archivos de plantilla.

replicaCount: 3

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

service:
  type: ClusterIP
  port: 80

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

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

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

Plantillas: Manifestos dinámicos de Kubernetes

Las plantillas utilizan la sintaxis de plantillas de Go para generar dinámicamente recursos de Kubernetes. Estas plantillas pueden generar cualquier tipo de recurso de Kubernetes, desde simples Despliegues hasta complejos StatefulSets para aplicaciones que requieren almacenamiento persistente. Para aplicaciones que necesitan identidades estables y volúmenes persistentes, querrás usar StatefulSets en lugar de Despliegues, como se detalla en nuestra guía sobre StatefulSets y Almacenamiento Persistente en Kubernetes.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-application.fullname" . }}
  labels:
    {{- include "my-application.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-application.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-application.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          {{- toYaml .Values.resources | nindent 10 }}

Ayudas de plantilla (_helpers.tpl)

Crea funciones de plantilla reutilizables para evitar la repetición:

{{/*
Expandir el nombre del chart.
*/}}
{{- define "my-application.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Crear un nombre completo de aplicación por defecto.
*/}}
{{- define "my-application.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

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

Gestión de Charts de Helm: Instalación y operaciones

Instalando un Chart

# Instalar desde un repositorio
helm install my-release bitnami/postgresql

# Instalar desde un directorio local
helm install my-app ./my-application

# Instalar con valores personalizados
helm install my-app ./my-application -f values-production.yaml

# Instalar con sobrescrituras de valores en línea
helm install my-app ./my-application \
  --set replicaCount=5 \
  --set image.tag=2.0.0

Actualizando lanzamientos

# Actualizar con nuevos valores
helm upgrade my-app ./my-application -f values-production.yaml

# Actualizar con retroceso automático en caso de error
helm upgrade my-app ./my-application --atomic --timeout 5m

# Forzar actualizaciones de recursos
helm upgrade my-app ./my-application --force

Retroceso y historial

# Ver historial de lanzamientos
helm history my-app

# Retroceder a la versión anterior
helm rollback my-app

# Retroceder a una revisión específica
helm rollback my-app 3

Pruebas y depuración

# Ejecutar simulación para ver los manifiestos generados
helm install my-app ./my-application --dry-run --debug

# Renderizado de plantillas sin instalación
helm template my-app ./my-application

# Revisar el chart para problemas
helm lint ./my-application

# Probar lanzamiento con ganchos de prueba
helm test my-app

Características avanzadas de Helm

Dependencias de Chart

Los Charts de Helm pueden depender de otros Charts, lo que permite componer aplicaciones complejas a partir de componentes reutilizables. Esto es especialmente útil al desplegar microservicios que necesitan bases de datos, colas de mensajes u otros servicios de soporte. Define dependencias en Chart.yaml:

dependencies:
  - name: redis
    version: "17.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

Actualizar dependencias:

helm dependency update ./my-application

Ganchos de Helm para gestión del ciclo de vida

Los ganchos se ejecutan en puntos específicos del ciclo de vida del lanzamiento:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "my-application.fullname" . }}-db-migration
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
      - name: db-migrate
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["python", "manage.py", "migrate"]
      restartPolicy: Never

Tipos de ganchos incluyen:

  • pre-install: Antes de instalar los recursos
  • post-install: Después de instalar todos los recursos
  • pre-upgrade: Antes de la actualización
  • post-upgrade: Después de la actualización
  • pre-delete: Antes de la eliminación
  • post-delete: Después de la eliminación
  • pre-rollback: Antes del retroceso
  • post-rollback: Después del retroceso

Lógica condicional y control de flujo

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

Soporte de registro OCI: Distribución moderna de Charts

Desde Helm 3.8, el soporte para registros OCI (Open Container Initiative) es estable, permitiendo almacenar Charts junto con imágenes de contenedor.

Publicar en un registro OCI

# Iniciar sesión en el registro
helm registry login registry.example.com

# Empaquetar el chart
helm package ./my-application

# Enviar al registro OCI
helm push my-application-1.0.0.tgz oci://registry.example.com/charts

# Instalar desde el registro OCI
helm install my-app oci://registry.example.com/charts/my-application --version 1.0.0

Ventajas de los registros OCI

  • Almacenamiento unificado: Charts e imágenes en un solo lugar
  • Herramientas estándar: Usar infraestructura de registro existente
  • Mejor seguridad: Aprovechar autenticación y escaneo del registro
  • Gestión más sencilla: No se necesita un servidor de repositorio de Charts separado

Mejores prácticas para Charts de Helm en producción

1. Estructura y documentación de valores

Documenta todos los valores con comentarios:

# -- Número de réplicas para la aplicación
replicaCount: 3

# -- Configuración de imagen
image:
  # -- Repositorio de imagen
  repository: myapp/backend
  # -- Política de extracción de imagen
  pullPolicy: IfNotPresent
  # -- Etiqueta de imagen (por defecto, appVersion del chart)
  tag: ""

2. Gestión de recursos

Siempre establece solicitudes y límites de recursos:

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

3. Contextos de seguridad

Define contextos de seguridad para contenedores:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 1000
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true

4. Pruebas de salud

Incluye pruebas de vivacidad y preparación:

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

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

5. Gestión de ConfigMap y Secret

La gestión adecuada de secretos es crítica para despliegues en producción. Usa gestores de secretos externos (Sealed Secrets, External Secrets Operator o Vault) en lugar de almacenar secretos en archivos de valores. Esto asegura que datos sensibles como contraseñas de base de datos, claves API y certificados se manejen de forma segura:

envFrom:
- secretRef:
    name: {{ include "my-application.fullname" . }}-secrets
- configMapRef:
    name: {{ include "my-application.fullname" . }}-config

6. Validación de esquema

Crea values.schema.json para validar entradas de usuario:

{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1
    },
    "image": {
      "type": "object",
      "properties": {
        "repository": {
          "type": "string"
        },
        "tag": {
          "type": "string"
        }
      },
      "required": ["repository"]
    }
  },
  "required": ["image"]
}

7. NOTES.txt para orientación al usuario

Proporciona instrucciones posteriores a la instalación:

1. Obten la URL de la aplicación ejecutando:
{{- if .Values.ingress.enabled }}
  https://{{ (index .Values.ingress.hosts 0).host }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "my-application.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- end }}

2. Monitorea el despliegue:
  kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "my-application.name" . }}"

Pruebas de Chart de Helm e integración con CI/CD

Pruebas de Chart con chart-testing (ct)

# Instalar chart-testing
brew install chart-testing

# Lintear charts
ct lint --config ct.yaml

# Instalar y probar charts
ct install --config ct.yaml

Ejemplo de GitHub Actions

name: Helm Chart CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Configurar Helm
        uses: azure/setup-helm@v3
        with:
          version: 3.12.0

      - name: Configurar chart-testing
        uses: helm/chart-testing-action@v2

      - name: Lintear charts
        run: ct lint --config ct.yaml

      - name: Crear clúster kind
        uses: helm/kind-action@v1

      - name: Instalar charts
        run: ct install --config ct.yaml

GitOps con Helm: ArgoCD y Flux

Herramientas de GitOps como ArgoCD y Flux se integran de forma fluida con Charts de Helm, permitiendo despliegues declarativos y automatizados. Estas herramientas vigilan tu repositorio de Git para cambios y sincronizan automáticamente los lanzamientos de Helm, haciendo el despliegue continuo sencillo. Para arquitecturas complejas de microservicios, considera cómo patrones de transacciones distribuidas como el patrón Saga pueden ayudar a gestionar la consistencia en servicios desplegados mediante Helm.

Aplicación de ArgoCD

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-application
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/my-app-chart
    targetRevision: main
    path: charts/my-application
    helm:
      valueFiles:
        - values-production.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

HelmRelease de Flux

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-application
  namespace: flux-system
spec:
  interval: 5m
  chart:
    spec:
      chart: my-application
      version: '1.x.x'
      sourceRef:
        kind: HelmRepository
        name: my-charts
  values:
    replicaCount: 5
    image:
      tag: "2.0.0"

Solución de problemas de problemas comunes de Helm

Problema: Actualización fallida en estado pendiente

# Verificar el estado del lanzamiento
helm list --all-namespaces

# Ver detalles del lanzamiento
helm status my-app -n namespace

# Eliminar forzado si es necesario (usar con cuidado)
kubectl delete secret -n namespace -l owner=helm,name=my-app

Problema: Errores de renderizado de plantillas

# Depurar el renderizado de plantillas
helm template my-app ./my-application --debug

# Validar contra Kubernetes
helm template my-app ./my-application | kubectl apply --dry-run=client -f -

Problema: Valores no aplicados

# Ver valores fusionados
helm get values my-app

# Mostrar todos los valores calculados
helm get values my-app --all

Ecosistema y herramientas de Helm

El ecosistema de Helm incluye numerosas herramientas que extienden sus capacidades e integran con otras tecnologías de Kubernetes. Cuando se despliegan aplicaciones que requieren características avanzadas de red como comunicación servicio a servicio, gestión de tráfico y políticas de seguridad, considere integrarse con una Red de Servicios con Istio y Linkerd, que pueden desplegarse y gestionarse mediante Charts de Helm.

Herramientas esenciales

  • Helmfile: Especificación declarativa para desplegar Charts de Helm
  • Helm Diff: Previsualizar cambios antes de la actualización
  • Helm Secrets: Gestionar secretos con SOPS
  • Nova: Encontrar Charts de Helm obsoletos
  • Pluto: Detectar APIs de Kubernetes obsoletas

Ejemplo de Helmfile

repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

releases:
  - name: postgresql
    namespace: database
    chart: bitnami/postgresql
    version: 12.x.x
    values:
      - postgresql:
          auth:
            database: myapp
            username: appuser

  - name: my-app
    namespace: production
    chart: ./charts/my-application
    values:
      - values-production.yaml
    needs:
      - database/postgresql

El futuro de Helm

El ecosistema de Helm continúa evolucionando:

  • Nativo de OCI: Transición completa a registros OCI como estándar
  • Mejora de seguridad: Mejores herramientas de gestión de secretos y capacidades de firma
  • Rendimiento: Rendimiento más rápido de renderizado e instalación para Charts grandes
  • Soporte de WASM: WebAssembly para plugins y extensiones de Chart
  • Mejor validación: Validación de esquema mejorada y cumplimiento de políticas

Conclusión

Helm se ha convertido en el estándar de facto para la gestión de paquetes en Kubernetes, y dominarlo es esencial para las prácticas modernas de DevOps. Al comprender la estructura del Chart, plantillas, gestión de valores y mejores prácticas, puedes crear despliegues de Kubernetes mantenibles, seguros y escalables.

Comienza con Charts simples, incorpora gradualmente características avanzadas como ganchos y dependencias, e integra con herramientas de GitOps para infraestructura de producción. La comunidad de Helm proporciona miles de Charts preconstruidos, pero el verdadero poder proviene de crear Charts personalizados adaptados a las necesidades de tu organización. Ya sea que estés desplegando aplicaciones sin estado o cargas de trabajo con estado que requieren almacenamiento persistente, Helm simplifica la complejidad de la gestión de recursos de Kubernetes. Para equipos que están configurando nuevos clústeres de Kubernetes, considere instalar Kubernetes con Kubespray o explorar distribuciones de Kubernetes como k3s o MicroK8s para entornos de desarrollo. Si estás evaluando qué distribución se ajusta a tus necesidades de homelab o clúster pequeño, consulta nuestro análisis comparativo completo de distribuciones de Kubernetes para un análisis detallado.

Enlaces útiles