## Introduction

Les quotas de ressources Kubernetes (Resource Quotas) sont essentiels pour éviter qu'une seule équipe ou un seul namespace ne consomme excessivement les ressources du cluster. Cependant, gérer les quotas manuellement sur de nombreux namespaces est source d'erreurs et prend du temps. Automatiser la gestion des quotas avec CI/CD garantit des changements cohérents, auditables et reproductibles. Cet article fournit un guide pratique et concret pour construire un pipeline CI/CD pour les quotas de ressources, couvrant l'inventaire de l'environnement, la configuration sécurisée, la vérification, la récupération en cas d'échec et une liste de contrôle opérationnelle. Nous utiliserons des commandes, des manifestes et des exemples concrets pour que vous puissiez adapter le flux de travail à vos propres clusters.

## Inventaire des versions et de l'environnement

Avant d'automatiser les changements de quotas, vous devez comprendre votre environnement actuel. Cette section explique comment collecter les informations de version, de topologie et les prérequis à l'aide de commandes en lecture seule, puis planifier le plus petit changement sûr.

### Prérequis

- Cluster Kubernetes version 1.21 ou supérieure (l'API Resource Quota est stable depuis la v1, mais certaines fonctionnalités comme les sélecteurs d'étendue peuvent varier). Vérifiez avec :

kubectl version --short 
 Sortie attendue :

Client Version: v1.27.0
 Server Version: v1.27.0 

- kubectl configuré avec les permissions RBAC appropriées pour obtenir, lister et créer des objets ResourceQuota dans les namespaces cibles.

- Un dépôt Git pour stocker les manifestes YAML des quotas et les définitions du pipeline.

- Un système CI/CD (par exemple, GitHub Actions, GitLab CI, Jenkins) avec un compte de service disposant de droits limités sur le cluster.

### Observation en lecture seule

 Commencez par inspecter les quotas de ressources existants dans un namespace sans rien modifier. Par exemple, dans le namespace team-a :

kubectl get resourcequota -n team-a 
 Si aucun quota n'existe, vous verrez :

No resources found in team-a namespace. 
 Si des quotas existent, la sortie ressemblera à :

NAME AGE REQUEST LIMIT
compute-quota 10d requests.cpu: 2/4, requests.memory: 2Gi/4Gi limits.cpu: 4/8, limits.memory: 4Gi/8Gi 
 Obtenez les détails d'un quota spécifique :

kubectl describe resourcequota compute-quota -n team-a 
 Notez les valeurs utilisées (Used) et dures (Hard). Cela vous indique à quel point vous êtes proche des limites avant tout changement.

Inspectez également les libellés du namespace, car les quotas peuvent être limités par sélecteur de namespace si vous utilisez ResourceQuota avec scopeSelector (plus de détails plus loin). Vérifiez les libellés :

kubectl get namespace team-a --show-labels 

### Rayon d'impact et plus petit changement

 Modifier un quota de ressources affecte tous les pods de ce namespace : les nouveaux pods peuvent être rejetés s'ils dépassent le quota, mais les pods existants ne sont pas expulsés automatiquement. Le rayon d'impact est à l'échelle du namespace. Par conséquent, le plus petit changement justifié pourrait être d'ajouter un nouveau quota pour une ressource spécifique plutôt que de modifier un quota existant. Par exemple, si vous devez limiter le nombre de demandes de volumes persistants, créez un objet quota séparé au lieu de modifier le quota de calcul.

Exemple de nouveau quota minimal YAML ( pvc-quota.yaml ) :

apiVersion: v1
kind: ResourceQuota
metadata:
 name: pvc-quota
 namespace: team-a
spec:
 hard:
 persistentvolumeclaims: "5" 
 Appliquez d'abord ceci manuellement dans un namespace de test pour vérifier le comportement, puis automatisez.

### Commande de vérification

Après tout changement, vérifiez que le quota est actif et correctement configuré :

kubectl get resourcequota pvc-quota -n team-a -o yaml 
 Vérifiez les champs spec.hard et status.used .

