## Introduction

Les images Kubernetes sont au cœur de chaque charge de travail, et savoir les inspecter, les mettre à jour et les dépanner est essentiel pour les développeurs, les consultants DevOps et les équipes techniques de startups. Cet article passe d'un problème observé à un résultat vérifié en reliant des commandes de base, des exemples concrets, une antisèche et des pratiques opérationnelles.

Nous mettons l'accent sur la sécurité pratique : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés plutôt que des secrets, vérifier le résultat et documenter comment récupérer si l'état attendu n'est pas atteint. Chaque commande ci-dessous est versionnée (Kubernetes 1.24+ sauf indication contraire) et suppose que kubectl est installé, configuré avec un contexte actuel, et que vous avez un accès en lecture à l'espace de noms concerné.

L'objectif de la sécurité opérationnelle n'est pas seulement d'exécuter des commandes, mais de comprendre ce qu'elles changent et comment revenir en arrière. Nous couvrirons l'inventaire des versions et de l'environnement, le chemin de configuration sûr pour les mises à jour d'images, la vérification et le diagnostic, les modes de défaillance et la récupération, ainsi qu'une liste de contrôle opérationnelle réutilisable entre les clusters.

## Inventaire des versions et de l'environnement

Avant de toucher aux images, établissez les versions du cluster et des composants. Cet inventaire est en lecture seule et forme la base de référence pour tout changement ultérieur.

Composants clés à inventorier :

- Versions du plan de contrôle Kubernetes et des nœuds

- Runtime de conteneurs (containerd, CRI-O ou Docker via cri-dockerd)

- Version du plugin CNI

- Points de terminaison du registre d'images et authentification

- Politiques de tirage d'image existantes sur les charges de travail

Commencez par les commandes de découverte de version :

kubectl version --short
# Exemple de sortie attendue :
# Client Version: v1.28.2
# Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
# Server Version: v1.28.2 
 Si kubectl version --short est déconseillé dans les versions plus récentes, utilisez :

kubectl version 
 Qui affiche le JSON complet, y compris les versions client et serveur. Consignez cette base de référence dans votre runbook.

Vérifiez la version du runtime du nœud avec :

kubectl get nodes -o wide
# NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
# node1 Ready control-plane 10d v1.28.2 192.168.1.10 <none> Ubuntu 22.04.3 LTS 5.15.0-91-generic containerd://1.7.8
# node2 Ready <none> 10d v1.28.2 192.168.1.11 <none> Ubuntu 22.04.3 LTS 5.15.0-91-generic containerd://1.7.8 
 La colonne CONTAINER-RUNTIME liste le runtime et sa version, ce qui importe pour la compatibilité des images (par exemple, certaines fonctionnalités nécessitent containerd 1.6+).

Exemple : si vous devez utiliser le streaming d'images (par exemple, pour de grandes images), assurez-vous que le runtime le supporte. containerd 1.7 avec CRI 1.2 et KEP 3668 l'active ; les versions plus anciennes ne le font pas.

Inventoriez l'utilisation actuelle des images dans tous les espaces de noms avec :

kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}' 
 Exemple de sortie :

default nginx-deployment-6b474476c4-8g2kf nginx:1.25.3
default redis-cache-0 redis:7.2-alpine
kube-system coredns-5d78c9869d-8h4wp registry.k8s.io/coredns/coredns:v1.11.1 
 Cet inventaire en lecture seule montre toutes les images en cours d'exécution. Comparez-le à votre liste d'images approuvées pour repérer les dérives.

Prérequis pour des opérations d'image sûres :

- Version de kubectl compatible avec le serveur (à une version mineure près)

- Identifiants du registre configurés comme secret si vous tirez depuis des registres privés

- Espace disque suffisant sur les nœuds pour les tirages d'images (vérifiez avec df -h sur les nœuds ou utilisez la surveillance)

- Sortie réseau vers les points de terminaison du registre

Une observation en lecture seule ciblée pour la santé des images :

kubectl get events --all-namespaces --field-selector reason=FailedToPullImage 
 Si aucun événement n'apparaît, les images se tirent normalement au cours de la dernière heure (TTL d'événement par défaut). Sinon, notez l'espace de noms, le pod et l'image en cause.

