Contactez-nous

Introduction aux Custom Resource Definitions (CRDs) : Etendre l'API K8s

Découvrez comment les Custom Resource Definitions (CRDs) vous permettent d'étendre l'API Kubernetes pour définir et gérer vos propres types de ressources de manière native.

Pourquoi les ressources natives ne suffisent pas toujours ?

Kubernetes est livré avec un ensemble riche de ressources intégrées, telles que les Pods, Deployments, Services, ConfigMaps, Secrets, etc. Ces objets permettent de modéliser et de gérer un grand nombre d'applications et de configurations. Cependant, à mesure que l'écosystème Kubernetes s'est développé et que les utilisateurs ont cherché à gérer des systèmes de plus en plus complexes, les limites des ressources natives sont apparues.

Imaginez devoir gérer une flotte de bases de données clusterisées, des systèmes de cache spécialisés, ou même des configurations matérielles spécifiques via Kubernetes. Essayer de représenter ces concepts complexes uniquement avec des combinaisons de Deployments, StatefulSets et ConfigMaps peut devenir extrêmement lourd, contre-intuitif et difficile à automatiser de manière fiable. Il manque une façon de parler le "langage métier" de ces applications directement dans l'API Kubernetes.

C'est précisément le problème que les Custom Resource Definitions (CRDs) viennent résoudre. Elles offrent un mécanisme puissant pour étendre l'API Kubernetes, vous permettant de définir vos propres types d'objets (ressources) qui s'intègrent de manière transparente aux côtés des ressources natives.

Qu'est-ce qu'une Custom Resource Definition (CRD) ?

Une CRD est elle-même une ressource Kubernetes (apiVersion: apiextensions.k8s.io/v1, kind: CustomResourceDefinition). Lorsque vous créez une CRD dans votre cluster, vous demandez à l'API Server Kubernetes d'enregistrer un nouveau type de ressource personnalisé.

Une fois la CRD créée, l'API Server expose un nouvel endpoint REST dynamique pour votre nouveau type de ressource. Vous pouvez alors créer et gérer des objets de ce nouveau type, appelés Custom Resources (CRs), en utilisant kubectl et les mêmes outils et bibliothèques clientes que vous utilisez pour les ressources natives. Par exemple, si vous définissez une CRD pour un type DatabaseCluster, vous pourrez ensuite faire kubectl get databaseclusters ou kubectl apply -f my-database-cluster.yaml.

Il est essentiel de distinguer la CRD (la définition du type) de la CR (une instance de ce type). La CRD définit le schéma, les noms et la portée (Namespaced ou Cluster) de votre ressource personnalisée. La CR contient les données spécifiques d'une instance particulière de cette ressource, conformément au schéma défini dans la CRD.

Anatomie d'une CRD : Définir votre propre ressource

Regardons la structure typique d'un manifeste YAML pour une CRD. Prenons l'exemple conceptuel d'une ressource ApplicationBackup :

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # Le nom DOIT être au format: .
  name: applicationbackups.stable.example.com
spec:
  # group est le nom du groupe API (ex: batch, apps). Doit être unique.
  group: stable.example.com
  # versions est une liste des versions API supportées pour cette ressource
  versions:
    - name: v1alpha1 # Nom de la version
      served: true    # Cette version est exposée via l'API REST
      storage: true   # Cette version est stockée dans etcd
      schema:
        # openAPIV3Schema définit la structure et la validation
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                applicationName:
                  type: string
                  description: "Nom de l'application à sauvegarder"
                storageLocation:
                  type: string
                  description: "Emplacement de stockage de la sauvegarde (ex: S3 bucket)"
                schedule:
                  type: string
                  description: "Format Cron pour la planification (optionnel)"
              required:
                - applicationName
                - storageLocation
            status: # Section pour l'état observé
              type: object
              properties:
                lastBackupTime:
                  type: string
                  format: date-time
                phase:
                  type: string
                  enum: [Pending, Running, Completed, Failed]
  # scope peut être Namespaced (ressource dans un namespace) ou Cluster (ressource globale)
  scope: Namespaced
  # names définit les différents noms utilisés pour cette ressource
  names:
    plural: applicationbackups
    singular: applicationbackup
    kind: ApplicationBackup # Utilisé dans les manifestes de CR
    shortNames:
    - appbkp

