Skopeo is a command-line tool for working with container images and registries without requiring a running container daemon. On RHEL 8 it is available directly from the default repositories, making it one of the easiest container tools to install and use. Unlike Docker CLI, Skopeo can inspect, copy, sync, and delete images across registries without ever pulling an image to disk as a running container. This tutorial covers the most useful Skopeo operations for day-to-day container image management on RHEL 8.
Prerequisites
- RHEL 8 system with a valid subscription or CentOS Stream 8 equivalent
- Root or sudo access
- Network access to at least one container registry (Docker Hub, Quay.io, or a private registry)
- Optional: credentials for a private registry stored in
~/.config/containers/auth.json
Step 1 — Install Skopeo
Skopeo ships with RHEL 8’s container-tools module and requires no additional repository configuration. It installs alongside Podman in the container-tools application stream.
# Install Skopeo directly — no Docker daemon needed
dnf install -y skopeo
# Verify installation
skopeo --version
# Install the full container-tools module for Podman + Skopeo + Buildah
dnf module install -y container-tools
# Log in to a registry (credentials saved to auth.json)
skopeo login docker.io
skopeo login registry.example.com --username admin --password-stdin
Step 2 — Inspect Images Without Pulling
One of Skopeo’s most useful features is the ability to inspect an image’s metadata, layers, and manifest without downloading the full image. This is ideal for auditing images before pulling them into a production environment.
# Inspect an image on Docker Hub (no daemon, no pull)
skopeo inspect docker://nginx:latest
# Inspect a specific architecture variant
skopeo inspect --override-arch amd64 docker://nginx:latest
# Show only the image labels
skopeo inspect docker://nginx:latest | python3 -m json.tool | grep -i label -A 10
# Inspect an image in a private registry
skopeo inspect docker://registry.example.com/myapp:1.0.0
# Get the raw image manifest
skopeo inspect --raw docker://nginx:latest | python3 -m json.tool
Step 3 — Copy Images Between Registries
Skopeo can copy images directly from one registry to another without saving them to disk. This is perfect for promoting images through staging, production, and air-gapped environments.
# Copy from Docker Hub to a private registry
skopeo copy
docker://nginx:latest
docker://registry.example.com/mirror/nginx:latest
# Copy to a local directory (OCI format)
skopeo copy
docker://nginx:latest
oci:/tmp/nginx-oci:latest
# Copy to a Docker archive (compatible with docker load)
skopeo copy
docker://nginx:latest
docker-archive:/tmp/nginx.tar:nginx:latest
# Load the archive into Docker
docker load < /tmp/nginx.tar
# Copy preserving all architecture manifests (multi-arch)
skopeo copy --all
docker://nginx:latest
docker://registry.example.com/mirror/nginx:latest
Step 4 — Sync an Entire Repository
The skopeo sync command mirrors all tags of a repository — or even an entire registry namespace — to a destination. This is the recommended approach for populating an internal mirror or an air-gapped registry.
# Sync all tags of nginx from Docker Hub to a private registry
skopeo sync
--src docker --dest docker
nginx
registry.example.com/mirror/
# Sync to a local directory first, then push to the registry
skopeo sync
--src docker --dest dir
nginx
/tmp/registry-mirror/
skopeo sync
--src dir --dest docker
/tmp/registry-mirror/nginx
registry.example.com/mirror/
# Use a YAML config file to sync multiple repositories at once
cat > /tmp/sync-config.yaml <<'EOF'
registry.access.redhat.com:
images:
ubi8/ubi: ["latest", "8.9"]
ubi8/ubi-minimal: ["latest"]
docker.io:
images:
library/nginx: ["1.25", "1.26", "latest"]
EOF
skopeo sync
--src yaml --dest docker
/tmp/sync-config.yaml
registry.example.com/mirror/
Step 5 — Delete Images from a Registry
Skopeo can delete image tags directly from a registry that supports the Docker Registry HTTP API v2 DELETE endpoint. This is useful for automated cleanup pipelines.
# Delete a specific tag from a private registry
skopeo delete docker://registry.example.com/myapp:0.9.0
# Verify the tag is gone
skopeo inspect docker://registry.example.com/myapp:0.9.0 || echo "Tag not found"
# List all tags before deletion (using curl against the registry API)
curl -s https://registry.example.com/v2/myapp/tags/list | python3 -m json.tool
Step 6 — Convert Between Image Formats
Skopeo supports multiple image transport formats. Converting between them is useful when integrating with different toolchains — for example, building with Buildah in OCI format and loading into Docker.
# Convert OCI image to Docker archive
skopeo copy
oci:/tmp/myapp-oci:latest
docker-archive:/tmp/myapp-docker.tar:myapp:latest
# Convert Docker archive to OCI layout
skopeo copy
docker-archive:/tmp/myapp-docker.tar
oci:/tmp/myapp-oci-out:latest
# Compare two image manifests to see differences between versions
skopeo inspect --raw docker://nginx:1.25 > /tmp/manifest-1.25.json
skopeo inspect --raw docker://nginx:1.26 > /tmp/manifest-1.26.json
diff /tmp/manifest-1.25.json /tmp/manifest-1.26.json
# Supported transport prefixes:
# docker:// — remote registry
# docker-archive:— tar file (docker save/load format)
# oci: — OCI image layout directory
# oci-archive: — OCI image as tar
# containers-storage: — local containers/storage (Podman, Buildah)
Conclusion
Skopeo fills the gap between the Docker daemon and the container registry, offering lightweight inspection, copying, syncing, and deletion without ever requiring a running daemon or root privileges in most operations. On RHEL 8 it is available out of the box via the container-tools module and integrates naturally with Podman and Buildah in a daemonless container workflow. Its ability to copy directly between registries and mirror entire repositories makes it an indispensable tool for maintaining internal registries, seeding air-gapped environments, and auditing images before deployment.
Next steps: How to Build Docker Images with Multi-Stage Builds on RHEL 8, How to Configure Docker Daemon TLS Encryption on RHEL 8, and How to Set Up a Kubernetes Dashboard on RHEL 8.