Documentez l'état actuel avec l'horodatage et le contexte du cluster :

date -u && kubectl config current-context && kubectl get pods -A -o wide > inventory-$(date +%Y%m%d-%H%M).txt 
 Ce fichier texte est votre référence de restauration pour les changements ultérieurs.

<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

Quelle commande est utilisée pour mettre à jour l'image d'un conteneur dans un pod à l'aide d'un patch JSON ?

- kubectl set image pod valid-pod kubernetes-serve-hostname=new image
- kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
- kubectl edit pod valid-pod
- kubectl apply -f pod.yaml

<button type="button" class="eno-quiz-submit" disabled>Valider</button>
<div class="eno-quiz-explanation">Le passage de référence fourni montre explicitement la commande pour mettre à jour l&#39;image d&#39;un conteneur à l&#39;aide de kubectl patch avec un patch de fusion où spec.containers[*].name est requis comme clé de fusion.</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

Changer une image doit suivre le plus petit changement justifié : une image à la fois dans une charge de travail, avec une vérification observable.

### Mise à jour d'image dans un déploiement

Supposons que vous ayez un déploiement web exécutant nginx:1.25.2 et que vous vouliez le mettre à jour vers nginx:1.25.3 . D'abord, confirmez l'image actuelle :

kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:1.25.2 
 Observez l'état actuel du déploiement :

kubectl rollout status deployment/web --timeout=60s
# deployment "web" successfully rolled out 
 Maintenant, mettez à jour l'image en utilisant la commande impérative (plus petit changement) :

kubectl set image deployment/web nginx=nginx:1.25.3
# deployment.apps/web image updated 
 Surveillez le déploiement et vérifiez :

kubectl rollout status deployment/web --timeout=120s
# Waiting for deployment "web" rollout to finish: 1 out of 2 new replicas have been updated...
# deployment "web" successfully rolled out 
 Confirmez que la nouvelle image est en place :

kubectl get pods -l app=web -o jsonpath='{.items[*].spec.containers[0].image}{"\n"}'
# nginx:1.25.3 nginx:1.25.3 
 Revenez en arrière si nécessaire (chemin de récupération) :

kubectl rollout undo deployment/web
# deployment.apps/web rolled back
kubectl rollout status deployment/web
# deployment "web" successfully rolled out 
 Vérifiez l'image après le retour en arrière :

kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:1.25.2 

### Politique de tirage d'image

 Par défaut, Kubernetes utilise IfNotPresent pour les images avec une étiquette explicite (comme nginx:1.25.3 ) et Always pour les images avec l'étiquette latest . Cela peut causer une mise en cache inattendue.

Exemple : définissez la politique de tirage sur Always pour garantir la dernière image dans un espace de noms de développement. Modifiez le déploiement :

kubectl patch deployment web -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","imagePullPolicy":"Always"}]}}}}'
# deployment.apps/web patched 
 Vérifiez avec :

kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].imagePullPolicy}'
# Always 
 Remarque : Always ajoute une charge sur le registre et peut ralentir le démarrage des pods. Pour la production, utilisez des étiquettes explicites et IfNotPresent (par défaut) ou un condensat.

### Utilisation de condensats d'image pour l'immuabilité

Épingler à un condensat empêche les changements accidentels si l'étiquette est écrasée. Trouvez le condensat :

docker buildx imagetools inspect nginx:1.25.3 --format '{{.Manifest.Digest}}'
# sha256:... (hash réel) 
 Ou utilisez skopeo inspect docker://nginx:1.25.3 | jq -r '.Digest' .

Mettez à jour le déploiement pour utiliser le condensat :

kubectl set image deployment/web nginx=nginx@sha256:abcdef1234567890... 
 Vérifiez :

kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx@sha256:abcdef1234567890... 
 Le retour en arrière fonctionne de la même manière via kubectl rollout undo .

### Identifiants de registre privé

Si votre image est dans un registre privé, créez un secret et ajoutez-le à la spécification du pod. Créez le secret :