Les éléments clés sont :

  • metadata.name : Doit suivre le format ..
  • spec.group : Le groupe API de votre ressource. Utilisez un nom de domaine inversé pour éviter les collisions.
  • spec.versions : Permet de gérer l'évolution de votre API. Chaque version a un nom, indique si elle est servie (served) et stockée (storage), et surtout définit son schéma via openAPIV3Schema.
  • spec.versions.schema.openAPIV3Schema : C'est le coeur de la définition. Il utilise la spécification OpenAPI v3 pour décrire la structure de votre ressource (champs, types, descriptions, champs requis, validations comme les énumérations, les patterns, etc.). Ce schéma est utilisé par l'API Server pour valider les CRs que vous créez et par kubectl explain.
  • spec.scope : Détermine si la ressource est liée à un Namespace (Namespaced) ou globale au cluster (Cluster). La plupart des ressources applicatives sont Namespaced.
  • spec.names : Définit comment nommer votre ressource : au pluriel (plural), au singulier (singular), le type (kind, utilisé dans le champ kind: des CRs) et des alias éventuels (shortNames).

Créer et interagir avec des Custom Resources (CRs)

Une fois que vous avez défini votre CRD dans un fichier (par exemple, appbackup-crd.yaml), vous l'appliquez au cluster :

kubectl apply -f appbackup-crd.yaml

Après quelques instants, l'API Server reconnaîtra votre nouvelle ressource. Vous pouvez alors créer un fichier YAML pour une instance de cette ressource (une Custom Resource ou CR), en utilisant l'apiVersion (group/version) et le kind que vous avez définis :

# my-backup-job.yaml
apiVersion: stable.example.com/v1alpha1 # Group/Version défini dans la CRD
kind: ApplicationBackup                 # Kind défini dans la CRD
metadata:
  name: daily-crm-backup
  namespace: prod
spec:
  applicationName: crm-database
  storageLocation: s3://my-backup-bucket/crm
  schedule: "0 2 * * *" # Tous les jours à 2h du matin

Vous créez ensuite cette CR comme n'importe quelle autre ressource Kubernetes :

kubectl apply -f my-backup-job.yaml

Et vous pouvez interagir avec elle en utilisant les commandes kubectl standard :

# Lister toutes les sauvegardes dans le namespace prod
kubectl get applicationbackups -n prod
kubectl get appbkp -n prod # Utiliser le shortName

# Obtenir les détails d'une sauvegarde spécifique
kubectl get applicationbackup daily-crm-backup -n prod -o yaml

# Décrire la sauvegarde (affiche Spec et Status si un contrôleur le remplit)
kubectl describe applicationbackup daily-crm-backup -n prod

# Expliquer les champs disponibles (utilise le schéma de la CRD)
kubectl explain applicationbackup
kubectl explain applicationbackup.spec

# Supprimer la sauvegarde
kubectl delete applicationbackup daily-crm-backup -n prod

CRDs : Les fondations de l'automatisation avancée

Les CRDs sont extrêmement puissantes car elles vous permettent de modéliser n'importe quel concept ou processus de manière déclarative, directement dans l'API Kubernetes. Cela offre plusieurs avantages :

  • Cohérence de l'API : Vos ressources personnalisées se comportent comme des ressources natives.
  • Configuration Déclarative : Vous définissez l'état désiré dans un fichier YAML, et le système (via un contrôleur/Operator) travaille pour l'atteindre.
  • Intégration avec l'Ecosystème Kubernetes : Les CRs bénéficient automatiquement des fonctionnalités de base de Kubernetes comme le contrôle d'accès basé sur les rôles (RBAC), les labels et sélecteurs, les annotations, l'audit, etc.
  • Validation Intégrée : Le schéma OpenAPI dans la CRD permet à l'API Server de valider les CRs à la création et à la mise à jour, évitant les erreurs de configuration.

Il est crucial de comprendre qu'une CRD, en elle-même, ne fait que définir un nouveau type de ressource et permettre le stockage d'objets de ce type dans etcd. Elle n'ajoute aucune logique métier ou automatisation par défaut. Créer une CR ApplicationBackup ne déclenche pas magiquement une sauvegarde.

C'est là qu'intervient le pattern Operator : pour rendre ces ressources personnalisées réellement utiles, vous devez écrire un contrôleur personnalisé (un Operator) qui surveille ces CRs et exécute la logique nécessaire pour atteindre l'état désiré décrit dans la spec de la CR, et met à jour le champ status pour refléter l'état observé. Les CRDs sont donc la fondation sur laquelle repose le pattern Operator pour créer des automatisations natives à Kubernetes.