<style>
.eno-quiz-widget{margin:2rem 0;padding:1.5rem;border-radius:12px;background:var(--eno-surface-lowest,#f7f7f8);border:1px solid var(--eno-border-soft,#e2e2e6);font-family:var(--eno-font-body,Inter,sans-serif)}
.eno-quiz-widget .eno-quiz-kicker{font-family:var(--eno-font-label,"JetBrains Mono",monospace);font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;color:var(--eno-text-muted,#5f5f68);margin:0 0 .5rem}
.eno-quiz-widget .eno-quiz-question{font-family:var(--eno-font-heading,"Hanken Grotesk",sans-serif);font-size:1.0625rem;font-weight:600;margin:0 0 1rem;color:var(--eno-text-strong,#1a1a1f)}
.eno-quiz-widget .eno-quiz-options{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.eno-quiz-widget .eno-quiz-option{display:block;width:100%;min-height:44px;text-align:left;padding:.625rem .875rem;border-radius:8px;border:1.5px solid var(--eno-border-soft,#e2e2e6);background:#fff;font-size:.9375rem;cursor:pointer;transition:border-color var(--eno-motion-base,180ms ease-out),background var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-option:hover{border-color:var(--eno-primary,#0059bb)}
.eno-quiz-widget .eno-quiz-option:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-option[aria-pressed="true"]{border-color:var(--eno-primary,#0059bb);background:rgb(0 89 187 / 0.06)}
.eno-quiz-widget .eno-quiz-option[data-correct="true"].eno-quiz-revealed{border-color:var(--eno-success,#17803a);background:rgb(23 128 58 / 0.08)}
.eno-quiz-widget .eno-quiz-option[data-correct="false"].eno-quiz-revealed.eno-quiz-was-selected{border-color:var(--eno-error,#ba1a1a);background:var(--eno-error-soft,#ffdad6)}
.eno-quiz-widget .eno-quiz-option-icon{display:inline-block;width:1.1em;margin-right:.4em;font-weight:700}
.eno-quiz-widget .eno-quiz-submit{margin-top:1rem;min-height:44px;padding:.5rem 1.25rem;border-radius:8px;border:none;background:var(--eno-primary,#0059bb);color:#fff;font-weight:600;font-size:.9375rem;cursor:pointer;transition:opacity var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-submit:disabled{opacity:.5;cursor:not-allowed}
.eno-quiz-widget .eno-quiz-submit:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-explanation{margin-top:1rem;padding:.875rem 1rem;border-radius:8px;font-size:.9375rem;line-height:1.5;display:none}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-visible{display:block}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-correct{background:rgb(23 128 58 / 0.08);color:var(--eno-success,#17803a)}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-incorrect{background:var(--eno-error-soft,#ffdad6);color:var(--eno-error,#ba1a1a)}
@media (prefers-reduced-motion: reduce){.eno-quiz-widget *{transition:none!important}}
</style><div class="eno-quiz-widget" role="group" aria-label="Question rapide">
Question rapide 1 sur 2

Quel est le code de statut HTTP renvoyé lorsqu'une création de ressource viole une contrainte de quota ?

- 400 Bad Request
- 403 Forbidden
- 429 Too Many Requests
- 500 Internal Server Error

<button type="button" class="eno-quiz-submit" disabled>Valider</button>
<div class="eno-quiz-explanation">La référence indique que si la création ou la mise à jour d&#39;une ressource viole une contrainte de quota, le plan de contrôle rejette la requête avec le code de statut HTTP 403 Forbidden.</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Chemin de configuration sûr

Cette section détaille comment gérer les configurations de quotas de ressources en toute sécurité dans un pipeline CI/CD, en garantissant que chaque changement est revu, testé et appliqué avec un plan de restauration.

### Structure du dépôt

Organisez vos manifestes de quotas dans un dépôt Git avec une structure de répertoires claire. Par exemple :

quotas/
 team-a/
 compute-quota.yaml
 pvc-quota.yaml
 team-b/
 compute-quota.yaml
 global/
 default-quotas.yaml 
 Chaque fichier doit contenir une ou plusieurs définitions ResourceQuota avec le namespace spécifié dans les métadonnées. Alternativement, utilisez Kustomize ou Helm pour gérer les surcharges spécifiques au namespace.

### Étapes du pipeline

Un pipeline CI/CD typique pour les quotas de ressources comporte ces étapes :

- Lint : Valider la syntaxe YAML et le schéma Kubernetes.

- Dry-run : Utiliser kubectl apply --dry-run=client pour vérifier les erreurs d'API.

- Appliquer au staging : Déployer d'abord sur un cluster ou namespace de staging.

- Test de fumée : Vérifier que les quotas sont créés et appliqués comme prévu.

- Approbation : Exiger une approbation manuelle avant la production.

- Appliquer en production : Déployer avec --server-side en option pour éviter les conflits.

- Enregistrer : Stocker les manifestes appliqués et les sorties pour l'audit.

### Exemple de pipeline (GitHub Actions)

Créez un fichier de workflow .github/workflows/quota-deploy.yaml :

name: Deploy Resource Quotas
on:
 push:
 paths:
 - 'quotas/**'
 branches:
 - main
 workflow_dispatch:

jobs:
 deploy:
 runs-on: ubuntu-latest
 environment: production
 steps:
 - uses: actions/checkout@v3
 - name: Set up kubectl
 uses: azure/setup-kubectl@v3
 with:
 version: 'v1.27.0'
 - name: Dry-run apply
 run: |
 set -e
 for file in $(find quotas -name '*.yaml'); do
 echo "Dry-run applying $file"
 kubectl apply -f $file --dry-run=client
 done
 - name: Apply to production
 run: |
 for file in $(find quotas -name '*.yaml'); do
 kubectl apply -f $file
 done 
 Dans cet exemple, le pipeline s'exécute à chaque push sur main affectant les fichiers de quotas. Il effectue d'abord un dry-run de tous les manifestes, puis les applique. Vous pouvez ajouter une étape d'approbation manuelle en utilisant les règles de protection des environnements GitHub.

### Stratégie de restauration

Les changements de quotas sont faciles à annuler si vous utilisez des tags Git ou conservez les versions précédentes dans le dépôt. Pour annuler, appliquez simplement la version précédente du manifeste :

git revert <commit-hash>
kubectl apply -f quotas/team-a/compute-quota.yaml 
 Si le quota a été supprimé accidentellement, réappliquez-le depuis Git. Comme les objets ResourceQuota sont déclaratifs, l'application de l'ancien manifeste restaure l'état souhaité.

## Vérification et diagnostic

Après avoir appliqué les changements de quotas, vous devez vérifier non seulement que l'objet quota existe, mais aussi qu'il est correctement appliqué. Cette section fournit des commandes pour diagnostiquer les problèmes.

### Vérifier la création du quota

Vérifiez que le quota est présent :

kubectl get resourcequota -n team-a 
 La sortie attendue montre le nom du quota et son âge. S'il est absent, vérifiez les journaux du pipeline pour les erreurs.

### Vérifier l'application

Créez un pod de test qui dépasse le quota pour voir s'il est rejeté. Par exemple, si vous avez défini requests.cpu: "4" dans un quota, créez un pod demandant 5 CPU :

# test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
 name: test-overquota
 namespace: team-a
spec:
 containers:
 - name: nginx
 image: nginx
 resources:
 requests:
 cpu: "5" 
 Appliquez-le :

kubectl apply -f test-pod.yaml 
 Erreur attendue :

Error from server (Forbidden): error when creating "test-pod.yaml": pods "test-overquota" is forbidden: exceeded quota: compute-quota, requested: requests.cpu=5, used: requests.cpu=2, limited: requests.cpu=4 
 Si le pod est créé, le quota n'est pas appliqué ou est mal configuré.

### Commandes de diagnostic

- Lister les événements du namespace pour voir les erreurs liées aux quotas :

kubectl get events -n team-a --sort-by='.lastTimestamp' 
 Recherchez les messages FailedCreate ou ExceededQuota .

- Décrire le quota pour son statut :

kubectl describe resourcequota compute-quota -n team-a 

- Consulter les journaux du serveur API si nécessaire (nécessite des droits d'administrateur du cluster).

 Question rapide 2 sur 2

Selon l'article, quel est un mode de défaillance courant dans les pipelines CI/CD de Resource Quota ?

- Les nœuds du cluster manquent d'espace disque
- Le pipeline s'applique au mauvais cluster
- Les quotas de ressources ne sont pas namespacés
- Éviction de Pod lors d'un changement de quota

<button type="button" class="eno-quiz-submit" disabled>Valider</button>
<div class="eno-quiz-explanation">L&#39;article cite « Le pipeline s&#39;applique au mauvais cluster » comme un mode de défaillance courant, expliqué par « Le contexte Kubeconfig pointe vers la production alors que vous visiez la préproduction. »</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Modes de défaillance et récupération

Même avec l'automatisation, des échecs surviennent. Cette section couvre les modes de défaillance courants pour CI/CD des quotas de ressources et comment les récupérer.

### Modes de défaillance courants

- Syntaxe de manifeste invalide : erreur d'indentation YAML ou champ manquant. Le pipeline devrait détecter cela à l'étape lint/dry-run. Sinon, l'application échoue avec une erreur d'analyse. Récupération : corriger le manifeste et relancer le pipeline.

- RBAC insuffisant : le compte de service CI/CD n'a pas la permission de créer/mettre à jour ResourceQuota dans le namespace cible. Erreur : forbidden: User "system:serviceaccount:ci:deployer" cannot create resource "resourcequotas" . Récupération : accorder le rôle RBAC approprié.

- Namespace incohérent : le manifeste spécifie un namespace qui n'existe pas. Erreur : namespaces "team-c" not found . Récupération : créer d'abord le namespace ou corriger le manifeste.

- Quota trop restrictif : les développeurs ne peuvent pas déployer de pods, provoquant un incident. Récupération : augmenter immédiatement le quota en modifiant le YAML et en l'appliquant, ou supprimer temporairement le quota (avec prudence).

- Le pipeline s'applique au mauvais cluster : le contexte kubeconfig pointe vers la production alors que vous vouliez le staging. Récupération : utiliser des contextes séparés et la protection d'environnement dans CI.

### Procédures de restauration

Pour tout changement échoué, restaurez le dernier état connu bon depuis Git :

git log --oneline -- quotas/team-a/compute-quota.yaml
# Identifier le hash du commit précédent
git revert <commit-hash>
kubectl apply -f quotas/team-a/compute-quota.yaml 
 Si le pipeline lui-même est cassé, appliquez manuellement le dernier bon manifeste :

kubectl apply -f quotas/team-a/compute-quota.yaml 

### Surveillance et alertes

 Configurez des alertes sur l'utilisation des quotas pour détecter proactivement les problèmes. Par exemple, si vous utilisez Prometheus, une règle d'alerte :

groups:
- name: quota-alerts
 rules:
 - alert: QuotaAlmostFull
 expr: kube_resourcequota{resource="requests.cpu", type="used"} / kube_resourcequota{resource="requests.cpu", type="hard"} > 0.9
 for: 5m
 labels:
 severity: warning
 annotations:
 summary: "Resource quota {{ $labels.resourcequota }} is over 90% used" 

## Liste de contrôle opérationnelle

 Utilisez cette liste de contrôle pour chaque changement de quota via CI/CD afin de garantir sécurité et cohérence.

<div class="my-stack-md overflow-x-auto">
<table class="min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Étape</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Action</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Commande / Outil</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Résultat attendu</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">1</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Valider la syntaxe YAML</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl apply --dry-run=client -f &lt;file&gt;</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Aucune erreur de syntaxe</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">2</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Vérifier les quotas actuels</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get resourcequota -n &lt;namespace&gt;</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Liste des quotas existants</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">3</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Comparer souhaité vs actuel</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">diff</code> entre ancien et nouveau manifeste</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Comprendre les changements</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">4</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Appliquer au namespace de staging</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl apply -f &lt;file&gt; -n staging</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Quota créé/mis à jour</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">5</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Tester l&#39;application en staging</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Créer un pod dépassant le quota</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Pod rejeté avec erreur Forbidden</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">6</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Approuver pour la production</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Porte manuelle CI/CD</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Approbation accordée</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">7</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Appliquer en production</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl apply -f &lt;file&gt;</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Quota mis à jour</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">8</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Vérifier en production</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl describe resourcequota &lt;name&gt; -n &lt;namespace&gt;</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Valeurs Hard et Used correctes</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">9</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Enregistrer le déploiement</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Tag Git, journal CI</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Piste d&#39;audit disponible</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">10</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Surveiller l&#39;utilisation des quotas</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Prometheus/ Grafana</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Aucune alerte déclenchée</td></tr></tbody>
</table>
</div>

### Exemple de scénario concret

Parcourons un exemple concret : augmenter le quota de demandes CPU pour team-a de 4 à 6 CPU.

- Quota actuel ( compute-quota.yaml ) :

apiVersion: v1
 kind: ResourceQuota
 metadata:
 name: compute-quota
 namespace: team-a
 spec:
 hard:
 requests.cpu: "4"
 requests.memory: "4Gi"
 limits.cpu: "8"
 limits.memory: "8Gi" 

- Modifier requests.cpu en "6" dans une branche de fonctionnalité.

- Pousser la branche , ouvrir une PR. Le CI exécute dry-run et lint.

- Réviser et fusionner dans main . Le pipeline applique en production.

- Vérifier :

 kubectl describe resourcequota compute-quota -n team-a 
 Attendez requests.cpu: 2/6 (si l'utilisation actuelle est de 2).

- Tester : déployer un pod demandant 5 CPU, cela devrait réussir maintenant.

## Conclusion

Automatiser la gestion des quotas de ressources Kubernetes avec CI/CD apporte reproductibilité, auditabilité et sécurité à la gouvernance des ressources par namespace. En suivant les pratiques décrites dans cet article—inventorier votre environnement, concevoir un chemin de configuration sûr, vérifier rigoureusement les changements, se préparer aux échecs et utiliser une liste de contrôle opérationnelle—vous pouvez prévenir la contention des ressources et les erreurs de configuration. Commencez petit : choisissez un namespace, définissez ses quotas dans Git et créez un pipeline simple avec des étapes de dry-run et d'application. Au fur et à mesure que vous gagnez en confiance, étendez à tous les namespaces et ajoutez des tests automatisés et des alertes. N'oubliez pas que la clé est d'observer avant de changer, de limiter le rayon d'impact et de toujours avoir un plan de restauration.