kubectl create secret docker-registry my-registry-secret \
 --docker-server=registry.example.com \
 --docker-username=myuser \
 --docker-password='s3cr3t' \
 --docker-email=user@example.com
# secret/my-registry-secret created 
 Patchez le compte de service ou le déploiement pour l'utiliser (le compte de service est recommandé pour une valeur par défaut à l'échelle du cluster) :

kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"my-registry-secret"}]}' 
 Ou directement sur la spécification du pod :

kubectl patch deployment web -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"my-registry-secret"}]}}}}' 
 Ne stockez jamais de mots de passe en clair dans le YAML de déploiement ; utilisez des secrets et évitez de les commiter dans Git.

### Garder un test local petit pour une configuration sûre

Avant de passer à un équilibreur de charge externe ou à une entrée, testez localement avec kubectl port-forward :

kubectl port-forward deployment/web 8080:80
# Forwarding from 127.0.0.1:8080 -> 80
# Forwarding from [::1]:8080 -> 80 
 Puis testez avec curl http://localhost:8080 . Cela vérifie le pod directement sans l'exposer au réseau.

## Vérification et diagnostic

Après un changement d'image, vérifiez que l'application est saine et que la bonne image s'exécute.

### État du pod et détails de l'image

Listez les pods avec les images :

kubectl get pods -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# web-5f6cf84df-8n2k5 1/1 Running 0 2m 10.244.2.5 node2 <none> <none>
# web-5f6cf84df-v9xqt 1/1 Running 0 2m 10.244.1.7 node1 <none> <none> 
 Obtenez des informations détaillées sur l'image :

kubectl get pods -o jsonpath='{.items[*].spec.containers[0].image}'
# nginx:1.25.3 nginx:1.25.3 
 Vérifiez l'image actuelle du déploiement :

kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:1.25.3 

### Journaux et événements pour le diagnostic

 Si les pods sont en boucle de crash, obtenez les journaux :

kubectl logs deployment/web --tail=50
# Exemple : 2024/01/15 error: image not found 
 Pour l'instance de conteneur précédente :

kubectl logs <pod-name> --previous 
 Décrivez le pod pour les événements :

kubectl describe pod <pod-name>
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Normal Scheduled 3m default-scheduler Successfully assigned default/web-5f6cf84df-8n2k5 to node2
# Normal Pulled 2m59s kubelet Container image "nginx:1.25.3" already present on machine
# Normal Created 2m59s kubelet Created container nginx
# Normal Started 2m58s kubelet Started container nginx 
 Si le tirage d'image échoue, vous verrez Failed avec ErrImagePull ou ImagePullBackOff .

### Vérifier les erreurs de tirage d'image dans le cluster

kubectl get events --all-namespaces --field-selector reason=FailedToPullImage,reason=ErrImagePull 

### Vérification de l'image au moment de l'exécution

 Dans un pod en cours d'exécution, confirmez l'image du processus réel (nécessite sh) :

kubectl exec -it <pod-name> -- cat /etc/os-release
# NAME="Alpine Linux"
# ID=alpine
# VERSION_ID=3.19.0 
 Ou vérifiez les métadonnées de l'image du conteneur depuis le nœud : crictl images | grep nginx si vous avez accès au nœud.

### Historique des déploiements

Vérifiez l'historique des déploiements pour les changements d'image :

kubectl rollout history deployment/web
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 <none> 
 Si vous avez utilisé --record (déconseillé en 1.27) ou annoté avec cause de changement, vous verrez des détails. Pour afficher l'image d'une révision :

kubectl rollout history deployment/web --revision=2 

### Vérification des sondes de santé

 Si votre pod a des sondes de préparation, vérifiez qu'elles réussissent :

kubectl get pods -l app=web -o jsonpath='{.items[*].status.conditions[?(@.type=="Ready")].status}{"\n"}'
# True True 
 Et les points de terminaison :

kubectl get endpoints web
# NAME ENDPOINTS AGE
# web 10.244.1.7:80,10.244.2.5:80 5m 

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

 Les défaillances liées aux images se répartissent généralement en échecs de tirage, mauvaise image, secrets manquants ou incompatibilité de runtime. Cette section couvre les modes de défaillance courants et les étapes de récupération explicites.

