Chart de Helm para una app Next.js
Úsalo para charts/<app>/ y cómo Argo CD lo consume. La imagen que ejecuta proviene de docker-nextjs; el pipeline que publica ambos es github-actions.
La plantilla charts/__APP__/ es la fuente de verdad. Todos los valores comentados: references/values.md. Conexión con Argo CD: references/argocd.md.
Reglas
-
Un chart por app, en
charts/<app>/dentro de la raíz del repositorio de la app. ¿Por qué ahí?: Argo CD puede sincronizarlo directamente desde git (path: charts/<app>) para un entorno de desarrollo y desde el registro OCI para producción, con los mismos archivos; está fuera deapps/, por lo que no está ni en el contexto de compilación de Docker ni en un paquete del workspace pnpm; y el chart cambia en el mismo PR que el código que lo necesita. El chart es intencionadamente de una sola app: sin umbrella, sin subcharts. Plantillas genéricas basadas en valores (como el chart umbrella de backend) solo donde una sola app necesita el cambio: ingress, HPA, PDB, distribución topológica. -
Nunca edites manualmente
versionoappVersion. Ambos permanecen como0.0.0en git.release.yamlejecutahelm package --version X.Y.Z --app-version vX.Y.Za partir de la etiquetavX.Y.Z, por lo que el chart publicado y la etiqueta de la imagen siempre coinciden. -
image.tagpor defecto esappVersion; establécelo solo para entornos sincronizados por git. Desde OCI,appVersiones la etiqueta de lanzamiento y la imagen esghcr.io/nuvraxis/<app>:vX.Y.Z. Sincronizado desde git,appVersiones0.0.0, por lo que la aplicación Argo CD estableceimage.tag: sha-<short-sha>(omain).image.repositorysiempre va en minúsculas. -
Sondas: startup, liveness y readiness, todas en
/api/health. La sonda startup (2s × 30) cubre el arranque; liveness y readiness solo se inician después de ella. La ruta nunca toca una dependencia, por lo que una caída de la base de datos no reinicia los pods. No apuntes una sonda a/: renderiza una página. -
El contexto de seguridad coincide con la imagen: uid/gid 1001,
runAsNonRoot,readOnlyRootFilesystem, sin escalado de privilegios, todas las capabilities eliminadas, seccompRuntimeDefault.automountServiceAccountToken: falsetanto en la ServiceAccount como en el pod: la app no llama a la API de Kubernetes. -
.next/cachees unemptyDirconsizeLimit. Es la única ruta de escritura (/app/apps/<app>/.next/cache). El límite evita que un caché de imágenes descontrolado llene el nodo. -
Configuración mediante
envFrom: un ConfigMap desdevalues.config, y un Secret que ya existe.config: API_BASE_URL: https://api.nuvraxis.com existingSecret: portal-secretsEl chart nunca crea plantillas de valores secretos: no hay
kind: Secretcondatade valores, ni--set secret=…. El Secret es creado por External Secrets, Sealed Secrets o un operador, y solo su nombre está en los valores. Un cambio en el ConfigMap reinicia los pods mediante la anotaciónchecksum/config. -
No uses
NEXT_PUBLIC_*en el chart. Se incluyen en la compilación de la imagen (verdocker-nextjs); establecerlos en tiempo de ejecución no tiene efecto. -
Recursos: solicitudes de CPU y memoria, un límite de memoria, sin límite de CPU. Los límites de CPU estrangulan un servidor Node durante ráfagas e inflan la latencia de cola; el límite de memoria se mantiene porque el heap de Node crece hasta lo que se le asigna.
-
Alta disponibilidad por defecto: 2 réplicas, PDB
maxUnavailable: 1, actualización progresiva conmaxUnavailable: 0, distribución topológica entre zonas y nodos (ScheduleAnyway). Conautoscaling.enabledel Deployment omitereplicas, por lo que Argo CD y el HPA no compiten por ello. -
Ingress es opcional, TLS mediante anotaciones de cert-manager.
ingress.enabled,className, hosts,tlsconsecretName, ycert-manager.io/cluster-issueren anotaciones. Para respuestas en streaming en ingress-nginx añadenginx.ingress.kubernetes.io/proxy-buffering: "off"; para limitación de tasa,limit-rps(vernextjs-security). -
Sin hooks de Helm, sin
lookup, sin valores aleatorios. Argo CD renderiza el chart conhelm templatey aplica el resultado: los hooks se convierten en hooks de Argo con semántica diferente,lookupno devuelve nada, yrandAlphaNumcambia en cada sincronización y muestra la app permanentemente desincronizada. Todo lo renderizado debe ser una función pura de los valores. -
Los paquetes privados de GHCR necesitan credenciales de pull. Los paquetes GHCR son privados al primer push. Para imágenes: un Secret
docker-registrycon un token que tengaread:packages, referenciado enimagePullSecrets(los valores de producción referencianghcr-pull). Para el chart en Argo CD: un Secret de repositorio conenableOCI: "true"(verreferences/argocd.md). O haz los paquetes públicos en GitHub si el código es público. -
values-production.yamlcontiene solo lo que difiere en producción. Capa:-f values.yaml -f values-production.yaml. No copies los valores por defecto en él. -
Valida con
helm lint --strictyhelm template | kubeconform -strict. ¿Por qué kubeconform en lugar de helm-unittest?: los errores que realmente tiene un chart de una sola app son nombres de campo, tipos o versiones de API incorrectos en la salida renderizada, que kubeconform detecta contra los esquemas reales de Kubernetes sin código de prueba. helm-unittest afirma lógica de plantillas, que este chart apenas tiene. Lint y valida ambos archivos de valores, como hacepr.yaml.
Añadir cosas
| Necesidad | Cambio |
|---|---|
| Una variable de entorno en tiempo de ejecución | config: en valores (no secreto) o una clave en el Secret existente |
| Un secreto | añádelo al Secret externo; nada en el chart cambia |
| Otro puerto o sidecar | justifícalo primero; una app Next necesita un puerto |
| Un cron job | un chart o app separados, no este Deployment |
| NetworkPolicy | añade templates/networkpolicy.yaml, activado por networkPolicy.enabled |
Verificar
helm lint --strict charts/<app>
helm lint --strict charts/<app> -f charts/<app>/values-production.yaml
helm template <app> charts/<app> -f charts/<app>/values-production.yaml \
| docker run --rm -i ghcr.io/yannh/kubeconform:v0.8.0 -strict -summary -kubernetes-version 1.34.0 -
Fuentes
- https://helm.sh/docs/topics/charts/
- https://helm.sh/docs/chart_best_practices/
- https://helm.sh/docs/topics/registries/
- https://helm.sh/docs/overview/
- https://github.com/yannh/kubeconform
- https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
- https://kubernetes.io/docs/concepts/security/pod-security-standards/
- https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/
- https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
- https://argo-cd.readthedocs.io/en/stable/user-guide/helm/
- https://cert-manager.io/docs/usage/ingress/
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry