Skopeo vous permet d’inspecter, copier et supprimer des images conteneurs directement sur les registres, sans les télécharger ni démarrer de daemon. En 10 minutes, vous saurez transférer une image entre Docker Hub et un registre privé, créer un miroir local, et préparer des images pour un environnement air-gap.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Inspecter une image distante : consulter métadonnées, tags et digest sans télécharger
- Copier entre registres : transférer images entre Docker Hub, Quay.io, Harbor
- Synchroniser un miroir : répliquer plusieurs images avec un fichier YAML
- Gérer l’air-gap : exporter et importer des images pour environnements déconnectés
Ce que Skopeo sait faire
Section intitulée « Ce que Skopeo sait faire »Skopeo couvre quatre cas d’usage principaux pour la gestion des images conteneurs :
| Fonctionnalité | Commande | Cas d’usage |
|---|---|---|
| Inspection | skopeo inspect | Vérifier les métadonnées, l’architecture, les couches avant téléchargement |
| Copie | skopeo copy | Transférer une image entre registres ou vers un fichier local |
| Synchronisation | skopeo sync | Répliquer plusieurs images/tags vers un miroir privé |
| Suppression | skopeo delete | Supprimer une image d’un registre distant |
Transports supportés
Section intitulée « Transports supportés »Skopeo supporte plusieurs formats de source/destination (appelés “transports”) :
| Transport | Format | Description |
|---|---|---|
docker:// | docker://registry/image:tag | Registre Docker (Docker Hub, Quay.io, Harbor, etc.) |
dir: | dir:/chemin/local | Répertoire local avec les couches et le manifest |
docker-archive: | docker-archive:/chemin/image.tar | Archive au format docker save |
oci: | oci:/chemin:tag | Répertoire au format OCI |
oci-archive: | oci-archive:/chemin/image.tar | Archive au format OCI |
containers-storage: | containers-storage:image:tag | Stockage local Podman/Buildah |
Installation de Skopeo
Section intitulée « Installation de Skopeo »sudo apt update && sudo apt install -y skopeosudo dnf install -y skopeobrew install skopeoSous WSL avec Ubuntu :
sudo apt update && sudo apt install -y skopeoVérification de l’installation :
skopeo --versionRésultat attendu (la version peut varier) :
skopeo version 1.21.0commit: 8bd9c541f0513a3f688bdae54c5f0ec4e581f420Inspecter une image distante
Section intitulée « Inspecter une image distante »La commande skopeo inspect permet de consulter les métadonnées d’une image sans la télécharger. Pratique pour vérifier l’architecture, la date de création ou les variables d’environnement avant de déployer.
Afficher les métadonnées complètes
Section intitulée « Afficher les métadonnées complètes »skopeo inspect docker://docker.io/library/nginx:1.27.3Extrait du résultat :
{ "Name": "docker.io/library/nginx", "Digest": "sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef", "RepoTags": ["1", "1-alpine", "1.27", "1.27.3", "..."], "Architecture": "amd64", "Os": "linux", "Created": "2024-11-26T18:42:08Z", "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.27.3", "NJS_VERSION=0.8.7" ]}Les informations clés retournées :
- Digest : empreinte SHA256 unique de l’image (garantit l’intégrité)
- RepoTags : tous les tags disponibles pour cette image
- Architecture/Os : plateforme cible (amd64, arm64, linux, windows)
- Created : date de build de l’image
- Env : variables d’environnement définies dans l’image
Extraire une information spécifique avec jq
Section intitulée « Extraire une information spécifique avec jq »Pour n’afficher que certains champs, combinez avec jq :
skopeo inspect docker://docker.io/library/nginx:1.27.3 | jq '{Name, Digest, Architecture, Os, Created}'Résultat :
{ "Name": "docker.io/library/nginx", "Digest": "sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef", "Architecture": "amd64", "Os": "linux", "Created": "2024-11-26T18:42:08Z"}Lister les tags disponibles
Section intitulée « Lister les tags disponibles »Pour connaître toutes les versions publiées d’une image :
skopeo list-tags docker://docker.io/library/nginxFiltrer les tags avec jq (ici, les versions 1.27.x) :
skopeo list-tags docker://docker.io/library/nginx | jq '.Tags | map(select(startswith("1.27"))) | .[:10]'Résultat :
[ "1.27", "1.27-alpine", "1.27-alpine-otel", "1.27-alpine-perl", "1.27-alpine-slim", "1.27-alpine3.19", "1.27-alpine3.19-otel", "1.27-alpine3.19-perl", "1.27-alpine3.19-slim", "1.27-alpine3.20"]Inspection avec authentification
Section intitulée « Inspection avec authentification »Si le registre nécessite une authentification :
skopeo inspect --creds utilisateur:mot_de_passe docker://registry.example.com/mon-image:1.0.0Ou avec un fichier d’authentification (format Docker) :
skopeo inspect --authfile ~/.docker/config.json docker://registry.example.com/mon-image:1.0.0Copier des images entre registres
Section intitulée « Copier des images entre registres »La commande skopeo copy transfère une image d’une source vers une destination. Le transfert s’effectue directement entre les registres — votre machine ne stocke pas l’image.
Copie de base entre deux registres
Section intitulée « Copie de base entre deux registres »skopeo copy docker://docker.io/library/alpine:3.20.6 docker://registry.example.com/alpine:3.20.6L’image alpine:3.20.6 est copiée de Docker Hub vers votre registre privé.
Copie avec authentification
Section intitulée « Copie avec authentification »Quand source et/ou destination nécessitent des credentials :
skopeo copy \ --src-creds utilisateur_source:mdp_source \ --dest-creds utilisateur_dest:mdp_dest \ docker://quay.io/mon-org/mon-app:2.1.0 \ docker://registry.example.com/mon-app:2.1.0Copier vers un répertoire local
Section intitulée « Copier vers un répertoire local »Pour extraire les couches et le manifest dans un dossier :
skopeo copy docker://docker.io/library/alpine:3.20.6 dir:/tmp/alpine-3.20.6Contenu du répertoire créé :
/tmp/alpine-3.20.6/├── 0a9a5dfd008f... # Couche (layer) compressée├── ff221270b9fb... # Configuration de l'image├── manifest.json # Manifest décrivant l'image└── version # Version du formatCopier vers une archive Docker
Section intitulée « Copier vers une archive Docker »Pour créer un fichier .tar compatible avec docker load :
skopeo copy docker://docker.io/library/alpine:3.20.6 docker-archive:/tmp/alpine-3.20.6.tarCopier vers une archive OCI
Section intitulée « Copier vers une archive OCI »Format OCI, compatible avec podman load et les runtimes OCI :
skopeo copy docker://docker.io/library/alpine:3.20.6 oci-archive:/tmp/alpine-3.20.6-oci.tarConvertir entre formats Docker et OCI
Section intitulée « Convertir entre formats Docker et OCI »De Docker vers OCI :
skopeo copy docker://docker.io/library/nginx:1.27.3 oci:nginx-oci:1.27.3De OCI vers archive Docker :
skopeo copy oci:nginx-oci:1.27.3 docker-archive:nginx.tarOptions utiles pour la copie
Section intitulée « Options utiles pour la copie »| Option | Description |
|---|---|
--all | Copie toutes les architectures d’une image multi-arch |
--preserve-digests | Conserve les digests d’origine (utile pour les signatures) |
--retry-times 3 | Nombre de tentatives en cas d’échec réseau |
--retry-delay 5s | Délai entre les tentatives (v1.18.0+) |
--digestfile /tmp/digest.txt | Écrit le digest de l’image copiée dans un fichier |
Exemple avec options de fiabilité :
skopeo copy \ --retry-times 3 \ --retry-delay 5s \ --digestfile /tmp/nginx-digest.txt \ docker://docker.io/library/nginx:1.27.3 \ docker://registry.example.com/nginx:1.27.3Environnements air-gap (déconnectés)
Section intitulée « Environnements air-gap (déconnectés) »Dans les environnements isolés d’Internet, Skopeo permet d’exporter puis d’importer des images sans connexion réseau.
Workflow complet air-gap
Section intitulée « Workflow complet air-gap »-
Sur une machine connectée : exportez l’image vers une archive
Fenêtre de terminal skopeo copy docker://docker.io/library/nginx:1.27.3 docker-archive:/media/usb/nginx-1.27.3.tar -
Transférez l’archive vers l’environnement air-gap (clé USB, disque, etc.)
-
Sur la machine air-gap : importez l’image vers le registre privé
Fenêtre de terminal skopeo copy docker-archive:/media/usb/nginx-1.27.3.tar docker://registre-interne.local/nginx:1.27.3
Synchroniser plusieurs images
Section intitulée « Synchroniser plusieurs images »La commande skopeo sync réplique plusieurs images ou tags en une seule opération. Idéal pour maintenir un miroir privé à jour.
Synchronisation d’un dépôt complet
Section intitulée « Synchronisation d’un dépôt complet »Synchroniser tous les tags d’une image :
skopeo sync --src docker --dest docker docker.io/library/alpine registry.example.comCette commande copie tous les tags de alpine vers votre registre.
Synchronisation sélective avec fichier YAML
Section intitulée « Synchronisation sélective avec fichier YAML »Pour un contrôle fin, définissez les images dans un fichier YAML :
# Registre source : docker.iodocker.io: images: # Toutes les versions d'alpine >= 3.19 alpine: - "3.19" - "3.20" - "3.20.6" # Versions spécifiques de nginx nginx: - "1.27.3" - "1.27.3-alpine" tls-verify: true
# Registre source : quay.ioquay.io: images: prometheus/prometheus: - "v2.54.1" - "v2.55.0" tls-verify: trueExécution :
skopeo sync --src yaml --dest docker sync.yaml registry.example.com/mirror/Options de synchronisation utiles
Section intitulée « Options de synchronisation utiles »| Option | Description |
|---|---|
--dry-run | Simule la synchronisation sans copier |
--keep-going | Continue même si une image échoue |
--scoped | Préfixe les images avec leur chemin source |
--all | Synchronise toutes les architectures |
Exemple avec dry-run pour vérifier avant d’exécuter :
skopeo sync --src yaml --dest docker --dry-run sync.yaml registry.example.com/mirror/Créer un miroir local (répertoire)
Section intitulée « Créer un miroir local (répertoire) »Pour stocker les images localement avant de les transférer :
skopeo sync --src docker --dest dir docker.io/library/alpine /backup/images/Puis pousser le miroir local vers un registre :
skopeo sync --src dir --dest docker /backup/images/ registry.example.comSupprimer une image distante
Section intitulée « Supprimer une image distante »La commande skopeo delete supprime une image directement sur le registre :
skopeo delete docker://registry.example.com/mon-app:1.0.0-obsoleteAvec authentification :
skopeo delete --creds admin:secret docker://registry.example.com/test-image:devComparer deux images
Section intitulée « Comparer deux images »Pour vérifier si deux images sont identiques (même contenu), comparez leurs digests :
# Digest de l'image sur Docker Hubskopeo inspect docker://docker.io/library/nginx:1.27.3 | jq -r '.Digest'
# Digest de l'image sur votre registreskopeo inspect docker://registry.example.com/nginx:1.27.3 | jq -r '.Digest'Si les deux digests sont identiques, les images sont strictement équivalentes (même contenu binaire).
Dépannage
Section intitulée « Dépannage »Erreur “unauthorized: authentication required”
Section intitulée « Erreur “unauthorized: authentication required” »Le registre nécessite une authentification. Solutions :
# Option 1 : credentials en ligne de commandeskopeo inspect --creds utilisateur:mot_de_passe docker://registry.example.com/image:tag
# Option 2 : fichier d'authentificationskopeo login registry.example.comskopeo inspect docker://registry.example.com/image:tagErreur “certificate signed by unknown authority”
Section intitulée « Erreur “certificate signed by unknown authority” »Le certificat TLS du registre n’est pas reconnu. Solutions :
# Option 1 : désactiver la vérification TLS (non recommandé en production)skopeo inspect --tls-verify=false docker://registry.example.com/image:tag
# Option 2 : spécifier le répertoire des certificatsskopeo inspect --cert-dir /etc/docker/certs.d/registry.example.com docker://registry.example.com/image:tagErreur “manifest unknown” ou “not found”
Section intitulée « Erreur “manifest unknown” ou “not found” »L’image ou le tag n’existe pas. Vérifiez :
- Le nom exact de l’image et du tag
- Que vous avez les permissions de lecture
- Listez les tags disponibles :
skopeo list-tags docker://registry/image
Timeout sur gros transferts
Section intitulée « Timeout sur gros transferts »Pour les images volumineuses, augmentez les tentatives :
skopeo copy --retry-times 5 --retry-delay 10s docker://source/image:tag docker://dest/image:tagÀ retenir
Section intitulée « À retenir »- Skopeo fonctionne sans daemon : contrairement à Docker, il ne nécessite aucun service en arrière-plan
- Transfert direct : les images passent de registre à registre sans stockage intermédiaire
- Pinner les versions : utilisez toujours des tags précis (ex:
1.27.3) plutôt quelatest - Plusieurs formats : Skopeo convertit entre Docker, OCI, archives et répertoires
- Air-gap ready : export/import via archives pour les environnements déconnectés
Prochaines étapes
Section intitulée « Prochaines étapes »Plus d’infos
Section intitulée « Plus d’infos »FAQ — Questions fréquentes
Section intitulée « FAQ — Questions fréquentes »Définition
Skopeo est un outil en ligne de commande créé par Red Hat qui permet de manipuler des images conteneurs directement sur les registres, sans démon Docker.
Avantages clés
| Avantage | Description |
|---|---|
| Sans daemon | Aucun processus Docker ou Podman requis |
| Transfert direct | Images passent de registre à registre sans stockage local |
| Multi-transport | Supporte docker://, oci:, dir:, docker-archive: |
| Léger | Binaire standalone, idéal pour CI/CD |
| Air-gap ready | Export/import via archives pour environnements déconnectés |
Cas d'usage recommandés
- Migrations de registres : Docker Hub → Harbor, Quay.io → ECR
- Miroirs privés : synchroniser images publiques vers registre interne
- Air-gap : exporter images vers clé USB pour environnements isolés
- CI/CD : copier images entre registres sans daemon
- Inspection : vérifier métadonnées avant déploiement
Exemple rapide
# Inspecter sans télécharger
skopeo inspect docker://docker.io/library/nginx:1.27.3
# Copier entre registres
skopeo copy docker://docker.io/nginx:1.27.3 docker://registry.local/nginx:1.27.3
Comparaison
| Critère | Docker pull/push | Skopeo copy |
|---|---|---|
| Daemon requis | ✅ Oui (root) | ❌ Non |
| Stockage local | ✅ Télécharge puis pousse | ❌ Transfert direct |
| Privilèges | Root ou groupe docker | Utilisateur normal |
| Vitesse migration | Lent (2 transferts) | Rapide (1 transfert) |
| Bande passante | Consomme 2x | Consomme 1x |
Workflow Docker (classique)
# Étape 1 : télécharger localement
docker pull docker.io/nginx:1.27.3
# Étape 2 : retagger
docker tag nginx:1.27.3 registry.local/nginx:1.27.3
# Étape 3 : pousser
docker push registry.local/nginx:1.27.3
# → 3 commandes, stockage local temporaire
Workflow Skopeo (optimisé)
# Transfert direct en 1 commande
skopeo copy docker://docker.io/nginx:1.27.3 docker://registry.local/nginx:1.27.3
# → 1 commande, pas de stockage local
Quand utiliser Skopeo ?
- Migration massive : copier 100+ images rapidement
- CI/CD sans daemon : pas de socket Docker à monter
- Scripts automation : binaire léger, scriptable
- Environnement rootless : pas besoin de privilèges
Quand rester sur Docker ?
- Développement local : habitudes d'équipe
- Builds + push : docker build + docker push intégrés
Commande de base
skopeo inspect docker://docker.io/library/nginx:1.27.3
Informations retournées
| Champ | Description |
|---|---|
| Name | Nom complet de l'image |
| Digest | Empreinte SHA256 (garantit l'intégrité) |
| RepoTags | Tous les tags disponibles |
| Architecture | amd64, arm64, etc. |
| Os | linux, windows |
| Created | Date de build |
| Env | Variables d'environnement |
Filtrer avec jq
# Informations essentielles
skopeo inspect docker://nginx:1.27.3 | jq '{Name, Digest, Architecture, Os, Created}'
# Uniquement le digest
skopeo inspect docker://nginx:1.27.3 | jq -r '.Digest'
# Variables d'environnement
skopeo inspect docker://nginx:1.27.3 | jq '.Env'
Lister les tags disponibles
skopeo list-tags docker://docker.io/library/nginx
# Filtrer versions 1.27.x
skopeo list-tags docker://nginx | jq '.Tags | map(select(startswith("1.27")))'
Avec authentification
# Credentials en ligne
skopeo inspect --creds user:password docker://registry.private.com/app:1.0.0
# Fichier d'authentification
skopeo inspect --authfile ~/.docker/config.json docker://registry.private.com/app:1.0.0
Workflow complet
Étape 1 : Exporter sur machine connectée
# Export simple
skopeo copy docker://docker.io/library/nginx:1.27.3 docker-archive:/media/usb/nginx-1.27.3.tar
# Export multi-architecture (amd64 + arm64)
skopeo copy --all docker://docker.io/library/nginx:1.27.3 docker-archive:/media/usb/nginx-1.27.3-multiarch.tar
Étape 2 : Transférer l'archive
- Clé USB
- Disque externe
- Gravure DVD
- Transfert sécurisé (SCP sur réseau isolé)
Étape 3 : Importer sur machine air-gap
skopeo copy docker-archive:/media/usb/nginx-1.27.3.tar docker://registre-interne.local/nginx:1.27.3
Alternatives d'export
# Format OCI (compatible Podman)
skopeo copy docker://nginx:1.27.3 oci-archive:/media/usb/nginx-1.27.3-oci.tar
# Répertoire local (layers décompressés)
skopeo copy docker://nginx:1.27.3 dir:/media/usb/nginx-1.27.3/
Synchroniser plusieurs images
# sync.yaml
docker.io:
images:
nginx:
- "1.27.3"
- "1.27.3-alpine"
alpine:
- "3.20.6"
# Exporter vers répertoire
skopeo sync --src yaml --dest dir sync.yaml /media/usb/images/
# Importer depuis répertoire
skopeo sync --src dir --dest docker /media/usb/images/ registre-interne.local
Vérifier l'intégrité
# Comparer digests avant/après
skopeo inspect docker://nginx:1.27.3 | jq -r '.Digest'
skopeo inspect docker://registre-interne.local/nginx:1.27.3 | jq -r '.Digest'
# Doivent être identiques
Fichier de configuration YAML
# sync.yaml
# Registre source : Docker Hub
docker.io:
images:
# Versions spécifiques
nginx:
- "1.27.3"
- "1.27.3-alpine"
alpine:
- "3.19"
- "3.20"
- "3.20.6"
# Image avec toutes versions (dangereux)
busybox: []
tls-verify: true
# Registre source : Quay.io
quay.io:
images:
prometheus/prometheus:
- "v2.54.1"
- "v2.55.0"
coreos/etcd:
- "v3.5.17"
tls-verify: true
Exécution
# Synchroniser vers registre privé
skopeo sync --src yaml --dest docker sync.yaml registry.local/mirror/
# Simulation (dry-run)
skopeo sync --src yaml --dest docker --dry-run sync.yaml registry.local/mirror/
# Continuer malgré erreurs
skopeo sync --src yaml --dest docker --keep-going sync.yaml registry.local/mirror/
Options utiles
| Option | Description |
|---|---|
--dry-run |
Simule sans copier |
--keep-going |
Continue si une image échoue |
--scoped |
Préfixe avec chemin source (docker.io/library/nginx) |
--all |
Toutes les architectures |
--preserve-digests |
Conserve digests originaux |
Synchronisation d'un dépôt complet
# Tous les tags d'une image
skopeo sync --src docker --dest docker docker.io/library/alpine registry.local
Créer miroir local (répertoire)
# Télécharger vers disque
skopeo sync --src yaml --dest dir sync.yaml /backup/images/
# Pousser depuis disque vers registre
skopeo sync --src dir --dest docker /backup/images/ registry.local
Automatisation (cron)
#!/bin/bash
# /usr/local/bin/sync-mirror.sh
set -e
LOG_FILE="/var/log/skopeo-sync.log"
SYNC_FILE="/etc/skopeo/sync.yaml"
REGISTRY="registry.local/mirror/"
echo "$(date) - Starting sync" >> $LOG_FILE
skopeo sync --src yaml --dest docker --keep-going $SYNC_FILE $REGISTRY >> $LOG_FILE 2>&1
echo "$(date) - Sync completed" >> $LOG_FILE
# Crontab (sync quotidien à 2h)
0 2 * * * /usr/local/bin/sync-mirror.sh
Erreur "unauthorized: authentication required"
Solution 1 : Credentials en ligne de commande
skopeo inspect --creds utilisateur:mot_de_passe docker://registry.private.com/app:1.0.0
skopeo copy --src-creds user:pass --dest-creds user:pass \
docker://source/image:tag docker://dest/image:tag
Solution 2 : Login préalable
# Login (crée ~/.docker/config.json ou fichier XDG)
skopeo login registry.private.com
Username: admin
Password: ****
# Commandes suivantes utilisent le token
skopeo inspect docker://registry.private.com/app:1.0.0
Solution 3 : Fichier d'authentification
# Utiliser config Docker existante
skopeo inspect --authfile ~/.docker/config.json docker://registry.private.com/app:1.0.0
# Ou fichier personnalisé
skopeo inspect --authfile /etc/skopeo/auth.json docker://registry.private.com/app:1.0.0
Registres spécifiques
GitHub Container Registry (GHCR)
# Créer PAT avec scopes : read:packages, write:packages
# https://github.com/settings/tokens
echo $GITHUB_TOKEN | skopeo login ghcr.io -u $GITHUB_USER --password-stdin
skopeo copy docker://ghcr.io/me/app:1.0.0 dir:/tmp/app
Docker Hub
# Créer Access Token : https://hub.docker.com/settings/security
echo $DOCKER_TOKEN | skopeo login docker.io -u $DOCKER_USER --password-stdin
AWS ECR
# Token AWS (valide 12h)
aws ecr get-login-password | skopeo login --username AWS --password-stdin 123456789.dkr.ecr.eu-west-1.amazonaws.com
Dépannage
# Vérifier le fichier d'auth
cat ~/.docker/config.json | jq
# Tester la connexion
skopeo login --get-login registry.private.com
# Logout si token expiré
skopeo logout registry.private.com
skopeo login registry.private.com
Erreur "certificate signed by unknown authority"
Solution 1 : Désactiver la vérification TLS (test uniquement)
# ⚠️ Non recommandé en production
skopeo inspect --tls-verify=false docker://registry.local/app:1.0.0
skopeo copy --src-tls-verify=false --dest-tls-verify=false \
docker://registry.local/app:1.0.0 dir:/tmp/app
Solution 2 : Ajouter le certificat CA
# Créer répertoire pour le registre
sudo mkdir -p /etc/docker/certs.d/registry.local/
# Copier le certificat CA
sudo cp /chemin/vers/ca.crt /etc/docker/certs.d/registry.local/ca.crt
# Utiliser avec Skopeo
skopeo inspect --cert-dir /etc/docker/certs.d/registry.local docker://registry.local/app:1.0.0
Solution 3 : Ajouter CA au système
# Ubuntu/Debian
sudo cp ca.crt /usr/local/share/ca-certificates/registry-local.crt
sudo update-ca-certificates
# RHEL/Fedora
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
# Skopeo utilise maintenant le CA système
skopeo inspect docker://registry.local/app:1.0.0
Configuration permanente
# /etc/containers/registries.conf.d/registry-local.conf
[[registry]]
location = "registry.local"
insecure = false
[[registry.mirror]]
location = "registry.local"
insecure = false
Dépannage
# Vérifier le certificat du registre
openssl s_client -connect registry.local:443 -showcerts
# Télécharger le certificat
echo | openssl s_client -connect registry.local:443 2>/dev/null | openssl x509 -out /tmp/registry.crt
# Vérifier la chaîne
openssl verify -CAfile /tmp/ca.crt /tmp/registry.crt
Liste des transports
| Transport | Format | Description |
|---|---|---|
docker:// |
docker://registry/image:tag |
Registres Docker/OCI (Docker Hub, GHCR, Quay, Harbor, ECR) |
dir: |
dir:/chemin/local |
Répertoire avec layers et manifest |
docker-archive: |
docker-archive:/chemin/image.tar |
Archive tar format docker save |
oci: |
oci:/chemin:tag |
Répertoire layout OCI |
oci-archive: |
oci-archive:/chemin/image.tar |
Archive tar format OCI |
containers-storage: |
containers-storage:image:tag |
Stockage local Podman/Buildah |
docker-daemon: |
docker-daemon:image:tag |
Daemon Docker local |
Exemples d'utilisation
# Registre → Répertoire local
skopeo copy docker://nginx:1.27.3 dir:/tmp/nginx
# Registre → Archive Docker
skopeo copy docker://nginx:1.27.3 docker-archive:/tmp/nginx.tar
# Registre → Archive OCI
skopeo copy docker://nginx:1.27.3 oci-archive:/tmp/nginx-oci.tar
# Archive → Registre privé
skopeo copy docker-archive:/tmp/nginx.tar docker://registry.local/nginx:1.27.3
# Registre → Daemon Docker local
skopeo copy docker://nginx:1.27.3 docker-daemon:nginx:1.27.3
# Podman storage → Registre
skopeo copy containers-storage:myapp:1.0.0 docker://registry.local/myapp:1.0.0
Conversion entre formats
# Docker registry → OCI directory
skopeo copy docker://nginx:1.27.3 oci:nginx-oci:1.27.3
# OCI directory → Docker archive
skopeo copy oci:nginx-oci:1.27.3 docker-archive:nginx.tar
# Docker archive → OCI archive
skopeo copy docker-archive:nginx.tar oci-archive:nginx-oci.tar
Inspecter différents transports
# Registre distant
skopeo inspect docker://nginx:1.27.3
# Répertoire local
skopeo inspect dir:/tmp/nginx
# Archive
skopeo inspect docker-archive:/tmp/nginx.tar
Principe
Le digest (empreinte SHA256) identifie de manière unique le contenu d'une image. Deux images avec le même digest ont exactement le même contenu binaire.
Comparaison simple
# Digest de l'image source
skopeo inspect docker://docker.io/library/nginx:1.27.3 | jq -r '.Digest'
# sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef
# Digest de l'image destination
skopeo inspect docker://registry.local/nginx:1.27.3 | jq -r '.Digest'
# sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef
# → Identiques = images identiques
Script de comparaison
#!/bin/bash
SOURCE="docker://docker.io/library/nginx:1.27.3"
DEST="docker://registry.local/nginx:1.27.3"
DIGEST_SRC=$(skopeo inspect $SOURCE | jq -r '.Digest')
DIGEST_DST=$(skopeo inspect $DEST | jq -r '.Digest')
if [ "$DIGEST_SRC" = "$DIGEST_DST" ]; then
echo "✅ Images identiques"
echo " Digest: $DIGEST_SRC"
else
echo "❌ Images différentes"
echo " Source: $DIGEST_SRC"
echo " Dest: $DIGEST_DST"
fi
Comparer plusieurs champs
# Comparaison détaillée
skopeo inspect docker://source/image:tag > /tmp/source.json
skopeo inspect docker://dest/image:tag > /tmp/dest.json
diff <(jq -S . /tmp/source.json) <(jq -S . /tmp/dest.json)
Vérifier intégrité après copie
# Copier avec digestfile
skopeo copy --digestfile /tmp/digest.txt docker://nginx:1.27.3 docker://registry.local/nginx:1.27.3
# Vérifier
cat /tmp/digest.txt
# sha256:bc2f6a7c8ddbccf55bdb19659ce3b0a92ca6559e86d42677a5a02ef6bda2fcef
skopeo inspect docker://registry.local/nginx:1.27.3 | jq -r '.Digest'
# Doit correspondre
Commande de suppression
skopeo delete docker://registry.local/app:1.0.0-obsolete
Avec authentification
skopeo delete --creds admin:password docker://registry.local/app:1.0.0
# Ou après login
skopeo login registry.local
skopeo delete docker://registry.local/app:1.0.0
Limitations par registre
| Registre | Suppression API | Notes |
|---|---|---|
| Harbor | ✅ Oui | Nécessite rôle maintainer ou admin |
| Quay.io | ✅ Oui | Paramètre activé par défaut |
| Docker Hub | ❌ Non | Utiliser interface web |
| GHCR | ✅ Oui | Nécessite PAT avec delete:packages |
| ECR | ✅ Oui | Via API ou skopeo delete |
| GCR | ✅ Oui | Nécessite permissions appropriées |
Bonnes pratiques
# 1. Vérifier que l'image existe
skopeo inspect docker://registry.local/app:1.0.0
# 2. Vérifier qu'elle n'est plus utilisée
# (vérifier deployments Kubernetes, docker-compose, etc.)
# 3. Supprimer
skopeo delete docker://registry.local/app:1.0.0
# 4. Vérifier la suppression
skopeo inspect docker://registry.local/app:1.0.0
# Error: manifest unknown
Script de nettoyage (avec précaution)
#!/bin/bash
REGISTRY="registry.local"
IMAGE="app"
KEEP_LAST=5 # Garder les 5 derniers tags
# Lister tous les tags
TAGS=$(skopeo list-tags docker://$REGISTRY/$IMAGE | jq -r '.Tags[]' | sort -V)
# Supprimer les anciens (garder les 5 derniers)
echo "$TAGS" | head -n -$KEEP_LAST | while read tag; do
echo "Suppression de $REGISTRY/$IMAGE:$tag"
skopeo delete docker://$REGISTRY/$IMAGE:$tag
done
Attention
⚠️ La suppression est irréversible. Toujours :
- Vérifier que l'image n'est plus en production
- Avoir une sauvegarde si nécessaire
- Tester sur environnement de dev d'abord