How to Install and Use Skopeo for Container Image Management on RHEL 7
Skopeo is a command-line utility for performing operations on container images and image registries without requiring a running Docker daemon. It is part of the Open Container Initiative (OCI) ecosystem championed by Red Hat and is included in the standard RHEL extras and EPEL repositories. With Skopeo you can inspect image metadata, copy images between registries, list available tags, and mirror entire repositories — all without the overhead of pulling images to local Docker storage. On RHEL 7 systems where running a full Docker daemon is undesirable, or in CI pipelines where image promotion between registries is required, Skopeo is an indispensable tool.
Prerequisites
- RHEL 7 with active subscription, or CentOS 7 with EPEL enabled
- Root or
sudoaccess for package installation - Network access to source and destination container registries
- Credentials for any private registries you intend to use
- Optional: Docker CE installed if you want to compare behaviour with the Docker CLI
Step 1: Installing Skopeo on RHEL 7
On a registered RHEL 7 system, Skopeo is available in the extras channel. Enable the channel and install:
sudo subscription-manager repos --enable=rhel-7-server-extras-rpms
sudo yum install -y skopeo
skopeo --version
On CentOS 7 or RHEL 7 without a subscription, install from EPEL:
sudo yum install -y epel-release
sudo yum install -y skopeo
skopeo --version
Verify the installation and check the default policy file location:
which skopeo
rpm -qi skopeo
ls /etc/containers/
Step 2: Understanding Skopeo Image Transport Prefixes
Skopeo uses transport prefixes to specify where images come from or go to. Understanding these prefixes is essential for constructing copy and inspect commands:
docker://— A remote Docker registry (Docker Hub, quay.io, private registries)docker-daemon:— The local Docker daemon image storeoci:— An OCI image layout directory on diskoci-archive:— A tar archive containing an OCI image layoutdocker-archive:— A tar archive in Docker format (compatible withdocker load)dir:— A directory containing a raw image manifest and layer blobscontainers-storage:— The local Podman/Buildah container storage
Step 3: Inspecting Images Without Pulling
One of Skopeo’s most useful features is the ability to inspect an image’s metadata — configuration, layers, labels, environment variables — without downloading the full image:
# Inspect a public image from Docker Hub
skopeo inspect docker://docker.io/nginx:latest
# Inspect with formatted JSON output piped to jq
skopeo inspect docker://docker.io/nginx:latest | python -m json.tool
# Inspect a specific architecture variant
skopeo inspect --override-arch amd64 docker://docker.io/nginx:latest
# Inspect a private registry image (with credentials)
skopeo inspect
--creds myuser:mypassword
docker://registry.example.com/myapp:production
The output shows the image’s configuration digest, environment variables, exposed ports, labels, and layer digests — without transferring a single layer blob to disk.
Step 4: Listing Available Tags
Before copying or pulling an image, you often want to see what tags are available in a repository. Skopeo’s list-tags subcommand queries the registry API directly:
# List all tags for a public image
skopeo list-tags docker://docker.io/library/postgres
# List tags on a private registry
skopeo list-tags
--creds myuser:mypassword
docker://registry.example.com/myorg/myapp
# List tags on a registry with a self-signed certificate
skopeo list-tags
--tls-verify=false
docker://registry.internal.example.com/myapp
The output is a JSON object with a Tags array, which you can filter with standard UNIX tools:
skopeo list-tags docker://docker.io/library/node |
python -c "import sys,json; tags=json.load(sys.stdin)['Tags'];
[print(t) for t in tags if t.startswith('18')]"
Step 5: Copying Images Between Registries
The skopeo copy command is the core of Skopeo’s image management capability. It copies images directly between any two locations without buffering through the Docker daemon:
# Copy from Docker Hub to a private registry
skopeo copy
docker://docker.io/nginx:1.25
docker://registry.example.com/mirror/nginx:1.25
# Copy with authentication for both source and destination
skopeo copy
--src-creds srcuser:srcpassword
--dest-creds destuser:destpassword
docker://source-registry.example.com/app:v2.1
docker://dest-registry.example.com/app:v2.1
# Copy to a local OCI directory (useful for air-gapped transfers)
skopeo copy
docker://docker.io/nginx:latest
oci:/tmp/nginx-oci:latest
# Copy from OCI directory back to a registry
skopeo copy
oci:/tmp/nginx-oci:latest
docker://registry.example.com/mirror/nginx:latest
To copy all platform variants (multi-arch manifest) in a single operation, use the --all flag:
skopeo copy --all
docker://docker.io/library/alpine:3.18
docker://registry.example.com/mirror/alpine:3.18
Step 6: Saving and Loading Images Without a Daemon
For transferring images to air-gapped environments, copy to a Docker-compatible tar archive that can be loaded directly with docker load:
# Save image as docker-archive tar (compatible with docker load)
skopeo copy
docker://docker.io/postgres:15
docker-archive:/tmp/postgres15.tar:postgres:15
# Transfer to air-gapped host and load
scp /tmp/postgres15.tar airgapped-host:/tmp/
# On the air-gapped host:
docker load -i /tmp/postgres15.tar
docker images | grep postgres
Step 7: Mirroring Repositories with skopeo sync
The skopeo sync command mirrors entire repositories or specific tag sets in a single operation. This is ideal for maintaining a local mirror of upstream images for disconnected environments:
# Create a sync configuration file
cat > /etc/skopeo/sync-config.yaml <<'EOF'
docker.io:
images:
nginx:
- "1.24"
- "1.25"
- "latest"
postgres:
- "15"
- "15-alpine"
images-by-tag-regex:
node:
- "^18-alpine"
EOF
# Sync to a private registry
skopeo sync
--src yaml
--dest docker
--dest-creds admin:password
/etc/skopeo/sync-config.yaml
registry.example.com/mirror
# Sync to a local OCI directory for offline transfer
skopeo sync
--src yaml
--dest dir
/etc/skopeo/sync-config.yaml
/mnt/usb/image-mirror/
Set up a cron job on RHEL 7 to run the sync on a schedule, ensuring the mirror stays current:
cat > /etc/cron.d/skopeo-mirror <<'EOF'
0 2 * * * root /usr/bin/skopeo sync
--src yaml --dest docker
--dest-creds admin:password
/etc/skopeo/sync-config.yaml
registry.example.com/mirror
>> /var/log/skopeo-sync.log 2>&1
EOF
Step 8: Configuring policy.json for Image Verification
Skopeo uses /etc/containers/policy.json to enforce signature verification policies. The default on RHEL 7 requires images from registry.access.redhat.com to be signed, while allowing all others. You can customise this to enforce signing for your private registry:
cat /etc/containers/policy.json
# Example: require signatures for your private registry
cat > /etc/containers/policy.json <<'EOF'
{
"default": [{"type": "insecureAcceptAnything"}],
"transports": {
"docker": {
"registry.example.com": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/etc/containers/registry.example.com.pub"
}
],
"registry.access.redhat.com": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
}
]
}
}
}
EOF
To skip policy verification temporarily during testing, use the --policy flag with a permissive policy file or pass --insecure-policy:
skopeo copy --insecure-policy
docker://docker.io/nginx:latest
docker://registry.example.com/test/nginx:latest
Conclusion
Skopeo fills a critical gap in the container toolchain on RHEL 7 by enabling registry operations without a running Docker daemon. Whether you are promoting images through CI/CD pipelines, mirroring upstream images for disconnected environments, auditing image metadata before deployment, or enforcing signature policies across your registry infrastructure, Skopeo provides a lightweight and scriptable solution. Its support for multiple transport formats makes it a versatile bridge between different image storage systems, and its integration with the OCI ecosystem ensures long-term compatibility with the broader container tooling landscape on Red Hat Enterprise Linux.