Crane vous permet de copier, inspecter et optimiser vos images de conteneurs sans avoir besoin du démon Docker. Développé par Google dans le cadre du projet go-containerregistry, cet outil en ligne de commande communique directement avec les registries via l’API OCI. Vous pouvez l’utiliser pour copier une image entre Docker Hub et votre registry privée en une seule commande, inspecter les layers d’une image, ou aplatir une image multi-layers pour réduire sa taille. Particulièrement utile en CI/CD où Docker n’est pas toujours disponible, Crane s’installe en quelques secondes et fonctionne sur Linux, macOS et Windows.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Crane sur Linux ou macOS avec asdf ou Homebrew
- Inspecter les images d’une registry (manifest, config, layers)
- Copier des images entre registries sans Docker
- Optimiser les images en aplatissant les layers
- Automatiser la gestion des tags et versions en CI/CD
Pourquoi Crane plutôt que Docker ?
Section intitulée « Pourquoi Crane plutôt que Docker ? »Crane est un outil développé par Google qui permet de manipuler les images de conteneurs sans avoir besoin du démon Docker. C’est particulièrement utile dans les environnements CI/CD où Docker n’est pas toujours disponible, ou quand vous voulez simplement inspecter ou copier des images rapidement.
Cas d’usage typiques :
| Besoin | Avec Docker | Avec Crane |
|---|---|---|
| Copier une image entre registries | docker pull + docker tag + docker push | crane copy source dest |
| Voir les layers d’une image | docker history (limité) | crane manifest (détaillé) |
| Obtenir le digest SHA256 | docker inspect | crane digest |
| Exporter une image en tar | docker save | crane export |
| Aplatir les layers | Impossible nativement | crane flatten |
Installation de Crane
Section intitulée « Installation de Crane »Plusieurs méthodes d’installation sont disponibles selon votre système d’exploitation et vos préférences. Choisissez celle qui correspond le mieux à votre environnement de travail.
asdf-vm est un gestionnaire de versions
polyvalent. C’est ma méthode recommandée car elle permet de fixer une version
précise par projet grâce au fichier .tool-versions.
asdf plugin add craneasdf install crane 0.20.7asdf set --home crane 0.20.7L’avantage d’asdf est de pouvoir utiliser différentes versions de Crane selon les projets, ce qui est utile quand vous travaillez sur des codebases avec des contraintes de compatibilité différentes.
Si vous utilisez Homebrew, l’installation
se fait en une seule commande. Homebrew gère automatiquement les mises à jour
quand vous exécutez brew upgrade.
brew install craneSur Arch Linux, Crane est disponible dans les dépôts officiels. L’installation via pacman garantit l’intégration avec le système de paquets et les mises à jour automatiques.
pacman -S craneCette méthode fonctionne sur tous les systèmes Linux et permet de choisir une version précise. Les binaires sont disponibles pour plusieurs architectures : x86_64, arm64, armv6, i386, s390x et riscv64.
# Récupérer la dernière version automatiquementVERSION=$(curl -s "https://api.github.com/repos/google/go-containerregistry/releases/latest" | grep '"tag_name"' | cut -d'"' -f4)
# Ou fixer une version spécifiqueVERSION=v0.20.7
# Télécharger et extraire (adapter ARCH si nécessaire : arm64, armv6...)curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_Linux_x86_64.tar.gz" -o crane.tar.gztar -xzf crane.tar.gz cranesudo mv crane /usr/local/bin/rm crane.tar.gzSi vous avez Go installé (version 1.21+), vous pouvez compiler Crane depuis les sources. Cette méthode installe toujours la dernière version du code.
go install github.com/google/go-containerregistry/cmd/crane@latestLe binaire sera installé dans $GOPATH/bin (généralement ~/go/bin). Assurez-vous
que ce répertoire est dans votre PATH.
Vous pouvez utiliser Crane directement via son image Docker officielle, ce qui est pratique pour les pipelines CI/CD ou pour tester sans installation locale.
# Utilisation basiquedocker run --rm gcr.io/go-containerregistry/crane ls ubuntu
# Version avec shell (pour debug)docker run --rm -it --entrypoint "/busybox/sh" gcr.io/go-containerregistry/crane:debugL’image :debug inclut un shell BusyBox, utile pour le débogage. Les images
taggées sont disponibles sur gcr.io/go-containerregistry/crane:[version].
Vérification de l’installation :
crane version# Résultat attendu : 0.20.7Mise en place d’un lab de test
Section intitulée « Mise en place d’un lab de test »Pour les exemples qui suivent, je vais utiliser une registry locale. Cela permet de tester sans risque et sans créer de compte sur Docker Hub.
-
Démarrer une registry locale
Fenêtre de terminal docker run -d -p 5000:5000 --name registry registry:2.8La registry sera accessible sur
localhost:5000. -
Créer un Dockerfile de test
FROM alpine:3.21RUN apk --no-cache add nginxRUN mkdir -p /var/www/htmlCOPY index.html /var/www/html/WORKDIR /var/www/htmlEXPOSE 80 -
Créer le fichier index.html
<!DOCTYPE html><html><body><h1>Test Crane</h1></body></html> -
Construire et pousser l’image
Fenêtre de terminal docker build . -t localhost:5000/monserveurweb:0.1docker push localhost:5000/monserveurweb:0.1
Commandes essentielles de Crane
Section intitulée « Commandes essentielles de Crane »Crane propose une vingtaine de commandes pour interagir avec les registries. Dans cette section, nous allons voir les plus utilisées au quotidien. Toutes ces commandes communiquent directement avec la registry via HTTP/HTTPS, sans passer par le démon Docker.
Lister les images d’une registry
Section intitulée « Lister les images d’une registry »La commande catalog interroge l’API de la registry pour récupérer la liste
de toutes les images (appelées “repositories” dans la terminologie OCI). C’est
le point de départ pour explorer le contenu d’une registry.
crane catalog localhost:5000# monserveurwebSur une registry publique comme Docker Hub, cette commande peut retourner des milliers de résultats. Utilisez-la plutôt sur vos registries privées.
Lister les tags d’une image
Section intitulée « Lister les tags d’une image »Une fois que vous connaissez le nom d’une image, ls affiche tous les tags
disponibles. Un tag est un pointeur vers une version spécifique de l’image.
crane ls localhost:5000/monserveurweb# 0.1Cette commande est utile pour vérifier quelles versions sont disponibles avant de copier ou de déployer une image.
Inspecter le manifest d’une image
Section intitulée « Inspecter le manifest d’une image »Le manifest contient les métadonnées de l’image : ses layers, leur taille, leur digest SHA256. C’est l’équivalent d’une “table des matières” de l’image.
crane manifest localhost:5000/monserveurweb:0.1 | jq{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1476, "digest": "sha256:28865db66a2e..." }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 2829647, "digest": "sha256:f7dab3ab2d6e..." }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 617439, "digest": "sha256:607cfc754b09..." } ]}Obtenir la configuration complète
Section intitulée « Obtenir la configuration complète »La commande config affiche la configuration complète de l’image : historique
des layers, variables d’environnement, commande par défaut, labels…
crane config localhost:5000/monserveurweb:0.1 | jq{ "architecture": "amd64", "os": "linux", "config": { "Cmd": ["/bin/sh"], "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], "WorkingDir": "/var/www/html", "ExposedPorts": { "80/tcp": {} } }, "history": [ { "created_by": "/bin/sh -c #(nop) ADD file:..." }, { "created_by": "RUN /bin/sh -c apk --no-cache add nginx" }, { "created_by": "COPY index.html /var/www/html/" } ]}Récupérer le digest SHA256
Section intitulée « Récupérer le digest SHA256 »Le digest est l’identifiant unique et immuable d’une image. Contrairement au tag qui peut être modifié, le digest garantit que vous utilisez exactement la même image.
crane digest localhost:5000/monserveurweb:0.1# sha256:beb9fd8064525aa1787d60cfd6eba89c4580125f1e32a42e0ab006912cf48038Copier des images entre registries
Section intitulée « Copier des images entre registries »C’est la fonctionnalité phare de Crane. En une seule commande, vous copiez
une image d’une registry à une autre, y compris les images multi-architectures.
Contrairement à la méthode traditionnelle (docker pull + docker tag +
docker push), Crane ne télécharge pas l’image sur votre machine : il
orchestre un transfert direct entre les deux registries.
crane copy alpine:3.21 localhost:5000/alpine:3.21 --platform linux/amd64# 2026/01/23 09:13:02 Copying from alpine:3.21 to localhost:5000/alpine:3.21# 2026/01/23 09:13:03 existing blob: sha256:39477eca89b9...# 2026/01/23 09:13:03 existing blob: sha256:f637881d1138...# 2026/01/23 09:13:03 localhost:5000/alpine:3.21: digest: sha256:41c81533... size: 1022Cette commande copie l’image alpine:3.21 depuis Docker Hub vers votre
registry locale. L’option --platform limite la copie à une architecture
spécifique. Sans cette option, toutes les architectures sont copiées.
Ce que Crane fait en coulisses :
- Récupère le manifest de l’image source (la “table des matières”)
- Pour chaque layer, vérifie s’il existe déjà dans la destination
- Copie uniquement les layers manquants (économie de bande passante)
- Pousse le manifest final pour rendre l’image disponible
Vérification :
crane catalog localhost:5000# alpine# nginx
crane ls localhost:5000/alpine# 3.21Optimiser les images avec flatten
Section intitulée « Optimiser les images avec flatten »Une image Docker est composée de plusieurs layers (couches), chacune
représentant une modification du système de fichiers. Par exemple, l’image
nginx:1.27.3-alpine contient 8 layers : l’image de base Alpine, l’installation
de nginx, les fichiers de configuration, etc.
La commande flatten fusionne tous ces layers en un seul. L’image résultante
contient exactement les mêmes fichiers, mais dans une structure simplifiée.
# Copier nginx vers la registry localecrane copy nginx:1.27.3-alpine localhost:5000/nginx:1.27.3-alpine --platform linux/amd64
# Aplatir l'imagecrane flatten localhost:5000/nginx:1.27.3-alpine \ -t localhost:5000/nginx:1.27.3-alpine-flatL’option -t (ou --tag) spécifie le nom et le tag de l’image aplatie. Ici,
nous créons une nouvelle image plutôt que de modifier l’originale.
Comparaison avant/après :
# Avant : 8 layerscrane manifest localhost:5000/nginx:1.27.3-alpine | jq '.layers | length'# 8
# Après : 1 seul layercrane manifest localhost:5000/nginx:1.27.3-alpine-flat | jq '.layers | length'# 1Vérification de la taille :
docker pull localhost:5000/nginx:1.27.3-alpinedocker pull localhost:5000/nginx:1.27.3-alpine-flatdocker images | grep nginx# localhost:5000/nginx 1.27.3-alpine 20.5MB# localhost:5000/nginx 1.27.3-alpine-flat 20.2MBGérer les tags
Section intitulée « Gérer les tags »Les tags sont des pointeurs vers des versions spécifiques d’une image. Un même
digest (identifiant unique basé sur le contenu) peut avoir plusieurs tags. Par
exemple, une image peut être taguée 1.0.0, 1.0 et latest simultanément.
Ajouter un tag à une image existante
Section intitulée « Ajouter un tag à une image existante »La commande tag crée un nouveau pointeur vers une image existante. C’est une
opération légère qui ne duplique pas les données : les deux tags pointent vers
le même contenu.
crane tag localhost:5000/alpine:3.21 latestCette commande ajoute le tag latest à l’image qui porte déjà le tag 3.21.
Les deux tags coexistent et pointent vers la même version.
Vérification :
crane ls localhost:5000/alpine# 3.21# latestValider une image
Section intitulée « Valider une image »La commande validate vérifie que l’image est conforme aux spécifications OCI
(Open Container Initiative). Elle contrôle que le manifest est bien formé et
que tous les layers référencés existent.
crane validate --remote localhost:5000/monserveurweb:0.1# PASS: localhost:5000/monserveurweb:0.1Utilisez cette commande après une copie ou une modification pour vous assurer que l’image est utilisable.
S’authentifier à une registry
Section intitulée « S’authentifier à une registry »Les registries privées (Docker Hub pour les images privées, GCR, ECR, ACR, Harbor, GitLab Registry…) nécessitent une authentification avant de pouvoir lire ou écrire des images.
Crane stocke les credentials dans le même fichier que Docker
(~/.docker/config.json), ce qui permet de réutiliser les authentifications
existantes.
crane auth login registry.example.com -u username -p "password"# logged in via /home/user/.docker/config.jsonSur les providers cloud, vous pouvez utiliser des tokens temporaires. Par exemple, pour GCR avec gcloud :
crane auth login gcr.io -u oauth2accesstoken -p "$(gcloud auth print-access-token)"Commandes avancées
Section intitulée « Commandes avancées »Ces commandes sont moins utilisées au quotidien mais peuvent s’avérer très utiles dans des cas spécifiques : audit de sécurité, débogage, migration d’images, ou automatisation avancée.
Modifier les labels d’une image
Section intitulée « Modifier les labels d’une image »Les labels sont des métadonnées attachées à une image (version, mainteneur,
licence, etc.). La commande mutate permet de les modifier sans reconstruire
l’image, ce qui est utile pour ajouter des informations après coup.
crane mutate localhost:5000/alpine:3.21 \ --label "maintainer=team@example.com" \ --label "version=3.21" \ -t localhost:5000/alpine:3.21-labeledVérification des labels ajoutés :
crane config localhost:5000/alpine:3.21-labeled | jq '.config.Labels'# {# "maintainer": "team@example.com",# "version": "3.21"# }L’option -t (ou --tag) crée une nouvelle référence plutôt que de modifier
l’originale.
Modifier la plateforme d’une image
Section intitulée « Modifier la plateforme d’une image »Depuis la version 0.19.2, mutate permet de modifier la plateforme d’une image
avec l’option --set-platform. C’est utile quand une image a été buildée avec
une plateforme incorrecte ou manquante.
crane mutate localhost:5000/myapp:1.0 \ --set-platform linux/amd64 \ -t localhost:5000/myapp:1.0-amd64Exporter une image en tar
Section intitulée « Exporter une image en tar »La commande export télécharge tous les layers d’une image et les assemble
dans une archive tar. C’est utile pour l’archivage, le transfert vers un
environnement déconnecté (air-gapped), ou l’analyse du contenu.
crane export localhost:5000/monserveurweb:0.1 monserveurweb.tarL’archive contient le système de fichiers complet de l’image. Vous pouvez
l’explorer avec tar -tf monserveurweb.tar ou l’extraire pour inspection.
Récupérer un layer spécifique
Section intitulée « Récupérer un layer spécifique »Pour du débogage approfondi, vous pouvez extraire un layer particulier. Chaque layer correspond à une instruction du Dockerfile (RUN, COPY, ADD). Cela permet de voir exactement ce que chaque étape a ajouté ou modifié.
# Récupérer les digests des layerscrane manifest localhost:5000/monserveurweb:0.1 | jq '.layers[].digest'
# Extraire un layer spécifique (remplacer le digest)crane blob localhost:5000/monserveurweb:0.1@sha256:607cfc754b09... > layer.tar.gz
# Explorer le contenu du layertar -tzf layer.tar.gz | head -20Rebase sur une nouvelle image de base
Section intitulée « Rebase sur une nouvelle image de base »rebase permet de reconstruire une image avec une nouvelle image de base, sans
Dockerfile :
crane rebase localhost:5000/monserveurweb:0.1 \ --old_base alpine:3.20 \ --new_base alpine:3.21 \ --tag localhost:5000/monserveurweb:rebasedIntégration CI/CD
Section intitulée « Intégration CI/CD »Crane est particulièrement adapté aux pipelines CI/CD pour plusieurs raisons :
- Pas besoin de Docker : fonctionne sans démon, sans privilèges root
- Installation rapide : un seul binaire statique de ~15 Mo
- Efficace : copie directe entre registries, pas de stockage intermédiaire
- Scriptable : commandes simples, sorties prévisibles, codes retour standards
Les exemples ci-dessous montrent comment intégrer Crane dans vos workflows pour copier automatiquement les images validées vers un registry de production.
Exemple GitHub Actions
Section intitulée « Exemple GitHub Actions »name: Copy image to production registry
on: push: tags: - 'v*'
jobs: copy: runs-on: ubuntu-latest steps: - name: Install Crane run: | VERSION=0.20.7 curl -sL "https://github.com/google/go-containerregistry/releases/download/v${VERSION}/go-containerregistry_Linux_x86_64.tar.gz" | tar xzf - crane sudo mv crane /usr/local/bin/
- name: Login to registries run: | crane auth login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} crane auth login registry.example.com -u ${{ secrets.PROD_USER }} -p ${{ secrets.PROD_PASSWORD }}
- name: Copy image run: | crane copy ghcr.io/${{ github.repository }}:${{ github.ref_name }} \ registry.example.com/myapp:${{ github.ref_name }}Exemple GitLab CI
Section intitulée « Exemple GitLab CI »copy-to-prod: image: gcr.io/go-containerregistry/crane:v0.20.7 script: - crane auth login $CI_REGISTRY -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD - crane auth login $PROD_REGISTRY -u $PROD_USER -p $PROD_PASSWORD - crane copy $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG $PROD_REGISTRY/myapp:$CI_COMMIT_TAGDépannage
Section intitulée « Dépannage »Problèmes courants et solutions
Section intitulée « Problèmes courants et solutions »| Symptôme | Cause probable | Solution |
|---|---|---|
unauthorized | Token expiré ou invalide | crane auth login à nouveau |
manifest unknown | Tag inexistant | Vérifier avec crane ls |
UNSUPPORTED sur delete | Registry ne supporte pas la suppression | Normal pour registry locale par défaut |
connection refused | Registry non accessible | Vérifier l’URL et le réseau |
certificate signed by unknown authority | Certificat auto-signé | Ajouter --insecure (dev uniquement) |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »# Vérifier la connectivité à une registrycrane auth login registry.example.com -u test -p test
# Lister les images disponiblescrane catalog registry.example.com
# Vérifier qu'un tag existecrane digest registry.example.com/myimage:mytag
# Voir les détails d'une erreurcrane manifest registry.example.com/myimage:mytag 2>&1Bonnes pratiques
Section intitulée « Bonnes pratiques »Sécurité
Section intitulée « Sécurité »- Ne jamais utiliser
--insecureen production - Stocker les credentials dans des secrets CI/CD, jamais dans le code
- Utiliser les digests plutôt que les tags pour les déploiements critiques
Performance
Section intitulée « Performance »- Préférer
crane copyàdocker pull/pushpour les transferts entre registries - Utiliser
flattenavant de pousser des images finales en production - Paralléliser les copies dans vos pipelines si vous avez plusieurs images
Organisation
Section intitulée « Organisation »- Versionner les images avec des tags sémantiques (
1.2.3, paslatest) - Documenter les digests des images déployées en production
- Nettoyer régulièrement les anciennes images de vos registries
À retenir
Section intitulée « À retenir »- Crane fonctionne sans Docker : idéal pour les environnements CI/CD restreints
crane copyest plus efficace que pull/tag/push : il ne copie que les layers manquants- Le manifest contient toutes les métadonnées d’une image (layers, taille, digest)
flattenoptimise les images en fusionnant les layers, mais supprime le cache- Les digests sont immuables : préférez-les aux tags pour la reproductibilité
- Authentification : utilisez toujours des variables d’environnement pour les secrets
- Projet Google : Crane fait partie de go-containerregistry, maintenu activement
Prochaines étapes
Section intitulée « Prochaines étapes »Plus d’infos
Section intitulée « Plus d’infos »- go-containerregistry sur GitHub — Le projet qui contient Crane
- Documentation Crane — Référence des commandes
- Releases Crane — Télécharger les binaires
Questions fréquentes
Section intitulée « Questions fréquentes »Crane vs Skopeo
Crane et Skopeo sont deux outils complémentaires :
| Aspect | Crane | Skopeo |
|---|---|---|
| Éditeur | Red Hat | |
| Force | Copie directe, flatten |
Formats multiples |
| Transports | Registry uniquement | docker-daemon, oci-archive... |
| CI/CD | Excellent | Bon |
En pratique, Crane est souvent préféré en CI/CD pour sa simplicité, tandis que Skopeo convient mieux aux migrations complexes.
Installation de Crane
Plusieurs méthodes disponibles :
# Binaire GitHub
VERSION=v0.20.7
curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_Linux_x86_64.tar.gz" | tar xzf - crane
sudo mv crane /usr/local/bin/
Autres options :
- asdf-vm :
asdf plugin add crane && asdf install crane 0.20.7 - Arch Linux :
pacman -S crane - Homebrew :
brew install crane
Architectures supportées : x86_64, arm64, armv6, i386, s390x, riscv64.
Copie entre registries
crane copy alpine:3.21 registry.example.com/alpine:3.21
# Limiter à une architecture
crane copy alpine:3.21 registry.example.com/alpine:3.21 --platform linux/amd64
Avantages :
- Transfert direct registry-to-registry
- Pas de téléchargement local
- Copie uniquement les layers manquants
Aplatissement des layers
crane flatten myregistry/myimage:1.0 -t myregistry/myimage:1.0-flat
# Vérifier le résultat
crane manifest myregistry/myimage:1.0-flat | jq '.layers | length'
# 1
Avantages :
- Réduit légèrement la taille
- Masque l'historique de construction
Inconvénient : perte du cache Docker lors des rebuilds.
Inspection des layers
# Manifest complet
crane manifest alpine:3.21 | jq
# Nombre de layers
crane manifest alpine:3.21 | jq '.layers | length'
# Configuration et historique
crane config alpine:3.21 | jq
# Digest SHA256
crane digest alpine:3.21
Fonctionnement sans Docker
Crane communique directement avec les registries via l'API OCI HTTP.
Avantages :
- Pas besoin du démon Docker
- Fonctionne dans des conteneurs sans privilèges
- Idéal pour CI/CD restreints
- Binaire statique de ~15 Mo
# Fonctionne sur un serveur sans Docker
crane ls alpine
Authentification
# Login interactif
crane auth login registry.example.com -u username -p password
# CI/CD avec variables
crane auth login $REGISTRY -u $USER -p $PASSWORD
# GCR avec gcloud
crane auth login gcr.io -u oauth2accesstoken -p "$(gcloud auth print-access-token)"
Les credentials sont stockés dans ~/.docker/config.json, compatible avec Docker.
Modification des métadonnées
# Ajouter des labels
crane mutate myimage:1.0 \
--label version=1.0 \
--label maintainer=team@example.com \
-t myimage:1.0-labeled
# Modifier la plateforme (v0.19.2+)
crane mutate myimage:1.0 --set-platform linux/amd64 -t myimage:1.0-amd64
L'option -t crée une nouvelle référence plutôt que de modifier l'originale.
GitHub Actions
- name: Install Crane
run: |
VERSION=0.20.7
curl -sL "https://github.com/google/go-containerregistry/releases/download/v${VERSION}/go-containerregistry_Linux_x86_64.tar.gz" | tar xzf - crane
sudo mv crane /usr/local/bin/
- name: Copy image
run: |
crane auth login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
crane copy SOURCE DESTINATION
GitLab CI
image: gcr.io/go-containerregistry/crane:v0.20.7
Digest SHA256
crane digest alpine:3.21
# sha256:5405e8f36ce1878720f71217d664aa3dea32e5e5df11acbf07fc78ef5661465b
Pourquoi utiliser les digests ?
- Immuable (contrairement aux tags)
- Garantit la reproductibilité
- Évite les attaques par remplacement de tag
# Référencer par digest
crane copy alpine@sha256:5405e8f36ce... myregistry/alpine@sha256:5405e8f36ce...