### ImagePullBackOff

Cause : l'image n'existe pas, l'étiquette est incorrecte, le registre est inaccessible ou les identifiants du registre privé sont manquants.

Observez :

kubectl get pods
# NAME READY STATUS RESTARTS AGE
# web-7fd69d9c6-5k4j2 0/1 ImagePullBackOff 0 30s 
 Obtenez les détails :

kubectl describe pod web-7fd69d9c6-5k4j2 | tail -20
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Normal Scheduled 35s default-scheduler Successfully assigned default/web-7fd69d9c6-5k4j2 to node1
# Normal Pulling 34s kubelet Pulling image "nginx:1.25.9"
# Warning Failed 33s kubelet Failed to pull image "nginx:1.25.9": rpc error: code = NotFound desc = failed to pull and unpack image "docker.io/library/nginx:1.25.9": failed to resolve reference "docker.io/library/nginx:1.25.9": not found
# Warning Failed 33s kubelet Error: ErrImagePull
# Normal BackOff 32s kubelet Back-off pulling image "nginx:1.25.9" 
 Récupération :

- Corrigez l'étiquette de l'image dans le déploiement :

kubectl set image deployment/web nginx=nginx:1.25.3 

- Vérifiez le déploiement :

 kubectl rollout status deployment/web 

- Si registre privé, vérifiez que le secret existe et est correct :

 kubectl get secret my-registry-secret -o yaml 
 Assurez-vous que .dockerconfigjson contient la bonne authentification.

### CrashLoopBackOff dû à une mauvaise architecture d'image

Vous pouvez tirer une image ARM64 sur un nœud AMD64. Le pod démarre mais plante avec une erreur de format exec.

Observez :

kubectl logs <pod-name>
# exec /entrypoint.sh: exec format error 
 Récupération :

- Vérifiez l'architecture du nœud :

kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.architecture}'
# amd64 amd64 

- Utilisez une image multi-architecture ou une étiquette d'architecture correcte. Par exemple, utilisez nginx:1.25.3 qui supporte amd64 et arm64, ou spécifiez --platform=linux/amd64 lors de la construction.

- Mettez à jour l'image et vérifiez.

### Secret de tirage d'image manquant

 Si le pod ne peut pas tirer depuis un registre privé, le statut montre ImagePullBackOff avec unauthorized: authentication required .

Observez :

kubectl describe pod <name> | grep -A5 "Failed to pull image"
# Warning Failed 10s (x3 over 30s) kubelet Failed to pull image "registry.example.com/myapp:1.0": rpc error: code = Unknown desc = failed to pull and unpack image "registry.example.com/myapp:1.0": failed to resolve reference "registry.example.com/myapp:1.0": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed 
 Récupération :

- Créez ou mettez à jour le secret comme montré précédemment.

- Ajoutez imagePullSecrets au pod ou au compte de service.

- Supprimez le pod pour forcer un nouveau tirage :

kubectl delete pod <pod-name> 
 Le nouveau pod devrait démarrer.

### La mise à jour de l'image a causé une défaillance de l'application

