Skopeo est un outil en ligne de commande pour effectuer des opérations sur des images et des registries de conteneurs sans avoir besoin du daemon Docker, ni de root. Développé par Red Hat dans le cadre du projet containers/, il fait partie de la même famille que Podman et Buildah.
Sa commande principale est skopeo copy : elle copie une image d'une source vers une destination en supportant des dizaines de combinaisons de transports (docker://, oci://, docker-archive://, dir://...). C'est l'outil de référence pour les migrations air-gapped, la synchronisation inter-registries et l'inspection de manifests en CI/CD.
Idéal pour : copier des images entre registries sans les télécharger sur le disque local, synchroniser des registries en air-gapped, inspecter des manifests d'images sans docker pull, supprimer des tags depuis un registry.
Informations essentielles
Origine : Red Hat / projet containers/ · Licence : Apache 2.0 · Architectures : x86_64, ARM64, ppc64le, s390x
Liens : GitHub · Documentation · Releases
Support : Maintenu activement par Red Hat. Intégré dans RHEL/Fedora. Releases régulières.
Transports supportés
| Transport | Description |
|---|---|
docker:// | Registry distant (Docker Hub, Harbor, ECR...) |
oci:// | Dossier au format OCI Image Layout |
docker-archive:// | Fichier tar au format Docker (docker save/load) |
oci-archive:// | Fichier tar au format OCI |
docker-daemon:// | Daemon Docker local |
containers-storage:// | Storage Podman/Buildah local |
dir:// | Dossier en format natif Skopeo |
Installation
RHEL / Rocky Linux / Fedora
sudo dnf install -y skopeo
skopeo --version
Ubuntu / Debian
sudo apt-get install -y skopeo
skopeo --version
Binaires officiels
# Via le dépôt Kubic
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" \
| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
sudo apt-get update && sudo apt-get install -y skopeo
Copier des images
skopeo copy est la commande centrale. Elle ne télécharge pas l'image localement - elle la transfère directement de source à destination layer par layer.
# Docker Hub -> registry privé
skopeo copy \
docker://nginx:alpine \
docker://registry.example.com/mirror/nginx:alpine
# Avec authentification
skopeo copy \
--src-creds=user:password \
--dest-creds=user:password \
docker://source-registry.example.com/mon-app:1.0 \
docker://dest-registry.example.com/mon-app:1.0
# Registry -> fichier tar Docker (pour transport physique)
skopeo copy \
docker://nginx:alpine \
docker-archive:///tmp/nginx-alpine.tar
# Fichier tar -> registry (import air-gapped)
skopeo copy \
docker-archive:///tmp/nginx-alpine.tar \
docker://registry.example.com/nginx:alpine
# Registry -> dossier OCI
skopeo copy \
docker://nginx:alpine \
oci:///data/nginx-oci:alpine
Copie multi-architecture
# Copier tous les manifests (multi-arch) en préservant l'index OCI
skopeo copy --all \
docker://nginx:alpine \
docker://registry.example.com/nginx:alpine
# Sans --all, seule l'image de l'architecture courante est copiée
Inspecter sans télécharger
skopeo inspect récupère le manifest et les métadonnées d'une image sans télécharger les layers.
# Inspecter depuis Docker Hub
skopeo inspect docker://nginx:alpine
# Output JSON incluant :
# - Architecture, OS
# - Labels
# - Variables d'environnement
# - Layers (digests SHA256)
# - Digest de l'image
# Afficher uniquement le digest
skopeo inspect docker://nginx:alpine | jq '.Digest'
# Inspecter le manifest brut (format OCI)
skopeo inspect --raw docker://nginx:alpine | jq .
# Inspecter une image multi-arch (l'index)
skopeo inspect --raw docker://nginx:alpine | jq '.manifests[] | {platform, digest}'
Synchronisation de dépôts
skopeo sync copie un dépôt entier (ou une liste d'images) vers une destination.
# Synchroniser un dépôt entier
skopeo sync \
--src docker \
--dest docker \
registry-source.example.com/mon-projet \
registry-dest.example.com/mon-projet
# Synchroniser depuis un fichier de liste (YAML)
# images.yaml :
# registry-source.example.com:
# images:
# nginx: ["alpine", "1.25"]
# redis: ["7-alpine"]
skopeo sync \
--src yaml \
--dest docker \
images.yaml \
registry-dest.example.com
Fichier de liste pour air-gapped
# images.yaml
registry-1.docker.io:
images:
library/nginx:
- "alpine"
- "1.25-alpine"
library/postgres:
- "16-alpine"
ghcr.io:
images:
cert-manager/cert-manager-controller:
- "v1.14.0"
# Sync vers un dossier local (pour clé USB / transport physique)
skopeo sync \
--src yaml \
--dest dir \
images.yaml \
/media/usb/images/
# Puis importer depuis le dossier sur le réseau isolé
skopeo sync \
--src dir \
--dest docker \
/media/usb/images/registry-1.docker.io \
registry.interne.example.com
Lister les tags
# Lister tous les tags d'une image
skopeo list-tags docker://nginx
skopeo list-tags docker://registry.example.com/mon-app
# Avec authentification
skopeo list-tags \
--creds=user:password \
docker://registry.example.com/mon-app
Supprimer des images
# Supprimer un tag depuis un registry
skopeo delete docker://registry.example.com/mon-app:old-tag
# Avec authentification
skopeo delete \
--creds=user:password \
docker://registry.example.com/mon-app:old-tag
# Note : certains registries nécessitent que la suppression par digest soit activée
# (distribution: storage.delete.enabled: true)
Authentification
Fichier de credentials (recommandé en CI/CD)
# Skopeo lit ~/.docker/config.json automatiquement après docker login
docker login registry.example.com
# Ou spécifier un fichier de credentials différent
skopeo --authfile /path/to/auth.json copy ...
# Format du fichier auth.json
{
"auths": {
"registry.example.com": {
"auth": "<base64(user:password)>"
}
}
}
Variables d'environnement (CI/CD)
# Inline dans la commande
skopeo copy \
--src-creds="${SRC_USER}:${SRC_PASSWORD}" \
--dest-creds="${DEST_USER}:${DEST_PASSWORD}" \
docker://source/image:tag \
docker://dest/image:tag
Utilisation en CI/CD
Promotion d'image entre environnements
# Promouvoir une image de staging vers production (sans rebuilder)
skopeo copy \
--src-creds="${STAGING_USER}:${STAGING_PASS}" \
--dest-creds="${PROD_USER}:${PROD_PASS}" \
docker://staging-registry.example.com/mon-app:${CI_COMMIT_SHA} \
docker://prod-registry.example.com/mon-app:${VERSION}
Vérifier qu'une image existe avant déploiement
if skopeo inspect docker://registry.example.com/mon-app:${VERSION} > /dev/null 2>&1; then
echo "Image existe - déploiement possible"
else
echo "Image manquante - build requis"
exit 1
fi
Mise à jour
# RHEL / Rocky / Fedora
sudo dnf update skopeo
# Ubuntu / Debian
sudo apt-get install --only-upgrade skopeo
skopeo --version
Commandes utiles
# Copier
skopeo copy docker://source:tag docker://dest:tag
skopeo copy --all docker://source:tag docker://dest:tag # multi-arch
# Inspecter
skopeo inspect docker://image:tag
skopeo inspect --raw docker://image:tag | jq .
# Lister
skopeo list-tags docker://image
# Supprimer
skopeo delete docker://registry/image:tag
# Synchroniser
skopeo sync --src docker --dest docker source-registry/repo dest-registry
skopeo sync --src yaml --dest dir images.yaml /data/
Ressources
- GitHub : https://github.com/containers/skopeo
- Documentation man : https://github.com/containers/skopeo/blob/main/docs/skopeo.1.md
- Guide air-gapped : https://github.com/containers/skopeo/blob/main/docs/skopeo-sync.1.md
- Podman (même famille) : https://podman.io
- Buildah (même famille) : https://buildah.io