Introduction
Les définitions de ressources personnalisées (Custom Resource Definitions, CRD) de Kubernetes étendent l'API Kubernetes, permettant aux équipes plateforme et aux développeurs de modéliser des ressources spécifiques à un domaine. Cependant, la gestion des CRD dans les pipelines CI/CD présente des défis uniques : évolution des schémas, dépendance à l'ordre des contrôleurs, conversion des versions d'API et sécurité des retours en arrière. Cet article fournit des conseils opérationnels pratiques pour automatiser la gestion du cycle de vie des CRD, de la validation initiale au déploiement progressif et à la récupération.
Nous couvrirons l'inventaire des versions et de l'environnement, les modèles de configuration sûrs, la vérification et les diagnostics, les modes de défaillance avec des procédures de récupération, et une liste de contrôle opérationnelle pour la mise en production. Chaque section comprend des commandes kubectl concrètes, des exemples de manifestes, les sorties attendues et les points de décision. Les pratiques décrites ici s'adressent aux développeurs, consultants DevOps et équipes techniques de startups qui doivent livrer des modifications de CRD en toute confiance.
Inventaire des versions et de l'environnement
Avant d'automatiser toute modification de CRD, établissez un état des lieux de la configuration actuelle de votre cluster. Cet inventaire évite les suppositions et permet de prendre des décisions de retour en arrière.
Identifier la version du cluster et la compatibilité de l'API CRD
Commencez par enregistrer la version du serveur Kubernetes et celle des contrôleurs ou opérateurs pertinents.
kubectl version --short
# Exemple de sortie :
# Client Version: v1.28.2
# Server Version: v1.27.5
Vérifiez la version de l'API apiextensions.k8s.io prise en charge pour les CRD. Dans Kubernetes 1.16+, apiextensions.k8s.io/v1 est stable ; les versions plus anciennes peuvent utiliser v1beta1. Utilisez kubectl api-versions pour lister les groupes d'API disponibles.
kubectl api-versions | grep apiextensions
# apiextensions.k8s.io/v1
Inventorier les CRD existantes et leurs versions de stockage
Listez toutes les CRD et leur version de stockage actuelle. La version de stockage détermine comment les objets sont persistés.
kubectl get crd -o custom-columns=NAME:.metadata.name,GROUP:.spec.group,STORAGE:.spec.versions[*].storage
# Exemple de sortie :
# NAME GROUP STORAGE
# appconfigs.example.com example.com true,false
# backups.example.com example.com true
Pour une CRD spécifique, inspectez les détails de ses versions et préservez les champs inconnus.
kubectl get crd appconfigs.example.com -o yaml | grep -A5 versions:
# versions:
# - name: v1alpha1
# served: true
# storage: false
# - name: v1beta1
# served: true
# storage: true
Collecter les ressources prérequises et les RBAC
Les modifications de CRD nécessitent souvent des règles RBAC mises à jour pour les contrôleurs. Capturez les rôles et rôles de cluster actuels qui interagissent avec le groupe d'API de la CRD.
kubectl get clusterrole,role -l app=crd-controller -o yaml
# ou par groupe d'API :
kubectl get clusterrole -o yaml | grep -B2 'example.com'
Vérifiez si des webhooks d'admission sont configurés pour la CRD, car ils peuvent bloquer les mises à jour.
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations -o yaml | grep -B3 'example.com'
Documenter l'état actuel avec horodatage
Créez un répertoire d'instantané avec horodatage.
TIMESTAMP=$(date +%Y%m%d%H%M%S)
mkdir -p inventory-$TIMESTAMP
kubectl get crd -o yaml > inventory-$TIMESTAMP/crds.yaml
kubectl get deploy,sts,ds -n crd-controller-system -o yaml > inventory-$TIMESTAMP/controllers.yaml
kubectl get cm,secret -n crd-controller-system -o yaml > inventory-$TIMESTAMP/configs.yaml
Cet instantané est votre référence pour le retour en arrière. Stockez-le dans un système de contrôle de version ou un stockage d'objets.
Chemin de configuration sûr
Un chemin de configuration sûr garantit que chaque modification est cadrée, révisable et réversible. Pour les CRD, cela implique le versionnage, la validation du schéma et un déploiement progressif.
Utiliser des manifestes de CRD versionnés avec des schémas structurels
Spécifiez toujours un schéma structurel dans votre CRD. Cela permet la validation et la conversion future. Exemple de CRD minimale :
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: appconfigs.example.com
spec:
group: example.com
names:
kind: AppConfig
listKind: AppConfigList
plural: appconfigs
singular: appconfig
scope: Namespaced
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
minimum: 1
image:
type: string
required: ["replicas", "image"]
Utilisez kubectl apply --dry-run=server pour valider sans persister.
kubectl apply -f crd.yaml --dry-run=server
# Attendu : customresourcedefinition.apiextensions.k8s.io/appconfigs.example.com created (server dry run)
Maintenir plusieurs versions d'API avec stratégie de conversion
Si vous devez prendre en charge des clients sur différentes versions, définissez plusieurs versions et la conversion. Pour de simples changements de champs, la conversion None peut suffire.
spec:
versions:
- name: v1alpha1
served: true
storage: false
schema: ...
- name: v1beta1
served: true
storage: true
schema: ...
conversion:
strategy: None
Pour des changements complexes, utilisez un webhook de conversion et testez-le rigoureusement.
Appliquer le principe du moindre privilège RBAC
Créez des rôles dédiés pour les pipelines CI/CD qui n'autorisent que des opérations spécifiques sur la CRD et ses ressources.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: crd-deployer
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch", "create", "patch"]
- apiGroups: ["example.com"]
resources: ["appconfigs", "appconfigs/status"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
Évitez cluster-admin pour les comptes de service du pipeline.
Déploiements progressifs avec canary et livraison progressive
Appliquez les modifications de CRD à un espace de noms ou un cluster de staging d'abord. Utilisez kubectl apply --server-side pour des mises à jour atomiques si nécessaire.
kubectl apply -f crd.yaml --server-side --field-manager=ci-pipeline
Surveillez la santé du contrôleur avant de promouvoir.
kubectl rollout status deployment/crd-controller -n crd-controller-system --timeout=60s
# Attendu : deployment "crd-controller" successfully rolled out
Vérification et diagnostics
La vérification garantit que votre modification de CRD se comporte comme prévu. Utilisez une combinaison de vérifications déclaratives et de création réelle de ressources.
Valider l'existence de la CRD et son schéma
Après l'application, confirmez que la CRD est établie et acceptée.
kubectl get crd appconfigs.example.com -o jsonpath='{.status.conditions[?(@.type=="Established")].status}'
# Attendu : True
kubectl get crd appconfigs.example.com -o jsonpath='{.status.conditions[?(@.type=="NamesAccepted")].status}'
# Attendu : True
Vérifiez les versions stockées.
kubectl get crd appconfigs.example.com -o jsonpath='{.status.storedVersions}'
# Attendu : ["v1beta1"] si v1beta1 est la version de stockage
Créer une ressource personnalisée de test
Créez une ressource d'exemple pour vérifier la validation et le comportement du contrôleur.
apiVersion: example.com/v1beta1
kind: AppConfig
metadata:
name: test-appconfig
namespace: default
spec:
replicas: 2
image: nginx:1.21
kubectl apply -f test-cr.yaml
kubectl get appconfig test-appconfig -o yaml
Si le contrôleur de CRD définit un statut, vérifiez-le.
kubectl get appconfig test-appconfig -o jsonpath='{.status.conditions}'
Tester les échecs de validation
Créez intentionnellement une ressource invalide pour vous assurer que le schéma est appliqué.
apiVersion: example.com/v1beta1
kind: AppConfig
metadata:
name: bad-appconfig
spec:
replicas: 0 # viole le minimum de 1
kubectl apply -f bad-cr.yaml
# Erreur attendue :
# The AppConfig "bad-appconfig" is invalid: spec.replicas: Invalid value: 0: spec.replicas in body should be greater than or equal to 1
Diagnostiquer les problèmes du contrôleur
Si les ressources ne sont pas réconciliées, inspectez les journaux du contrôleur.
kubectl logs -n crd-controller-system deploy/crd-controller --tail=50
# Recherchez des erreurs comme "failed to list appconfigs" ou des erreurs de conversion.
Vérifiez les événements dans l'espace de noms.
kubectl get events -n default --sort-by=.lastTimestamp | grep appconfig
Modes de défaillance et récupération
Planifiez les défaillances avant qu'elles ne surviennent. Voici les modes de défaillance courants des CRD en CI/CD et les étapes de récupération.
Défaillance : Mise à jour de la CRD rejetée en raison d'un schéma invalide
Symptôme : kubectl apply renvoie une erreur 422 ou 400 avec des détails.
Récupération :
- Validez le manifeste avec
kubectl apply --dry-run=server. - Corrigez le schéma en fonction des messages d'erreur.
- Réappliquez.
Exemple :
The CustomResourceDefinition "appconfigs.example.com" is invalid: spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.replicas.type: Required value: must not be empty for specified object fields
Défaillance : Le contrôleur ne peut pas réconcilier la nouvelle version de stockage
Symptôme : La CRD s'applique, mais status.conditions montre NonStructuralSchema ou les journaux du contrôleur montrent des erreurs de conversion.
Récupération :
- Vérifiez
kubectl get crd appconfigs.example.com -o yamlpour les conditions de statut. - Si
NonStructuralSchemaest vrai, inspectez le schéma pour des champs non pris en charge (par exemple,nullable: trueà certains endroits) et corrigez. - En cas d'erreurs de conversion, assurez-vous que le webhook de conversion est joignable et renvoie des réponses appropriées.
- Si nécessaire, revenez au manifeste de CRD précédent :
kubectl apply -f backup/crds.yaml.
Défaillance : Un changement radical supprime une version servie encore utilisée
Symptôme : Les clients utilisant l'ancienne version d'API obtiennent une erreur 404 ou no kind is registered.
Récupération :
- Identifiez les clients via les journaux d'audit ou les requêtes d'admission.
- Rétablissez temporairement la version servie : définissez
served: truepour l'ancienne version et réappliquez. - Coordonnez la migration des clients, puis dépréciez à nouveau dans une version future.
Procédure de retour en arrière pour les CRD
Comme les CRD sont à portée de cluster, le retour en arrière doit être prudent.
- Restaurez le manifeste de CRD de sauvegarde.
kubectl apply -f inventory-$TIMESTAMP/crds.yaml
- Assurez-vous que la version de stockage est définie sur la précédente.
- Attendez que la condition
Establishedsoit vraie. - Vérifiez que les contrôleurs sont sains.
- Supprimez toutes les ressources personnalisées créées avec une version désormais non servie (si nécessaire, après sauvegarde).
Défaillance : Le compte de service du pipeline manque de permissions
Symptôme : Le job CI échoue avec forbidden: User "system:serviceaccount:ci:deployer" cannot create resource "customresourcedefinitions".
Récupération :
- Examinez le Role/RoleBinding utilisé par le pipeline.
- Ajoutez les groupes d'API et verbes requis.
- Appliquez les modifications RBAC et relancez le pipeline.
Liste de contrôle opérationnelle
Utilisez cette liste avant et après les modifications d'automatisation des CRD pour garantir la sécurité opérationnelle.
Liste de contrôle pré-déploiement
- [ ] Version du cluster et compatibilité API documentées.
- [ ] CRD existantes et versions de stockage inventoriées.
- [ ] Sauvegarde des YAML de CRD actuels stockée.
- [ ] Nouveau manifeste de CRD utilisant
apiextensions.k8s.io/v1et schéma structurel. - [ ] Modifications de schéma validées avec
kubectl apply --dry-run=server. - [ ] RBAC mis à jour pour le contrôleur et le pipeline.
- [ ] Stratégie de conversion définie si plusieurs versions.
- [ ] Plan de retour en arrière documenté avec commandes exactes.
Exécution du déploiement
# 1. Appliquer la CRD
kubectl apply -f crd.yaml --server-side
# 2. Attendre que la CRD soit établie
kubectl wait --for=condition=Established --timeout=60s crd/appconfigs.example.com
# 3. Déployer/mettre à jour le contrôleur si nécessaire
kubectl apply -f controller-deployment.yaml
kubectl rollout status deploy/crd-controller -n crd-controller-system --timeout=120s
# 4. Créer une CR de test de fumée
kubectl apply -f test-cr.yaml
kubectl wait --for=condition=Ready --timeout=30s appconfig/test-appconfig
Vérification post-déploiement
- [ ] Condition
Establishedde la CRD est vraie. - [ ] CR de test créée et réconciliée.
- [ ] Ressource invalide correctement rejetée.
- [ ] Journaux du contrôleur sans nouvelles erreurs.
- [ ] Ressources personnalisées existantes toujours accessibles et saines.
- [ ] Les métriques/alertes ne montrent aucun pic d'erreurs API.
Surveillance continue
Configurez des alertes pour :
- Erreurs de l'API
apiextensions.k8s.io/v1(apiserver_request_totalavecgroup=example.comet code >= 400). - Échecs de réconciliation du contrôleur.
- Latence des webhooks si des webhooks de conversion sont utilisés.
Exemple de règle d'alerte Prometheus :
- alert: CRDControllerDown
expr: up{job="crd-controller"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "CRD controller is down"
Conclusion
L'automatisation du CI/CD des CRD Kubernetes exige de la discipline en matière de versionnage, de validation, de déploiement et de récupération. En inventoriant votre état actuel, en suivant un chemin de configuration sûr, en vérifiant avec des signaux concrets et en préparant des procédures pour les défaillances courantes, vous réduisez le risque d'incohérence de l'API et de perturbation du contrôleur.
Commencez petit : choisissez une amélioration de CRD à faible risque, appliquez la liste de contrôle et mesurez le résultat. À mesure que votre confiance grandit, intégrez ces pratiques dans vos pipelines GitOps avec des tests automatisés et une livraison progressive. L'objectif n'est pas seulement de déployer des CRD, mais de les exploiter de manière sûre et réversible.