¿Cuántas releases de Helm hay en el clúster si Argo CD despliega las aplicaciones? Cero. helm ls está vacío y helm history no tiene nada que mostrar. Argo CD usa Helm como motor de plantillas: ejecuta helm template, toma los manifiestos renderizados y los aplica con su propio motor — helm install no se invoca nunca. El FAQ del proyecto lo dice con claridad y el código lo confirma (util/helm/helm.go).
De ahí sale la primera consecuencia para el debate «Helm contra Kustomize»: los argumentos sobre historial de releases, helm rollback y gestión del ciclo de vida mediante hooks no aplican dentro de un circuito GitOps. El historial y la reversión los da Argo CD — argocd app history, argocd app rollback.
Quedan tres cosas por comparar: el lenguaje en que se describe la configuración, el origen del artefacto y la capacidad de sacar ese artefacto de un registro cerrado. La primera es cuestión de gusto. Las otras dos se convirtieron en 2026 en límites técnicos duros.
Qué cambió en un año
La rama Helm 3 se cierra. La release 3.22.0 (septiembre de 2026) es su último minor, y salió limitada a propósito: solo actualiza las librerías cliente de Kubernetes para clústeres más nuevos. Los parches de seguridad llegan hasta el 10 de febrero de 2027. HIP-0012 fijaba noviembre de 2026; los maintainers añadieron tres meses. Después de febrero, 3.x no recibe nada. El Helm actual es 4.3.0, de la misma ventana de septiembre.
Para GitOps pesa más otra cosa. A partir de Argo CD 3.5 los charts los renderiza solo Helm 4. El campo spec.source.helm.version se ignora — puede dejarse, no tiene efecto. La 3.5.3 lleva Helm 4.2.1; las ramas 3.3 y 3.4, todavía soportadas, funcionan con Helm 3.19.4. La versión del motor de plantillas en el pipeline la fija la versión de Argo CD, no lo que tenga instalado el ingeniero en local.
Esto tiene una consecuencia práctica en CI. Si el pipeline ejecuta helm template o helm diff con un binario de Helm 3 mientras el Argo CD del clúster ya va por 3.5, se comparan las salidas de dos renderizadores distintos con la esperanza de que coincidan. La versión de Helm en CI conviene fijarla a la versión de Argo CD, no a lo que traiga la imagen del runner. La topología decide el resto: en hub-and-spoke renderiza un único Argo CD en el hub, así que hay una sola versión de Helm en el circuito; con Argo CD en cada clúster los clústeres se separan por minors de Argo CD y, con ellos, por versiones del motor de plantillas.
Kustomize vive más callado: 5.8.2 salió el 30 de septiembre de 2026, y los minors anteriores fueron 5.8.1 en febrero y 5.8.0 en noviembre de 2025. Tres releases en once meses. La versión integrada en kubectl va por detrás del binario independiente: kubectl 1.36 y 1.37 llevan 5.8.1, y Argo CD 3.5.3 también 5.8.1.
La actualización que rompe el registro interno
El paso de Argo CD a Helm 4 trajo un breaking change poco visible — los registros OCI sin TLS. Helm 4 exige un --plain-http explícito donde su predecesor se las arreglaba sin él. En Argo CD se resuelve con un flag en el Secret del repositorio:
stringData:
insecureOCIForceHttp: "true"
El detalle está en las dependencias. Si Chart.yaml apunta a repository: oci://… en un registro sin TLS, ese registro debe registrarse en Argo CD por separado, como repositorio con el mismo flag. Con Helm 3 esas dependencias se descargaban de forma transparente, sin registro. Y hay una trampa lista: con --insecure-skip-server-verification y --insecure-oci-force-http puestos a la vez, Helm 4 pierde --plain-http en silencio.
Dónde conviven y dónde se rompe la combinación
Mezclar los motores es casi inevitable: chart ajeno más valores propios. Funcionan dos caminos.
El primero es una Application multi-source. El chart viene de un registro Helm u OCI, los values viven en Git y se enganchan mediante ref y $values. Las credenciales se quedan en los Secrets de repositorio de Argo CD, que es su sitio.
spec:
sources:
- repoURL: https://prometheus-community.github.io/helm-charts
chart: prometheus
targetRevision: 15.7.1
helm:
valueFiles:
- $values/charts/prometheus/values.yaml
- repoURL: https://git.example.com/org/value-files.git
targetRevision: dev
ref: values
El segundo camino es Kustomize con el campo helmCharts: el chart se infla dentro de Kustomize y encima van los parches. Así se instalan Argo Rollouts y la mitad de los operadores con CRD. Este camino tiene un techo, y está documentado.
El flag --enable-helm, sin el cual helmCharts no funciona, en Argo CD se activa solo de forma global — mediante kustomize.buildOptions: --enable-helm en argocd-cm, para todas las aplicaciones Kustomize a la vez. No existe opción por aplicación; la alternativa es escribir un plugin CMP.
La autenticación falta por completo. El generador arma el comando helm pull sin un solo flag de credenciales: ni --username, ni --password, ni --registry-config, ni --plain-http. Los Secrets de repositorio de Argo CD no llegan a esa ruta, solo actúan para la Helm source nativa. El esquema oci:// sí lo soporta el generador — tiene una rama propia en pullCommand() —, pero un registro privado, o uno sin TLS, no se configura de forma declarativa en absoluto. En un Harbor interno sin TLS, la combinación «Kustomize + helmCharts + Argo CD 3.5» no llega ni a construirse.
Los maintainers de Kustomize no lo esconden: el generador está pensado como un subconjunto limitado de Helm, y en él aceptan correcciones de bugs, trabajo crítico de seguridad y flags análogos a helm template. El soporte de registros privados y autenticación no está planeado — la siguiente iteración debería ser una función KRM. Ese documento se lee como declaración de intenciones: también promete no añadir OCI, y el esquema oci:// ya está en el código del generador.
Hooks y determinismo
Argo CD reconoce helm.sh/hook y reparte los hooks entre sus propias fases, pero la correspondencia es incompleta y las diferencias cambian el comportamiento:
pre-installypre-upgradese colapsan enPreSync. Argo CD no distingue la primera instalación de una actualización: todo es un sync. Un Job de migración de base de datos anotado con"helm.sh/hook": pre-upgrade,pre-installse ejecutará en cada sync. Si no es idempotente, lo sabrá por los datos.pre-rollback,post-rollback,test-success,test-failureyhook-delete-timeoutse ignoran.- Un solo
argocd.argoproj.io/hookpropio en la aplicación desactiva todos los hooks de Helm.
El segundo hilo es el determinismo del renderizado. helm template se reejecuta en cada comparación con el clúster. Un chart que genera una contraseña con randAlphaNum produce un OutOfSync eterno: el valor cambia en cada render y el diff no converge nunca. Se cura fijando el valor en los values. Kustomize puro, sin helmCharts, no tiene esa clase de problema por construcción: la salida de kustomize build es determinista. La fuerza aquí es precisamente el determinismo; la ausencia de plantillas no garantiza nada por sí misma — envuelva un chart en helmCharts y se renderizará la misma plantilla con el mismo randAlphaNum y el mismo OutOfSync eterno.
Kustomize cobra su precio por el determinismo: el parche vive aparte del objeto, y para ver el manifiesto final hay que construir el overlay. Súmese la deuda técnica acumulada en árboles antiguos. La versión 5.0.0 marcó como obsoletos patchesStrategicMerge, patchesJson6902 y vars, y bases ya en la 2.1.0; el reemplazo son patches, replacements y resources, que convierte kustomize edit fix. De kustomize.config.k8s.io/v1beta1 no los quitarán, pero al futuro API v1 no pasarán, así que habrá que arreglarlo. La conversión automática de vars a replacements puede reescribir muchos ficheros y cambiar la salida del build — hágala en un árbol git limpio.
Renderice lo que renderice, lo que se valida es el resultado del render, no la fuente. Las políticas a la salida de helm template y kustomize build atrapan lo que no tiene por qué llegar al clúster, sea cual sea el motor elegido.
Cuándo elegir qué
| Situación | Elección | Por qué |
|---|---|---|
| Chart ajeno desde un registro público o privado | Helm source nativa más values vía multi-source | Credenciales, TLS y flags OCI viven en los Secrets de repositorio |
| Manifiestos propios, muchos entornos | Kustomize: bases y overlays | Salida determinista, parches en lugar de plantillas ramificadas |
| Hay que retocar el chart por encima: anotaciones, límites, sidecar | Kustomize más helmCharts | Parche sobre el render, pero el registro debe ser público y con TLS |
| Registro interno sin TLS o con autorización | Solo Helm source nativa | El generador helmCharts no pasa ni credenciales ni --plain-http |
| El chart va a un consumidor externo | Helm | Versionado del chart, dependencias, distribución OCI |
Qué se deduce de esto
La elección la dicta el origen del artefacto. Donde el chart hay que sacarlo de un registro que exige credenciales o funciona sin TLS, queda un camino viable — la Helm source nativa en Argo CD: solo ella tiene canal hacia los Secrets de repositorio. Donde los manifiestos son propios y viven en el mismo Git, Kustomize da un build determinista y parches en lugar de plantillas ramificadas. El gusto por las plantillas de Go no participa en esta decisión; participa a quién le abre la puerta el registro.