Chart Helm pour une application Next.js
À utiliser pour charts/<app>/ et comment Argo CD le consomme. L'image exécutée provient de docker-nextjs ; le pipeline qui publie les deux est github-actions.
Le dossier charts/__APP__/ du template est la source de vérité. Toutes les valeurs avec commentaires : references/values.md. Câblage Argo CD : references/argocd.md.
Règles
-
Un chart par application, dans
charts/<app>/à la racine du dépôt de l'application. Pourquoi là : Argo CD peut le synchroniser directement depuis git (path: charts/<app>) pour un environnement de développement et depuis le registre OCI pour la production, avec les mêmes fichiers ; il est en dehors deapps/, donc ni dans le contexte de construction Docker ni dans un paquet pnpm workspace ; et les modifications du chart accompagnent le code qui en a besoin dans la même PR. Le chart est délibérément mono-application : pas de chart umbrella, pas de sous-charts. Des templates génériques pilotés par les valeurs (comme le chart umbrella backend) uniquement là où une seule application a besoin du commutateur : Ingress, HPA, PDB, topology spread. -
Ne jamais modifier manuellement
versionouappVersion. Les deux restent0.0.0dans git.release.yamlexécutehelm package --version X.Y.Z --app-version vX.Y.Zà partir du tagvX.Y.Z, de sorte que le chart publié et le tag d'image correspondent toujours. -
image.tagpar défaut àappVersion; ne le définir que pour les environnements synchronisés par git. Depuis OCI,appVersionest le tag de version et l'image estghcr.io/nuvraxis/<app>:vX.Y.Z. Synchronisé depuis git,appVersionest0.0.0, donc l'Application Argo CD définitimage.tag: sha-<short-sha>(oumain).image.repositoryest en minuscules, toujours. -
Sondes : démarrage, vivacité et disponibilité, toutes sur
/api/health. La sonde de démarrage (2s × 30) couvre le boot ; la vivacité et la disponibilité ne démarrent qu'après. La route ne touche jamais une dépendance, donc une panne de base de données ne redémarre pas les pods. Ne pas pointer une sonde sur/: cela rend une page. -
Contexte de sécurité correspond à l'image : uid/gid 1001,
runAsNonRoot,readOnlyRootFilesystem, pas d'escalade de privilèges, toutes les capacités supprimées, seccompRuntimeDefault.automountServiceAccountToken: falseà la fois sur le ServiceAccount et le pod : l'application n'appelle pas l'API Kubernetes. -
.next/cacheest unemptyDiravec unsizeLimit. C'est le seul chemin inscriptible (/app/apps/<app>/.next/cache). La limite empêche un cache d'image incontrôlé de remplir le nœud. -
Configuration via
envFrom: une ConfigMap depuisvalues.config, et un Secret qui existe déjà.config: API_BASE_URL: https://api.nuvraxis.com existingSecret: portal-secretsLe chart ne template jamais les valeurs secrètes : pas de
kind: Secretavecdatadepuis les valeurs, pas de--set secret=…. Le Secret est créé par External Secrets, Sealed Secrets ou un opérateur, et seul son nom est dans les valeurs. Un changement de ConfigMap redémarre les pods via l'annotationchecksum/config. -
Pas de
NEXT_PUBLIC_*dans le chart. Ils sont intégrés à la construction de l'image (voirdocker-nextjs) ; les définir à l'exécution ne fait rien. -
Ressources : requests pour CPU et mémoire, une limite de mémoire, pas de limite CPU. Les limites CPU étranglent un serveur Node lors des pics et augmentent la latence de queue ; la limite de mémoire reste parce que le heap de Node grandit jusqu'à ce qu'on lui donne.
-
Haute disponibilité par défaut : 2 réplicas, PDB
maxUnavailable: 1, mise à jour glissante avecmaxUnavailable: 0, contraintes de dispersion topologique entre zones et nœuds (ScheduleAnyway). Avecautoscaling.enabled, le Deployment ometreplicas, donc Argo CD et le HPA ne se battent pas pour cela. -
Ingress est optionnel, TLS via les annotations cert-manager.
ingress.enabled,className, hosts,tlsavec unsecretName, etcert-manager.io/cluster-issuerdans les annotations. Pour les réponses en streaming sur ingress-nginx ajouternginx.ingress.kubernetes.io/proxy-buffering: "off"; pour la limitation de débit,limit-rps(voirnextjs-security). -
Pas de hooks Helm, pas de
lookup, pas de valeurs aléatoires. Argo CD rend le chart avechelm templateet applique le résultat : les hooks deviennent des hooks Argo avec une sémantique différente,lookupne retourne rien, etrandAlphaNumchange à chaque synchronisation et montre l'application comme définitivement désynchronisée. Tout ce qui est rendu doit être une fonction pure des valeurs. -
Les paquets GHCR privés nécessitent des identifiants de pull. Les paquets GHCR sont privés dès la première publication. Pour les images : un Secret
docker-registryavec un token ayantread:packages, référencé dansimagePullSecrets(les valeurs de production référencentghcr-pull). Pour le chart dans Argo CD : un Secret de dépôt avecenableOCI: "true"(voirreferences/argocd.md). Ou rendre les paquets publics dans GitHub si le code est public. -
values-production.yamlne contient que ce qui diffère en production. Superposer :-f values.yaml -f values-production.yaml. Ne pas copier les valeurs par défaut dedans. -
Valider avec
helm lint --strictethelm template | kubeconform -strict. Pourquoi kubeconform plutôt que helm-unittest : les bugs qu'un chart mono-application a réellement sont des noms de champs, types ou versions d'API incorrects dans la sortie rendue, ce que kubeconform attrape contre les schémas Kubernetes réels avec zéro code de test. helm-unittest vérifie la logique des templates, que ce chart a à peine. Valider et linter les deux fichiers de valeurs, comme le faitpr.yaml.
Ajouts
| Besoin | Modification |
|---|---|
| Une variable d'environnement runtime | config: dans les valeurs (non secrète) ou une clé dans le Secret existant |
| Un secret | l'ajouter au Secret externe ; rien ne change dans le chart |
| Un autre port ou sidecar | le justifier d'abord ; une application Next a besoin d'un port |
| Un cron job | un chart ou une application séparé(e), pas ce Deployment |
| NetworkPolicy | ajouter templates/networkpolicy.yaml, activé par networkPolicy.enabled |
Vérification
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 -
Sources
- 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