Si la nouvelle image s'exécute mais que l'application échoue (par exemple, mauvais point d'entrée, configuration manquante), vous pouvez revenir en arrière.

Retour rapide :

kubectl rollout undo deployment/web 
 Ou vers une révision spécifique :

kubectl rollout undo deployment/web --to-revision=1 
 Puis vérifiez :

kubectl rollout status deployment/web
kubectl get pods -l app=web -o jsonpath='{.items[*].spec.containers[0].image}' 

### Pression disque due à de grandes images

 Si les nœuds manquent de disque à cause de nombreuses images ou de grandes couches, les pods peuvent être évincés.

Observez les conditions du nœud :

kubectl describe node <node-name> | grep -A5 "Conditions:"
# Conditions:
# Type Status LastHeartbeatTime LastTransitionTime Reason Message
# ---- ------ ----------------- ------------------ ------ -------
# MemoryPressure False Tue, 16 Jan 2024 10:00:00 +0000 Tue, 16 Jan 2024 09:00:00 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available
# DiskPressure True Tue, 16 Jan 2024 10:05:00 +0000 Tue, 16 Jan 2024 10:04:30 +0000 KubeletHasDiskPressure kubelet has disk pressure 
 Récupération :

- Supprimez les images inutilisées sur le nœud : crictl rmi --prune (si vous avez accès au nœud)

- Définissez le seuil de collecte des ordures d'image : drapeau kubelet --image-gc-high-threshold=85 (par défaut 85%)

- Utilisez des images plus petites ou le streaming d'images.

### Échec de tirage dû à un réseau ou une panne du registre

Si le registre est indisponible, les pods montreront ImagePullBackOff avec connection refused ou timeout .

Vérifiez la connectivité depuis le nœud :

kubectl debug node/<node-name> -it --image=busybox -- sh
# dans le pod de debug : wget -O- https://registry-1.docker.io/v2/ ; echo $? 
 Récupération :

- Réparez le point de terminaison du registre/DNS/pare-feu.

- Utilisez un miroir local ou --registry-mirror dans le runtime de conteneurs.

- Mettez à jour la source de l'image si vous utilisez un registre différent.

<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 2 sur 2

Quel est l'objectif de l'utilisation d'un outil d'analyse d'images avant de déployer des conteneurs ?

- Améliorer les performances des conteneurs
- Analyser une image pour détecter les vulnérabilités avant le déploiement
- Mettre à jour automatiquement les images
- Créer des images de conteneurs

<button type="button" class="eno-quiz-submit" disabled>Valider</button>
<div class="eno-quiz-explanation">Le passage de référence cite « Utiliser un outil d&#39;analyse d&#39;images pour analyser une image avant de déployer des conteneurs » comme mesure de sécurité, ce qui implique que son objectif est d&#39;identifier des vulnérabilités.</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>

## Liste de contrôle opérationnelle

Utilisez cette liste de contrôle avant, pendant et après toute opération liée aux images pour maintenir la sécurité et la récupérabilité.

### 1. Liste de contrôle avant changement

- [ ] Enregistrez la version actuelle du cluster : kubectl version

- [ ] Enregistrez l'image actuelle de la charge de travail : kubectl get deployment <name> -o jsonpath='{.spec.template.spec.containers[0].image}'

- [ ] Notez l'état du déploiement : kubectl rollout status deployment/<name>

- [ ] Vérifiez la connectivité au registre : curl -I https://registry-1.docker.io/v2/ (ou votre registre)

- [ ] Vérifiez l'espace disque sur les nœuds : kubectl describe nodes | grep -A5 DiskPressure

- [ ] Sauvegardez le YAML du déploiement : kubectl get deployment <name> -o yaml > backup-<name>-$(date +%F).yaml

### 2. Exécution du changement

- [ ] Appliquez un changement d'image avec kubectl set image ou patch

- [ ] Surveillez la progression du déploiement : kubectl rollout status deployment/<name> --timeout=90s

- [ ] Si les nouveaux pods ne montent pas, vérifiez les événements : kubectl get events --field-selector reason=FailedToPullImage,reason=ErrImagePull

### 3. Vérification après changement

- [ ] Confirmez que la nouvelle image s'exécute : kubectl get pods -l app=<label> -o jsonpath='{.items[*].spec.containers[0].image}'

- [ ] Vérifiez la santé de l'application via les sondes ou les journaux : kubectl logs deployment/<name> --tail=20

- [ ] Testez l'accès local : kubectl port-forward deployment/<name> 8080:80 puis curl localhost:8080

- [ ] Vérifiez qu'il n'y a pas de nouveaux événements d'erreur dans les 5 dernières minutes : kubectl get events --since=5m | grep -i error

### 4. Plan de retour en arrière

- [ ] Connaissez la commande de retour : kubectl rollout undo deployment/<name>

- [ ] Si vous utilisez une mise à jour impérative, gardez le YAML de sauvegarde prêt : kubectl apply -f backup.yaml

- [ ] Vérifiez le succès du retour : kubectl rollout status deployment/<name> et vérification de l'image.

### 5. Documentation

- [ ] Mettez à jour le runbook avec la nouvelle version de l'image et les problèmes rencontrés.

- [ ] Étiquetez le changement dans votre système de gestion des changements.

### Exemple concret pas à pas

Supposons que vous deviez mettre à jour le déploiement web de nginx:1.25.2 à nginx:1.25.3 .

- Avant changement : enregistrez les versions et l'état, sauvegardez le YAML.

- Exécutez : kubectl set image deployment/web nginx=nginx:1.25.3 .

- Surveillez : kubectl rollout status deployment/web (réussit en 15 s).

- Vérifiez : kubectl get pods -l app=web -o jsonpath='{.items[*].spec.containers[0].image}' affiche nginx:1.25.3 nginx:1.25.3 .

- Testez : kubectl port-forward deployment/web 8080:80 et curl -I localhost:8080 renvoie HTTP/1.1 200 OK.

- Documentez : mettez à jour l'entrée du runbook avec la date, la version et la sortie de vérification.

Si le déploiement échoue après 90 s avec des pods bloqués dans ErrImagePull , vérifiez immédiatement les événements, corrigez l'image et redéployez. Si nécessaire, revenez en arrière : kubectl rollout undo deployment/web .

## Conclusion

La gestion des images Kubernetes ne se limite pas à tirer des conteneurs ; il s'agit d'un changement contrôlé avec observabilité et récupération. Les commandes et exemples de cet article fournissent une base pour exploiter les images en toute sécurité. Copier une commande sans vérifier les prérequis et la sortie attendue n'est pas une procédure opérationnelle.

Comme prochaine étape, choisissez une vérification à faible risque de ce guide pour votre environnement. Enregistrez l'état actuel, exécutez la vérification documentée, comparez le résultat avec le signal attendu et passez en revue les dépendances telles que les pods, les déploiements et les runtimes de conteneurs. Construisez votre propre liste de contrôle opérationnelle en utilisant le modèle fourni et adaptez-la à votre registre, vos politiques de sécurité et vos modèles de charge de travail.

Un flux de travail technique fiable rend les défaillances visibles, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la récupération avant qu'un incident ne force la décision. Avec ces pratiques, vous pouvez gérer en toute confiance les images Kubernetes en production.

---

## Annexe : Antisèche des images Kubernetes

Référence rapide des commandes couramment utilisées liées aux images :

<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">Tâche</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</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Lister tous les pods avec les images</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 pods -A -o jsonpath=&#39;{range .items[<em>]}{.metadata.namespace}{&quot;\t&quot;}{.metadata.name}{&quot;\t&quot;}{.spec.containers[</em>].image}{&quot;\n&quot;}{end}&#39;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Obtenir l&#39;image d&#39;un déploiement</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 deployment &lt;name&gt; -o jsonpath=&#39;{.spec.template.spec.containers[0].image}&#39;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Mettre à jour l&#39;image d&#39;un déploiement</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 set image deployment/&lt;name&gt; &lt;container-name&gt;=&lt;new-image&gt;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Vérifier l&#39;état du déploiement</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 rollout status deployment/&lt;name&gt;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Revenir en arrière sur un déploiement</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 rollout undo deployment/&lt;name&gt;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Décrire un pod pour les erreurs d&#39;image</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 pod &lt;pod-name&gt;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Voir les journaux pour un crash</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 logs &lt;pod-name&gt; --previous</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Obtenir les événements pour les échecs d&#39;image</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 events --all-namespaces --field-selector reason=FailedToPullImage</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Créer un secret de registre</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 create secret docker-registry my-secret --docker-server=REGISTRY --docker-username=USER --docker-password=PASS --docker-email=EMAIL</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Ajouter un secret de tirage d&#39;image au compte de service</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 patch serviceaccount default -p &#39;{&quot;imagePullSecrets&quot;:[{&quot;name&quot;:&quot;my-secret&quot;}]}&#39;</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Rediriger un port pour un test local</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 port-forward deployment/&lt;name&gt; 8080:80</code></td></tr></tbody>
</table>
</div>
Utilisez cette antisèche en complément des procédures détaillées ci-dessus pour rationaliser les opérations sur les images.