
Les Custom Resource Definitions (CRDs) étendent Kubernetes avec de nouveaux types de ressources. En tant que développeur, vous n'avez pas besoin de créer des opérateurs, mais vous devez savoir utiliser les ressources custom que d'autres ont créées. Ce guide vous montre comment découvrir, manipuler et diagnostiquer les CRDs dans votre cluster.
Une précision de périmètre, qui évite de chercher ici ce qui est ailleurs. Cette page traite de l'utilisation des CRDs et des opérateurs, c'est-à-dire de ce qu'un développeur applicatif fait tous les jours. Écrire son propre opérateur est un autre métier, traité dans le guide Operators.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Le parcours va de la découverte des CRDs enregistrées dans un cluster jusqu'au déblocage d'une ressource en Terminating. Les exemples s'appuient sur des opérateurs répandus, cert-manager et le Prometheus Operator en tête, mais la mécanique reste identique quelle que soit l'extension installée.
- Comprendre le modèle CRD/Operator sans entrer dans le développement
- Découvrir les CRDs disponibles dans votre cluster
- Manipuler des ressources custom avec kubectl
- Installer un opérateur depuis OperatorHub
- Diagnostiquer les problèmes courants liés aux CRDs
CRD et Operator : l'essentiel pour un développeur
Section intitulée « CRD et Operator : l'essentiel pour un développeur »Deux objets distincts se cachent derrière le sujet : la CRD déclare un nouveau type auprès de l'API server, l'opérateur est le programme qui donne un sens à ce type en créant les ressources sous-jacentes. Sans opérateur, une CRD ne produit rien, elle se contente de stocker vos manifests.
Qu'est-ce qu'une CRD ?
Section intitulée « Qu'est-ce qu'une CRD ? »Une Custom Resource Definition (CRD) ajoute un nouveau type d'objet à Kubernetes. Au lieu de manipuler uniquement des Pods, Services ou Deployments, vous pouvez manipuler des objets métier comme PostgresCluster, Certificate ou GitRepository.
| Concept | Exemple |
|---|---|
| CRD | kind: PostgresCluster |
| Custom Resource (CR) | Un cluster PostgreSQL spécifique |
| Operator | Crée les Pods, Services, Secrets nécessaires |
Le pattern Controller
Section intitulée « Le pattern Controller »L'opérateur est un controller qui observe les ressources custom et agit pour atteindre l'état désiré :
La bonne nouvelle est que vous n'avez pas à lire le code de l'opérateur. Votre interface, ce sont les Custom Resources, donc des objets YAML comme ceux que vous écrivez déjà. L'opérateur porte la complexité derrière, exactement comme un moteur de base de données que l'on interroge sans connaître son format de stockage.
Découvrir les CRDs de votre cluster
Section intitulée « Découvrir les CRDs de votre cluster »Les types disponibles changent d'un cluster à l'autre selon les opérateurs installés. Avant d'écrire un manifest, il faut savoir quelles CRDs sont enregistrées, dans quelle version d'API elles sont servies, et si la ressource est namespacée ou globale.
Lister toutes les CRDs
Section intitulée « Lister toutes les CRDs »Le nom complet d'une CRD suit toujours la forme <pluriel>.<groupe d'API>, ce qui identifie d'un coup d'œil l'opérateur qui l'a posée. La colonne CREATED AT donne la date d'installation, pratique pour repérer une extension ajoutée récemment sur un cluster partagé.
# Toutes les CRDs installéeskubectl get crds
# Exemple de sortie :# NAME CREATED AT# certificates.cert-manager.io 2026-03-20T10:00:00Z# issuers.cert-manager.io 2026-03-20T10:00:00Z# postgresclusters.postgres-operator.crunchydata.com 2026-03-15T08:30:00ZExplorer une CRD spécifique
Section intitulée « Explorer une CRD spécifique »describe affiche les versions servies, la portée de la ressource et les shortnames déclarés. La sortie YAML complète contient en plus le schéma OpenAPI qui valide vos manifests : c'est lui qui provoque le rejet quand un champ est mal orthographié.
# Détails d'une CRDkubectl describe crd certificates.cert-manager.io
# Structure YAML de la CRDkubectl get crd certificates.cert-manager.io -o yamlDécouvrir les API groups
Section intitulée « Découvrir les API groups »kubectl api-resources liste tout ce que l'API server sait servir, ressources natives et custom confondues. La colonne NAMESPACED indique s'il faut préciser un namespace, et APIVERSION donne exactement la valeur à recopier dans le champ apiVersion de votre manifest.
# Tous les types de ressources disponibles (natifs + custom)kubectl api-resources
# Filtrer par API groupkubectl api-resources --api-group=cert-manager.io
# Exemple de sortie :# NAME SHORTNAMES APIVERSION NAMESPACED KIND# certificates cert cert-manager.io/v1 true Certificate# issuers cert-manager.io/v1 true IssuerBeaucoup de CRDs déclarent des shortnames, et ils font gagner un temps réel
en exploitation : kubectl get cert remplace kubectl get certificates. Ils ne
s'inventent pas, ils se découvrent avec kubectl api-resources, qui les affiche
dans une colonne dédiée.
Lister les ressources custom
Section intitulée « Lister les ressources custom »Une fois le type connu, les CRs se listent comme n'importe quel objet Kubernetes. L'option -A balaie tous les namespaces, réflexe utile quand vous ignorez où la ressource a été créée ; -o wide révèle les colonnes supplémentaires définies par la CRD elle-même, souvent l'état de la ressource.
# Lister les instances d'une CRkubectl get certificates -n mon-namespace
# Dans tous les namespaceskubectl get certificates -A
# Avec plus de détailskubectl get certificates -o wideInteragir avec des ressources custom
Section intitulée « Interagir avec des ressources custom »Une CR se manipule avec les verbes habituels : apply, get, describe, edit, patch, delete. La différence tient au partage du contenu : vous écrivez la spec, l'opérateur écrit le status, et toute modification de la spec relance sa boucle de réconciliation.
Créer une ressource custom
Section intitulée « Créer une ressource custom »Le format est identique aux ressources natives. Exemple avec cert-manager :
apiVersion: cert-manager.io/v1kind: Certificatemetadata: name: mon-app-tls namespace: productionspec: secretName: mon-app-tls-secret issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - mon-app.example.com - www.mon-app.example.comkubectl apply -f certificate.yamlInspecter une ressource custom
Section intitulée « Inspecter une ressource custom »describe reste le point d'entrée : il regroupe la spec, le status et les événements émis par l'opérateur, qui portent le motif exact d'un échec. Le JSONPath sert quand vous cherchez un champ précis, par exemple dans un script qui attend qu'une condition passe à True.
# Détails completskubectl describe certificate mon-app-tls -n production
# YAML brutkubectl get certificate mon-app-tls -n production -o yaml
# JSONPath pour extraire un champkubectl get certificate mon-app-tls -n production \ -o jsonpath='{.status.conditions[0].status}'Comprendre le champ status
Section intitulée « Comprendre le champ status »Les CRs bien conçues exposent un champ .status mis à jour par l'opérateur :
status: conditions: - type: Ready status: "True" reason: CertificateIssued message: Certificate is up to date and has been issued lastTransitionTime: "2026-03-25T10:30:00Z" notAfter: "2026-06-25T10:30:00Z" notBefore: "2026-03-25T10:30:00Z" renewalTime: "2026-05-25T10:30:00Z"La plupart des CRs adoptent le même motif pour exprimer leur état, le tableau
conditions. Plutôt que de lire tout le .status, cherchez donc l'entrée
dont le type vaut Ready :
kubectl get <kind> <nom> -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'C'est le même motif que celui des objets natifs, ce qui rend la commande réutilisable telle quelle d'une CRD à l'autre.
Modifier une ressource custom
Section intitulée « Modifier une ressource custom »edit ouvre le manifest dans votre éditeur et applique le résultat à la fermeture. patch --type=merge fait la même chose sans interaction, donc en script ; attention, sur une liste comme dnsNames, la fusion remplace le tableau entier au lieu d'y ajouter une entrée.
# Édition interactivekubectl edit certificate mon-app-tls -n production
# Patch (modifier un champ)kubectl patch certificate mon-app-tls -n production \ --type=merge \ -p '{"spec":{"dnsNames":["mon-app.example.com","api.example.com"]}}'Supprimer une ressource custom
Section intitulée « Supprimer une ressource custom »La commande rend la main aussitôt, mais l'objet peut rester en Terminating le temps que l'opérateur achève le nettoyage des ressources qu'il avait créées.
kubectl delete certificate mon-app-tls -n productionExemples de CRDs courantes
Section intitulée « Exemples de CRDs courantes »Les quatre extensions ci-dessous couvrent des besoins que Kubernetes ne traite pas nativement : certificats TLS, collecte de métriques, déploiement continu et récupération de secrets externes. Toutes suivent la même grammaire, un bloc spec déclaratif que l'opérateur traduit en objets natifs.
cert-manager : Certificats TLS
Section intitulée « cert-manager : Certificats TLS »L'objet Certificate décrit le certificat voulu, pas la façon de l'obtenir. issuerRef désigne l'autorité qui le délivrera, dnsNames les noms à couvrir, et secretName le Secret dans lequel cert-manager déposera la clé privée et le certificat une fois la validation aboutie.
apiVersion: cert-manager.io/v1kind: Certificatemetadata: name: api-tls namespace: productionspec: secretName: api-tls-secret issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - api.example.comPrometheus : ServiceMonitor
Section intitulée « Prometheus : ServiceMonitor »Un ServiceMonitor ne collecte rien par lui-même : il indique au Prometheus Operator quels Services interroger. Le selector cible ces Services par label, port reprend le nom du port déclaré dans le Service et non son numéro, ce qui est la cause d'erreur la plus fréquente sur cette ressource.
apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: name: mon-app namespace: monitoringspec: selector: matchLabels: app: mon-app endpoints: - port: metrics interval: 30sArgo CD : Application
Section intitulée « Argo CD : Application »L'objet Application relie un dépôt Git à un namespace de destination. Les deux options de syncPolicy.automated sont les plus lourdes de conséquences : prune autorise Argo CD à supprimer les objets retirés du dépôt, selfHeal annule toute modification faite directement sur le cluster.
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: mon-app namespace: argocdspec: project: default source: repoURL: https://github.com/mon-org/mon-app path: k8s targetRevision: HEAD destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true selfHeal: trueExternal Secrets : Intégration vault
Section intitulée « External Secrets : Intégration vault »Un ExternalSecret décrit une correspondance entre des chemins d'un coffre externe et les clés d'un Secret Kubernetes. L'opérateur relit la source à chaque refreshInterval et met à jour le Secret cible : la valeur sensible ne figure jamais dans le manifest, seul son emplacement y apparaît.
apiVersion: external-secrets.io/v1beta1kind: ExternalSecretmetadata: name: db-credentials namespace: productionspec: refreshInterval: 1h secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: db-credentials data: - secretKey: username remoteRef: key: secret/data/database property: username - secretKey: password remoteRef: key: secret/data/database property: passwordInstaller un opérateur
Section intitulée « Installer un opérateur »Installer un opérateur revient à poser deux choses : ses CRDs et le Deployment du controller, avec les droits RBAC qui vont avec. Les trois méthodes ci-dessous se distinguent surtout sur la mise à jour et sur le sort des CRDs à la désinstallation, car supprimer une CRD détruit au passage toutes les CRs de ce type.
Option 1 : Helm (recommandé)
Section intitulée « Option 1 : Helm (recommandé) »La plupart des opérateurs sont distribués via Helm :
# Exemple : cert-managerhelm repo add jetstack https://charts.jetstack.iohelm repo update
helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set crds.enabled=trueOption 2 : kubectl apply
Section intitulée « Option 2 : kubectl apply »Certains projets publient un manifeste unique qui contient tout, CRDs, déploiement
de l'opérateur et RBAC. C'est pratique pour un essai, et c'est aussi ce qui rend
la désinstallation et la montée de version plus délicates qu'avec Helm :
rien ne tient l'inventaire de ce qui a été créé, et un kubectl delete -f sur
une version différente du fichier laisse des objets derrière lui.
Épinglez toujours l'URL sur une version précise, jamais sur latest : un
manifeste qui change sous vos pieds rend vos déploiements non reproductibles.
# Exemple : metrics-serverkubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlOption 3 : OperatorHub (OpenShift / OLM)
Section intitulée « Option 3 : OperatorHub (OpenShift / OLM) »Si votre cluster utilise Operator Lifecycle Manager :
# Installer OLM (si pas déjà présent) : télécharger le script, l'inspecter, puis l'exécutercurl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.46.0/install.sh -o olm-install.shless olm-install.shbash olm-install.sh v0.46.0
# Installer un opérateur depuis OperatorHubkubectl create -f https://operatorhub.io/install/prometheus.yamlDiagnostiquer les problèmes
Section intitulée « Diagnostiquer les problèmes »Quand une CR ne produit pas l'effet attendu, le manifest est rarement en cause : l'API server l'aurait rejeté à l'apply si sa structure était invalide. Trois pistes couvrent la majorité des cas, l'opérateur ne tourne pas, la CRD n'est pas installée, ou les permissions RBAC du controller sont insuffisantes.
La CR reste en état Pending/Unknown
Section intitulée « La CR reste en état Pending/Unknown »Un objet accepté mais jamais traité signale que personne ne l'écoute. Regardez d'abord les événements de la CR, puis l'état du Pod de l'opérateur, enfin ses logs : c'est là qu'apparaissent les erreurs de validation métier ou d'accès à un service externe.
# 1. Vérifier les événements de la CRkubectl describe <kind> <name> -n <namespace>
# 2. Vérifier que l'opérateur tournekubectl get pods -n <operator-namespace>
# 3. Lire les logs de l'opérateurkubectl logs -n <operator-namespace> deployment/<operator-name>Erreur "no matches for kind" lors du kubectl apply
Section intitulée « Erreur "no matches for kind" lors du kubectl apply »Ce message vient de l'API server : le kind demandé n'est enregistré nulle part. Soit la CRD n'est pas installée, soit vous visez une version d'API que le cluster ne sert plus, cas courant après le passage d'un groupe de v1beta1 à v1.
# Le CRD n'est pas installékubectl get crd | grep <kind>
# Solution : installer l'opérateur d'abordLa CR est bloquée en Terminating
Section intitulée « La CR est bloquée en Terminating »Un finalizer suspend la suppression tant que l'opérateur n'a pas confirmé son nettoyage. Si le controller a été désinstallé avant ses ressources, plus personne ne retire ce marqueur et l'objet reste indéfiniment en Terminating, y compris son namespace s'il en contient d'autres.
# Vérifier les finalizerskubectl get <kind> <name> -o jsonpath='{.metadata.finalizers}'
# Si l'opérateur ne tourne plus, retirer le finalizer manuellementkubectl patch <kind> <name> \ --type=json \ -p='[{"op": "remove", "path": "/metadata/finalizers"}]'Problème de permissions
Section intitulée « Problème de permissions »Ce cas se reconnaît à un symptôme trompeur : la CR est acceptée par l'API,
elle apparaît dans kubectl get, et pourtant rien ne se passe. L'erreur n'est
pas sur votre objet mais dans les journaux de l'opérateur, qui échoue à créer
les ressources dérivées faute de droits. C'est la raison pour laquelle le
diagnostic d'une CR passe toujours par les logs de son contrôleur avant tout
autre chose.
# Vérifier les logs pour des erreurs RBACkubectl logs -n <operator-namespace> deployment/<operator-name> | grep -i forbidden
# Vérifier les Roles/ClusterRoles de l'opérateurkubectl get clusterrole | grep <operator-name>kubectl describe clusterrole <operator-role>Utiliser kubectl explain
Section intitulée « Utiliser kubectl explain »La commande kubectl explain fonctionne aussi avec les CRDs :
# Structure généralekubectl explain certificate
# Champ spécifiquekubectl explain certificate.spec.issuerRef
# Liste des champs disponibleskubectl explain certificate.spec --recursivekubectl explain est l'outil qui évite le plus d'allers-retours vers une
documentation web : il lit le schéma OpenAPI que la CRD a elle-même publié
dans le cluster, donc la structure réellement installée chez vous, version
comprise, et non celle d'une page qui peut décrire une autre version.
La contrepartie est que la qualité de l'aide dépend de l'auteur de la CRD,
pas de kubectl. Relevé sur une CRD dont un seul champ porte une description :
FIELDS: retentionJours <integer> <no description>
source <string> -required- Le volume a sauvegarderDeux enseignements pratiques. Le marqueur -required- signale les champs
obligatoires, ce qui évite un aller-retour par un manifeste refusé. Et un
<no description> ne veut pas dire que le champ est sans usage : il veut dire
que personne ne l'a documenté dans la CRD, auquel cas il faut se rabattre
sur la documentation du projet.
Les trois refus du schéma, et comment les distinguer
Section intitulée « Les trois refus du schéma, et comment les distinguer »L'API server valide chaque ressource custom contre le schéma de sa CRD, et le message nomme toujours le champ fautif. Les trois formes se ressemblent assez pour qu'on traite la mauvaise :
| Faute | Message rendu |
|---|---|
| Champ obligatoire absent | spec.source: Required value |
| Valeur hors des bornes | spec.retentionJours: Invalid value: 400: ... should be less than or equal to 365 |
| Type incorrect | spec.retentionJours: Invalid value: "string": ... must be of type integer |
La distinction qui compte : les deux dernières sont des erreurs de valeur, qu'on corrige dans le manifeste, alors que la première peut aussi signaler que vous visez la mauvaise version de la CRD, dont les champs requis diffèrent. Vérifiez la version servie avant de remplir un champ que vous ne comprenez pas.
Bonnes pratiques développeur
Section intitulée « Bonnes pratiques développeur »Les trois listes suivantes évitent les allers-retours les plus coûteux : un manifest rejeté faute de CRD, une ressource introuvable faute de convention de nommage, et une CR en échec silencieux parce que personne ne surveille son status.
Avant de créer une CR
Section intitulée « Avant de créer une CR »Ces quatre vérifications prennent moins d'une minute. Notez la limite de --dry-run=client : il contrôle la syntaxe YAML localement, sans jamais confronter le manifest au schéma OpenAPI de la CRD. Pour cette validation-là, il faut --dry-run=server, qui envoie l'objet à l'API server sans le persister.
- Vérifiez que la CRD existe :
kubectl get crd <name> - Lisez la documentation : Les CRDs ont souvent des exemples
- Utilisez kubectl explain : Pour comprendre les champs disponibles
- Validez avec
--dry-run:kubectl apply -f cr.yaml --dry-run=client
Nommage et organisation
Section intitulée « Nommage et organisation »Les CRs s'accumulent dans un namespace partagé sans le regroupement visuel qu'offre un Deployment avec ses Pods : rien n'indique quelle application a créé quel objet. Un préfixe applicatif et des labels cohérents rendent le filtrage possible, y compris pour les suppressions groupées.
- Préfixez par application :
mon-app-certificateplutôt quecertificate-1 - Utilisez des labels : Facilitez le filtrage et le monitoring
- Documentez : Ajoutez des annotations expliquant le but
Surveillance
Section intitulée « Surveillance »Une CR peut rester en échec sans que rien ne le signale : elle ne redémarre pas comme un Pod et n'apparaît dans aucun kubectl get pods. Suivre status.conditions est le seul moyen fiable de détecter un certificat non renouvelé ou une synchronisation qui échoue depuis des semaines.
- Surveillez les status : Les CRs exposent leur état dans
.status - Alertez sur les échecs : Conditions
Ready=FalseouFailed=True - Tracez les changements : Activez l'audit logging pour les CRs sensibles
À retenir
Section intitulée « À retenir »Le tableau condense le vocabulaire du modèle. Un point revient dans presque tous les incidents : une CR acceptée par l'API server ne signifie pas qu'elle a été traitée. Seul le status écrit par l'opérateur en atteste, et c'est lui qu'il faut lire avant de conclure que la ressource fonctionne.
| Concept | Ce qu'il faut retenir |
|---|---|
| CRD | Nouveau type de ressource Kubernetes |
| CR (Custom Resource) | Instance d'une CRD |
| Operator | Controller qui gère les CRs |
kubectl api-resources | Découvrir les types disponibles |
kubectl explain | Comprendre la structure d'une CR |
.status.conditions | État de la ressource |
| Finalizers | Retardent la suppression pour nettoyage |
Règle d'or : En tant que développeur, vous utilisez les CRs, vous n'avez pas besoin de comprendre le code de l'opérateur, seulement la spec que vous fournissez et le status qu'il retourne.
Testez vos connaissances
Section intitulée « Testez vos connaissances »Dix questions tirées de la banque CKAD portent sur la découverte des types, la lecture du status et le déblocage d'une ressource en Terminating. Comptez huit minutes et 70 % de bonnes réponses pour valider.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Troubleshooting cluster : Le diagnostic d'une Custom Resource acceptée par l'API mais jamais réconciliée.
- Admission Controllers : Les webhooks qui valident et transforment vos Custom Resources au moment de l'admission.