What it is
Skopeo is a command-line utility that performs various operations on container images and container image registries, like copying images between registries, inspecting images, and deleting them, without needing to build or run a container.
Installation
Linux (Debian/Ubuntu):
sudo apt-get update
sudo apt-get install skopeo
Linux (Fedora/CentOS/RHEL):
sudo dnf install skopeo
# or
sudo yum install skopeo
macOS:
brew install skopeo
Windows: Skopeo can be run on Windows via the Windows Subsystem for Linux (WSL). Install Skopeo within your WSL distribution using the Linux instructions above.
Core Concepts
- Image Reference: A string that uniquely identifies a container image. This typically includes the registry, repository, and optionally a tag or digest. Examples:
docker.io/library/ubuntu:latest,quay.io/prometheus/node-exporter@sha256:abcdef123... - Registry: A storage and distribution system for container images (e.g., Docker Hub, Quay.io, ghcr.io).
- Copy: Skopeo can copy images between different registries, or from a registry to a local directory (as a tarball or OCI layout), or vice-versa.
- Inspect: Skopeo can retrieve metadata about a container image without pulling the entire image.
- Delete: Skopeo can delete images from a registry.
Commands / Usage
Inspecting Images
Inspect an image from Docker Hub:
skopeo inspect docker://docker.io/library/ubuntu:latest
Shows detailed metadata about the ubuntu:latest image on Docker Hub.
Inspect an image from a private registry (requires authentication):
skopeo inspect --creds your-username:your-password docker://your-registry.com/your-repo/your-image:v1.0
Shows metadata for a specific image, using provided credentials for authentication.
Inspect an image and output in JSON format:
skopeo inspect --format json docker://docker.io/library/alpine:3.18
Retrieves image metadata and formats the output as JSON.
Copying Images
Copy an image from Docker Hub to a private registry:
skopeo copy docker://docker.io/library/nginx:stable docker://your-registry.com/my-apps/nginx:v1.25
Copies the nginx:stable image from Docker Hub to your-registry.com under the my-apps repository as v1.25.
Copy an image from one private registry to another:
skopeo copy docker://registry-a.com/team-a/app:latest docker://registry-b.com/team-b/app:latest
Copies an image between two different private registries.
Copy an image to a local directory (OCI layout):
skopeo copy docker://docker.io/library/redis:7.0 oci:./redis-oci-layout
Copies the redis:7.0 image from Docker Hub into a local directory named redis-oci-layout in OCI image layout format.
Copy an image to a local directory (tarball):
skopeo copy docker://docker.io/library/memcached:1.6.22 docker-archive:./memcached-1.6.22.tar
Copies the memcached:1.6.22 image from Docker Hub into a local tar archive.
Copy an image from a local directory (OCI layout) to a registry:
skopeo copy oci:./my-app-oci-layout docker://your-registry.com/my-apps/my-app:v2.0
Pushes an image stored in OCI layout format from a local directory to a registry.
Copy an image from a local tarball to a registry:
skopeo copy docker-archive:./my-app-v1.tar docker://your-registry.com/my-apps/my-app:v1.0
Pushes an image stored in a Docker archive tarball to a registry.
Copy an image with a specific manifest type:
skopeo copy --dest-manifest-type application/vnd.oci.image.manifest.v1+json docker://docker.io/library/ubuntu:latest docker://your-registry.com/ubuntu:latest
Ensures the copied image uses the OCI manifest type.
Copy an image, preserving layers:
skopeo copy --src-transport docker --dest-transport docker docker://docker.io/library/ubuntu:latest docker://your-registry.com/ubuntu:latest
Explicitly sets source and destination transport types (defaulting to docker).
Copy an image, forcing re-creation of layers:
skopeo copy --purge-destination=true docker://docker.io/library/ubuntu:latest docker://your-registry.com/ubuntu:latest
If the destination image already exists, this flag attempts to purge it before copying. Use with caution.
Deleting Images
Delete an image from a registry:
skopeo delete docker://your-registry.com/your-repo/your-image:v1.0
Deletes the specified image tag from the registry. Note that this only removes the manifest and potentially the associated layers if no other tags reference them.
Delete an image using its digest:
skopeo delete docker://your-registry.com/your-repo/your-image@sha256:abcdef1234567890...
Deletes the image identified by its specific digest from the registry.
Working with Signatures
Copy an image along with its signature:
skopeo copy --src-creds user:pass --dest-creds user:pass docker://docker.io/library/alpine:latest docker://your-registry.com/alpine:latest
This command implicitly handles copying signatures if the source and destination formats support it and authentication is provided.
Inspect image signatures:
skopeo inspect --tls-verify=false --raw docker://localhost:5000/myimage:latest | jq .
While skopeo inspect doesn’t directly show signatures, you can inspect the raw manifest and look for signature-related fields if the registry or image format exposes them. For detailed signature inspection, tools like cosign are more appropriate.
Other Operations
Sync an image from one registry to another:
skopeo sync docker://docker.io/library/fedora:latest docker://your-registry.com/fedora:latest
Copies the image if it doesn’t exist at the destination or if the source manifest is newer.
List tags for a repository:
skopeo list-tags docker://docker.io/library/ubuntu
Lists all available tags for the ubuntu repository on Docker Hub.
Get the raw manifest of an image:
skopeo raw-manifest docker://docker.io/library/hello-world:latest
Retrieves the raw image manifest (v1 or v2) in JSON format.
Common Patterns
Copying the latest version of an image to a private registry:
skopeo copy docker://docker.io/library/ubuntu:latest docker://my.private.registry/ubuntu:latest
A very common workflow for mirroring public images to a private registry.
Copying an image to a local directory for inspection or backup:
skopeo copy docker://docker.io/library/redis:7.0 oci:./redis-oci-layout
Creates a local OCI layout directory that can be inspected with tools like buildah or podman.
Checking for updates before copying:
{% raw %}
LATEST_DIGEST=$(skopeo inspect --format '{{.Digest}}' docker://docker.io/library/nginx:latest)
{% endraw %}
{% raw %}
CURRENT_DIGEST=$(skopeo inspect --format '{{.Digest}}' docker://my.private.registry/nginx:latest || echo "notfound")
{% endraw %}
if [ "$LATEST_DIGEST" != "$CURRENT_DIGEST" ]; then
echo "Newer version found. Copying..."
skopeo copy docker://docker.io/library/nginx:latest docker://my.private.registry/nginx:latest
else
echo "Image is up-to-date."
fi
A script to check if an image has been updated in the source registry before performing a copy.
Copying an image to a Kubernetes-compatible registry:
skopeo copy docker://docker.io/library/my-app:v1.2.3 docker://registry.k8s.local/my-apps/my-app:v1.2.3
Often used to load images into private registries accessible by Kubernetes clusters.
Removing dangling images from a registry (requires registry API support):
# This is a conceptual example, actual implementation depends on registry capabilities
# Skopeo deletes manifests, but garbage collection is a registry feature.
# You might need to manually trigger garbage collection on your registry.
skopeo delete docker://my.private.registry/old-app:v1.0
# Then, potentially trigger garbage collection on my.private.registry
Skopeo removes the manifest for v1.0. The registry’s garbage collection process will then remove the actual layers if they are no longer referenced by any manifest.
Gotchas
- Authentication: For private registries, you must provide credentials. Skopeo can read credentials from standard input (
--creds), environment variables (REGISTRY_USERNAME,REGISTRY_PASSWORD), or configuration files. - Manifest Types: Skopeo supports both Docker V2 and OCI image formats. Be aware of the differences, especially when copying between registries that might prefer one over the other. The
--dest-manifest-typeflag can help control this. - Registry API Support: Some operations, like deleting images, rely on the registry providing the necessary API endpoints. Not all registries fully implement or expose these features.
- Layer Deduplication: When copying between registries that share a common underlying storage (e.g., two registries using the same S3 bucket), Skopeo might not always achieve perfect deduplication. The
skopeo copycommand copies manifests and layers independently unless specific registry features are leveraged. - Security Context: Skopeo operates outside of a container runtime. It doesn’t need Docker or Podman running. This is a feature, but it means it doesn’t inherit any security context or storage drivers from those runtimes.
--purge-destinationBehavior: This flag is powerful but can be destructive. It attempts to delete the destination image before copying. If the delete operation fails, the copy might also fail or result in an inconsistent state. Use with extreme caution.- TLS Verification: For registries using self-signed certificates or internal CAs, you might need to disable TLS verification (
--tls-verify=false) or provide custom CA certificates (--registry-ca-dir). Be cautious when disabling verification in production environments.