Ce guide vous montre comment installer kube-image-keeper (kuik) pour garantir l’accès à vos images conteneur même quand Docker Hub ou votre registry est indisponible. Vous apprendrez à configurer le routage d’images vers des miroirs et la réplication entre registries. Prérequis : un cluster Kubernetes fonctionnel et Helm installé.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer kuik et ses prérequis (cert-manager)
- Comprendre l’architecture et les CRDs de kuik v2
- Configurer les alternatives d’images avec
ClusterImageSetMirror - Déclarer des upstreams multiples avec
ClusterReplicatedImageSet - Valider vos filtres sur un cluster de test avec les logs DEBUG
- Diagnostiquer les problèmes courants
Qu’est-ce que kube-image-keeper ?
Section intitulée « Qu’est-ce que kube-image-keeper ? »kube-image-keeper (kuik, prononcé “quick”) est un système de routage et de mise en cache d’images conteneur pour Kubernetes, développé par Enix. Il résout un problème que tout administrateur Kubernetes a rencontré : l’impossibilité de démarrer des pods parce qu’une image ne peut pas être téléchargée.
Les causes sont multiples :
- Registry indisponible : Docker Hub en maintenance, panne réseau
- Rate limiting : quotas Docker Hub atteints (100 pulls/6h pour les anonymes)
- Image supprimée : politique de rétention, suppression accidentelle
- Réseau instable : clusters edge avec connexion intermittente
kuik intercepte les créations de pods via un mutating webhook et peut :
- Router les images vers un miroir local quand le registry source est indisponible
- Répliquer les images entre plusieurs registries pour créer une haute disponibilité virtuelle
Architecture de kuik v2
Section intitulée « Architecture de kuik v2 »kuik v2 s’articule autour de deux concepts principaux :
Les CRDs de kuik v2
Section intitulée « Les CRDs de kuik v2 »kuik v2 introduit quatre Custom Resource Definitions pour configurer le comportement du système. Les versions “Cluster” s’appliquent à tout le cluster, tandis que les versions sans préfixe sont limitées à un namespace spécifique.
| CRD | Portée | Usage |
|---|---|---|
ClusterImageSetMirror | Cluster | Définit des miroirs pour router les images |
ImageSetMirror | Namespace | Idem, mais limité à un namespace |
ClusterReplicatedImageSet | Cluster | Configure la réplication entre registries |
ReplicatedImageSet | Namespace | Idem, mais limité à un namespace |
La différence entre ImageSetMirror et ReplicatedImageSet est importante :
ImageSetMirror: quand une image correspond au filtre, kuik la rend disponible via le ou les miroirs déclarés, comme alternatives si l’upstream est indisponible. Ce CRD ne redirige pas systématiquement les pulls — il enrichit la liste des sources possibles.ReplicatedImageSet: permet de déclarer plusieurs upstreams pour une même image. Utile quand un projet publie ses images sur plusieurs registries à la fois — kuik peut proposer l’un ou l’autre en alternative.
La réécriture d’image est décidée au démarrage du pod : kuik vérifie si l’upstream est accessible et, s’il ne l’est pas, utilise les alternatives définies par un CISM ou un CRIS. Depuis la version 2.1, il est possible de forcer la réécriture via les priorités, même quand l’upstream est disponible.
Installation de kuik
Section intitulée « Installation de kuik »Prérequis
Section intitulée « Prérequis »kuik utilise un mutating webhook qui intercepte les créations de pods. Ce webhook doit communiquer avec l’API server de façon sécurisée via TLS. Pour gérer automatiquement les certificats, kuik s’appuie sur cert-manager.
Si cert-manager n’est pas déjà installé sur votre cluster :
# Installation de cert-managerkubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yaml
# Attendre que cert-manager soit prêtkubectl -n cert-manager rollout status deployment cert-manager --timeout=120skubectl -n cert-manager rollout status deployment cert-manager-webhook --timeout=120sInstallation via Helm
Section intitulée « Installation via Helm »-
Créer le namespace
Fenêtre de terminal kubectl create namespace kuik-system -
Installer kuik
Fenêtre de terminal helm upgrade --install \--namespace kuik-system \kube-image-keeper \oci://quay.io/enix/charts/kube-image-keeper \--version 2.2.1 \--wait -
Vérifier l’installation
Fenêtre de terminal kubectl -n kuik-system get podsRésultat attendu :
NAME READY STATUS RESTARTS AGEkube-image-keeper-manager-5c5dff9d7b-w6xcg 1/1 Running 0 31s
Vérifier les CRDs installés
Section intitulée « Vérifier les CRDs installés »Après l’installation, vérifiez que les Custom Resource Definitions ont été créées. Ces CRDs permettent de configurer kuik de façon déclarative :
kubectl api-resources | grep kuikRésultat :
clusterimagesetmirrors cism kuik.enix.io/v1alpha1 false ClusterImageSetMirrorclusterreplicatedimagesets cris kuik.enix.io/v1alpha1 false ClusterReplicatedImageSetimagesetmirrors ism kuik.enix.io/v1alpha1 true ImageSetMirrorreplicatedimagesets ris kuik.enix.io/v1alpha1 true ReplicatedImageSetLes raccourcis (cism, cris, ism, ris) permettent d’interagir plus rapidement avec kubectl : kubectl get cism au lieu de kubectl get clusterimagesetmirrors.
Configuration des miroirs d’images (ClusterImageSetMirror)
Section intitulée « Configuration des miroirs d’images (ClusterImageSetMirror) »Le ClusterImageSetMirror est le cas d’usage le plus simple de kuik. Il déclare des alternatives pour un ensemble d’images filtrées. Si l’upstream est indisponible au démarrage d’un pod, kuik propose ces alternatives à la place.
Cas d’usage typiques :
- Vous avez un Harbor configuré en proxy-cache de Docker Hub
- Vous utilisez un registry interne qui synchronise les images critiques
- Vous êtes sur un cluster edge avec un registry local
Exemple : miroir pour Docker Hub
Section intitulée « Exemple : miroir pour Docker Hub »Supposons que vous avez un registry miroir Harbor à harbor.example.com:5000. Ce registry est configuré pour mettre en cache les images Docker Hub :
apiVersion: kuik.enix.io/v1alpha1kind: ClusterImageSetMirrormetadata: name: dockerhub-mirrorspec: imageFilter: include: - ".+/nginx:.*" # Toutes les versions de nginx (registry normalisée incluse) - ".+/redis:[0-9]+\\..*" # redis avec version numérique exclude: - ".*:latest" # Exclure les tags latest mirrors: - registry: "harbor.example.com:5000" path: "docker-hub-cache"Appliquer la configuration
Section intitulée « Appliquer la configuration »kubectl apply -f dockerhub-mirror.yaml
# Vérifierkubectl get clusterimagesetmirrorsComment fonctionne la réécriture d’image ?
Section intitulée « Comment fonctionne la réécriture d’image ? »Quand un pod est créé avec image: nginx:1.25 :
-
Le webhook intercepte la création du pod
{"msg":"defaulting for Pod","namespace":"default","name":"test-nginx"} -
kuik normalise l’image et recense les alternatives
nginx:1.25→docker.io/library/nginx:1.25, puis kuik évalue tous les CISM et CRIS déclarés.{"msg":"reviewing alternatives","clusterImageSetMirrors":1,"clusterReplicatedImageSet":1}{"msg":"found alternatives","container":"nginx","references":["docker.io/library/nginx:1.25","harbor.example.com:5000/docker-hub-cache/library/nginx:1.25"]} -
Il teste la disponibilité de chaque alternative
Si le miroir est inaccessible :
{"msg":"image is not available","reference":"harbor.example.com:5000/...","error":"registry unreachable: dial tcp: lookup harbor.example.com: no such host"} -
Il choisit la meilleure source disponible
Si l’upstream original est accessible, kuik le conserve (failsafe) :
{"msg":"original image is available, using it","originalImage":"nginx:1.25"}Si l’upstream est indisponible et qu’une alternative est accessible, kuik réécrit l’image vers cette alternative.
# Voir l'image finale dans le podkubectl get pod mon-pod -o jsonpath='{.spec.containers[0].image}'Configuration des upstreams multiples (ClusterReplicatedImageSet)
Section intitulée « Configuration des upstreams multiples (ClusterReplicatedImageSet) »Le ClusterReplicatedImageSet répond à un besoin différent : certains projets publient leurs images sur plusieurs registries simultanément. Ce CRD permet de déclarer ces upstreams multiples pour qu’ils soient tous proposés comme alternatives lors du démarrage d’un pod.
Différences avec ClusterImageSetMirror :
| Aspect | ClusterImageSetMirror | ClusterReplicatedImageSet |
|---|---|---|
| Usage principal | Déclarer un miroir existant comme alternative | Déclarer plusieurs upstreams d’un même projet |
| Qui gère les images ? | Le miroir externe (Harbor, etc.) | Les registries upstream déclarés |
| Cas d’usage typique | Harbor proxy-cache, registry interne | Projet publié sur docker.io ET ghcr.io |
Exemple : image publiée sur plusieurs registries
Section intitulée « Exemple : image publiée sur plusieurs registries »Prenons le cas de Thanos, publié à la fois sur Docker Hub et Quay.io. Si Docker Hub est indisponible, kuik peut automatiquement router vers Quay.io :
apiVersion: kuik.enix.io/v1alpha1kind: ClusterReplicatedImageSetmetadata: name: thanos-multi-registryspec: upstreams: - registry: docker.io path: /thanosio/thanos imageFilter: include: - "/thanosio/thanos:.+" # matche après suppression du préfixe "docker.io" - registry: quay.io path: /thanos/thanos imageFilter: include: - "/thanos/thanos:.+" # matche après suppression du préfixe "quay.io"Quand un pod utilisant thanosio/thanos:v0.36.1 est créé, kuik vérifie la disponibilité de chacun des upstreams déclarés. Si docker.io est indisponible, kuik peut proposer quay.io comme alternative et réécrire l’image en conséquence.
Avec authentification
Section intitulée « Avec authentification »Pour un upstream nécessitant une authentification (registry privée) :
apiVersion: kuik.enix.io/v1alpha1kind: ClusterReplicatedImageSetmetadata: name: private-imagesspec: upstreams: - registry: ghcr.io path: /myorg/myapp credentialSecret: name: ghcr-credentials namespace: kuik-system imageFilter: include: - "/myorg/myapp:.+" # après strip de "ghcr.io" - registry: registry.example.com path: /myorg/myapp credentialSecret: name: private-registry-credentials namespace: kuik-system imageFilter: include: - "/myorg/myapp:.+" # après strip de "registry.example.com"Créez d’abord les secrets :
kubectl -n kuik-system create secret docker-registry ghcr-credentials \ --docker-server=ghcr.io \ --docker-username=myuser \ --docker-password=ghp_xxxx
kubectl -n kuik-system create secret docker-registry private-registry-credentials \ --docker-server=registry.example.com \ --docker-username=myuser \ --docker-password=mypasswordConfiguration avancée
Section intitulée « Configuration avancée »kuik offre plusieurs options pour adapter son comportement à votre environnement. Les principales personnalisations concernent la haute disponibilité du manager, le comportement du routage et la gestion du cycle de vie des images.
Personnaliser les values Helm
Section intitulée « Personnaliser les values Helm »Créez un fichier de values pour personnaliser l’installation. Voici les options les plus utiles :
manager: replicas: 2 # HA pour le manager verbosity: DEBUG # Plus de logs resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi"
configuration: routing: activeCheck: enabled: true # Vérifier la disponibilité des registries timeout: "2s" # Timeout de la vérification
unusedImageTTL: 48 # Heures avant suppression d'une image non utiliséehelm upgrade --install \ --namespace kuik-system \ kube-image-keeper \ oci://quay.io/enix/charts/kube-image-keeper \ --version 2.2.1 \ -f values-kuik.yamlExclure des namespaces
Section intitulée « Exclure des namespaces »Pour éviter que kuik n’intercepte certains namespaces système :
apiVersion: kuik.enix.io/v1alpha1kind: ClusterImageSetMirrormetadata: name: global-mirrorspec: imageFilter: include: - ".*" exclude: - "quay.io/enix/kube-image-keeper:.*" # Éviter les bouclesSurveillance et debug
Section intitulée « Surveillance et debug »kuik étant un composant critique (il intercepte toutes les créations de pods), il est important de savoir le surveiller et diagnostiquer les problèmes.
Logs du manager
Section intitulée « Logs du manager »Le manager kuik produit des logs structurés (JSON) qui permettent de comprendre son comportement. Suivez les logs en temps réel :
kubectl -n kuik-system logs deployment/kube-image-keeper-manager -fLes messages clés à surveiller, triés par niveaux de logs :
Niveau INFO (toujours visible) :
| Message | Signification |
|---|---|
mirroring image | kuik tente de copier une image vers un miroir |
could not mirror image | Échec de la copie (registry inaccessible) |
image is not used anymore | Image sans pod associé, marquée pour nettoyage |
Niveau DEBUG (nécessite verbosity: DEBUG) :
| Message | Signification |
|---|---|
defaulting for Pod | Webhook interceptant une création de pod |
reviewing alternatives | Évaluation des CISM/CRIS pour ce pod |
found alternatives | Liste des alternatives trouvées (avec references) |
image is available | Une alternative est accessible |
image is not available | Une alternative est inaccessible |
original image is available, using it | Image originale conservée (failsafe) |
Vérifier le status d’un CISM
Section intitulée « Vérifier le status d’un CISM »Le status d’un ClusterImageSetMirror liste les images qui ont matché les filtres et l’état de chaque miroir :
kubectl get cism dockerhub-mirror -o jsonpath='{.status}' | python3 -m json.tool{ "matchingImages": [ { "image": "docker.io/library/nginx:1.25", "mirrors": [ { "image": "harbor.example.com:5000/docker-hub-cache/library/nginx:1.25", "mirroredAt": "2026-04-07T09:30:40Z" } ] }, { "image": "docker.io/library/redis:7.2.4", "mirrors": [ { "image": "harbor.example.com:5000/docker-hub-cache/library/redis:7.2.4" } ] } ]}Si une image que vous attendiez est absente de matchingImages, votre filtre ne matche pas. Vérifiez la syntaxe regex et la normalisation de l’image.
Vérifier une règle
Section intitulée « Vérifier une règle »# Détail d'un ClusterImageSetMirrorkubectl get cism dockerhub-mirror -o yaml
# Détail d'un ClusterReplicatedImageSetkubectl get cris thanos-multi-registry -o yamlExplorer les CRDs
Section intitulée « Explorer les CRDs »# Documentation intégréekubectl explain clusterimagesetmirror.speckubectl explain clusterimagesetmirror.spec.imageFilterkubectl explain clusterreplicatedimageset.spec.upstreamsDépannage
Section intitulée « Dépannage »Les problèmes avec kuik se manifestent généralement de deux façons : les pods ne démarrent pas (images introuvables) ou le routage ne s’applique pas (images non réécrites). Voici les causes les plus fréquentes :
| Symptôme | Cause probable | Solution |
|---|---|---|
| Webhook non déclenché | cert-manager non prêt | Vérifier kubectl -n cert-manager get pods |
invalid nested repetition operator | Regex invalide (** au lieu de .*) | Corriger la syntaxe regex |
| Image non réécrite | Miroir inaccessible | Vérifier la connectivité au registry miroir |
no alternative image available | Aucune règle ne matche | Vérifier les filtres include/exclude |
| Pods kuik en CrashLoop | Certificats invalides | Recréer le namespace kuik-system |
Tester la connectivité au miroir
Section intitulée « Tester la connectivité au miroir »Si kuik indique qu’aucun miroir n’est disponible, vérifiez que les pods peuvent réellement atteindre votre registry miroir. Cette commande crée un pod temporaire pour tester la connectivité :
# Depuis un pod de debugkubectl run test-registry --rm -it --image=curlimages/curl -- \ curl -s https://harbor.example.com:5000/v2/Une réponse {} ou {"repositories":[]} indique que le registry est accessible. Une erreur de connexion ou un timeout signifie un problème réseau (firewall, DNS, etc.).
Valider vos filtres sur un cluster de test
Section intitulée « Valider vos filtres sur un cluster de test »Avant de déployer kuik en production, validez le comportement de vos filtres sur un cluster local. Cette section utilise k3d, mais tout cluster éphémère convient (kind, minikube).
Créer un cluster de test
Section intitulée « Créer un cluster de test »k3d cluster create kuik-test --agents 1 --waitInstallez cert-manager et kuik en mode DEBUG pour voir les décisions du webhook :
# cert-managerkubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yamlkubectl -n cert-manager rollout status deployment cert-manager-webhook --timeout=120s
# kuik avec logs DEBUGkubectl create namespace kuik-systemhelm upgrade --install --namespace kuik-system kube-image-keeper \ oci://quay.io/enix/charts/kube-image-keeper \ --version 2.2.1 --set manager.verbosity=DEBUG --waitAppliquer les règles et créer des pods de test
Section intitulée « Appliquer les règles et créer des pods de test »Appliquez vos CISM/CRIS, puis créez des pods pour déclencher le webhook :
# Appliquer les règleskubectl apply -f dockerhub-mirror.yamlkubectl apply -f thanos-multi-registry.yaml
# Pods de test : un par scénariokubectl run test-nginx --image=nginx:1.25 --command -- sleep 3600kubectl run test-latest --image=nginx:latest --command -- sleep 3600kubectl run test-redis --image=redis:7.2.4 --command -- sleep 3600kubectl run test-thanos --image=thanosio/thanos:v0.36.1 --command -- sleep 3600kubectl run test-no-match --image=busybox:1.36 --command -- sleep 3600Lire les logs et vérifier les résultats
Section intitulée « Lire les logs et vérifier les résultats »Examinez les logs pour voir les décisions de kuik sur chaque pod :
kubectl -n kuik-system logs deployment/kube-image-keeper-manager --since=30s \ | grep '"found alternatives"'Résultats attendus :
| Pod | Image normalisée | Alternatives trouvées | Explication |
|---|---|---|---|
test-nginx | docker.io/library/nginx:1.25 | originale + miroir Harbor | .+/nginx:.* matche, pas exclu |
test-latest | docker.io/library/nginx:latest | originale uniquement | .+/nginx:.* matche mais .*:latest l’exclut |
test-redis | docker.io/library/redis:7.2.4 | originale + miroir Harbor | .+/redis:[0-9]+\\..* matche |
test-thanos | docker.io/thanosio/thanos:v0.36.1 | docker.io + quay.io | CRIS : les deux upstreams matchent |
test-no-match | docker.io/library/busybox:1.36 | originale uniquement | Aucune règle ne matche |
Vérifiez aussi le status du CISM pour confirmer les images matchées :
kubectl get cism dockerhub-mirror -o jsonpath='{.status.matchingImages[*].image}'# docker.io/library/nginx:1.25 docker.io/library/redis:7.2.4nginx:latest et busybox:1.36 doivent être absents de cette liste.
Nettoyer
Section intitulée « Nettoyer »k3d cluster delete kuik-testDésinstallation
Section intitulée « Désinstallation »Pour désinstaller proprement :
# Supprimer kuikhelm uninstall kube-image-keeper -n kuik-system
# Supprimer les CRDs (attention : supprime toutes les règles)kubectl delete crd clusterimagesetmirrors.kuik.enix.iokubectl delete crd clusterreplicatedimagesets.kuik.enix.iokubectl delete crd imagesetmirrors.kuik.enix.iokubectl delete crd replicatedimagesets.kuik.enix.io
# Supprimer le namespacekubectl delete namespace kuik-systemÀ retenir
Section intitulée « À retenir »- kuik résout les problèmes de disponibilité des images (registry down, rate limits, images supprimées)
- kuik v2 utilise deux CRDs principaux :
ClusterImageSetMirror(alternatives via miroir) etClusterReplicatedImageSet(upstreams multiples pour un même projet) - Les filtres utilisent des regex Go en full match, pas des globs
- Les filtres CISM matchent sur l’image complète normalisée (ex :
docker.io/library/nginx:1.25), tandis que les filtres CRIS strippent le registry avant comparaison (ex :/library/nginx:1.25) - kuik est failsafe : si aucun miroir n’est disponible, l’image originale est conservée
- cert-manager est un prérequis obligatoire
- Évitez d’inclure l’image kuik dans vos règles pour prévenir les boucles