Formulaire dynamique : créer n'importe quelle ressource Kubernetes
Ma console avait déjà un éditeur YAML. Mais écrire du YAML à la main, c’est pas toujours fun. Surtout quand tu connais pas la structure exacte d’une ressource.
J’ai voulu un formulaire qui s’adapte automatiquement au type de ressource que tu veux créer.
L’idée
Au lieu d’écrire du YAML, tu :
- Sélectionnes le type de ressource (Pod, Deployment, Service…)
- Remplis un formulaire qui s’adapte automatiquement
- Le système génère le YAML pour toi
Le formulaire doit être intelligent : comprendre les champs obligatoires, proposer les bonnes valeurs par défaut, gérer les objets imbriqués.
Le défi technique
Kubernetes a des centaines de types de ressources. Chacun avec sa propre structure. Comment générer un formulaire pour tous ?
La solution : utiliser les schémas OpenAPI de Kubernetes. Chaque ressource a un schéma qui décrit sa structure. Il suffit de le parser et de générer les champs.
L’architecture
┌─────────────────────┐
│ Frontend React │
│ - ResourceSelector │
│ - DynamicForm │
│ - YAMLGenerator │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Backend Go │
│ - kubectl explain │
│ - Schema parser │
└─────────────────────┘
1. Sélection du type de ressource
Le frontend charge tous les types disponibles depuis l’API :
const response = await axios.get('/api/v1/resources/types')
// Retourne : Pod, Deployment, Service, Ingress...
L’utilisateur choisit dans une liste avec recherche et filtres par catégorie (Core, Apps, Networking…).
2. Récupération du schéma
Une fois le type sélectionné, on récupère son schéma OpenAPI depuis l’API Kubernetes :
// Backend utilise l'API OpenAPI de Kubernetes
openAPISchema, err := k8sClient.Discovery().OpenAPISchema()
// Parse le schéma pour trouver la définition de la ressource
schemaName := fmt.Sprintf("io.k8s.api.core.v1.%s", kind)
schema := definitions[schemaName]
Pourquoi l’API OpenAPI ? Parce que c’est la source de vérité. Kubernetes expose directement les schémas de toutes les ressources via son API Discovery.
3. Parsing du schéma
Le schéma OpenAPI décrit la structure :
{
"properties": {
"metadata": {
"properties": {
"name": {"type": "string", "required": true},
"namespace": {"type": "string"}
}
},
"spec": {
"properties": {
"containers": {
"type": "array",
"items": {
"properties": {
"name": {"type": "string"},
"image": {"type": "string"}
}
}
}
}
}
}
}
Le parser extrait :
- Les champs obligatoires vs optionnels
- Les types (string, number, boolean, array, object)
- Les descriptions pour l’aide contextuelle
- Les valeurs par défaut
4. Génération du formulaire
Selon le type de champ, on génère le bon input :
switch (fieldType) {
case 'string':
return <input type="text" />
case 'number':
return <input type="number" />
case 'boolean':
return <checkbox />
case 'array':
return <ArrayField /> // Avec bouton "Ajouter"
case 'object':
return <CollapsibleSection /> // Section repliable
}
Pour les objets complexes (comme spec.containers), on crée des sections repliables avec des sous-formulaires.
5. Gestion des arrays
Les arrays sont complexes. Par exemple, spec.containers est un array d’objets :
{containers.map((container, index) => (
<div key={index}>
<input name={`containers[${index}].name`} />
<input name={`containers[${index}].image`} />
<button onClick={() => removeContainer(index)}>Supprimer</button>
</div>
))}
<button onClick={addContainer}>Ajouter un container</button>
Chaque élément de l’array a son propre sous-formulaire.
6. Génération YAML
Une fois le formulaire rempli, on convertit les données en YAML :
import yaml from 'js-yaml'
const yamlStr = yaml.dump({
apiVersion: 'v1',
kind: 'Pod',
metadata: { name: formData.name },
spec: { containers: formData.containers }
})
Le YAML généré est propre, indenté correctement, avec les valeurs vides supprimées.
Exemple concret : créer un Pod
- Sélection : “Pod” dans la liste
- Formulaire généré :
- Name (obligatoire) :
mon-pod - Namespace :
default - Section “Spec” (repliable)
- Containers (array)
- Container 1 :
- Name :
nginx - Image :
nginx:latest - Ports (array) :
- Port :
80
- Port :
- Name :
- Container 1 :
- Containers (array)
- Name (obligatoire) :
- YAML généré :
apiVersion: v1
kind: Pod
metadata:
name: mon-pod
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
- Déploiement : Un clic et c’est déployé !
Les défis
1. Schémas complexes
Certaines ressources ont des structures très imbriquées. Par exemple, un Deployment avec des volumes, des env vars, des probes…
Solution : Sections repliables. L’utilisateur ouvre seulement ce dont il a besoin.
2. Champs conditionnels
Certains champs n’apparaissent que si un autre champ a une valeur spécifique.
Solution : Pour l’instant, on affiche tout. L’amélioration future serait de gérer les conditions.
3. Validation
Il faut valider que le formulaire est correct avant de générer le YAML.
Solution : Validation côté frontend (champs obligatoires) + validation Kubernetes côté backend.
L’intégration dans la console
Le formulaire est accessible dans l’onglet “Créer une ressource” :
- Sélection du type
- Formulaire dynamique
- Prévisualisation YAML
- Déploiement direct ou copie dans l’éditeur YAML
Ce que ça change
Avant :
- Chercher la doc Kubernetes
- Copier-coller un exemple YAML
- Modifier à la main
- Espérer que ça marche
Après :
- Sélectionner le type
- Remplir le formulaire
- Déployer
C’est pas révolutionnaire, mais c’est pratique. Surtout pour les ressources qu’on utilise pas souvent et dont on connaît pas la structure par cœur.
Les limites
- Les Custom Resources (CRDs) : ça marche si le schéma est disponible
- Les champs très complexes : parfois plus rapide d’écrire le YAML
- Pas de templates : chaque création part de zéro
L’évolution
À terme, j’aimerais :
- Sauvegarder des templates de formulaires
- Prévisualisation en temps réel du YAML
- Validation avancée avec messages d’erreur clairs
- Support des Custom Resources
Mais pour l’instant, ça fait le job. Et c’est un bon exemple de ce qu’on peut faire avec les schémas OpenAPI de Kubernetes.
Prochain article : Architecture complète - comment tout s’articule dans mon homelab.