Skopeo: Lightning-Fast Docker Image Copying Between Registries Without ‘Pulling’

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Give it a quick spin

Have you ever been frustrated waiting 15 minutes just to pull a 3GB image, re-tag it, and then push it to another registry? If so, Skopeo is your lifesaver.

Installing Skopeo on Ubuntu/Debian takes only a few seconds:

sudo apt-get update
sudo apt-get install -y skopeo

Suppose you need to move the nginx:latest image from Docker Hub to a private registry without downloading it to your local machine. Use this command:

skopeo copy \
    docker://docker.io/library/nginx:latest \
    docker://registry.mycompany.com/production/nginx:latest

In this case, Skopeo acts as a “broker,” coordinating data directly between the two registries via API. You don’t need Docker Engine, you don’t need sudo privileges, and most importantly, your disk remains empty.

Why should you ditch the Pull -> Tag -> Push workflow?

The traditional method typically causes three extremely frustrating issues for DevOps engineers:

  • Bandwidth consumption: Downloading 2GB of data and then uploading it back to another server is a massive waste of resources. If the network is slow, you could spend all morning just copying a few images.
  • Disk space exhaustion: Docker’s intermediate layers often take up significant space. On CI/CD runners with limited disk space (around 20GB), pulling heavy images will cause the pipeline to crash immediately.
  • Docker Daemon dependency: Not every environment has Docker pre-installed. In modern systems like Kubernetes, running Docker-inside-Docker often poses security risks.

Skopeo solves these problems completely. It communicates directly with the registry via HTTP API to manipulate manifests and layers without extracting anything to your machine.

Most practical features

1. Inspect: Peek into Image content in 1 second

Want to know if an image supports arm64 or amd64 before downloading? Instead of pulling it to check, use the inspect command:

skopeo inspect docker://docker.io/library/ubuntu:22.04

The result is a detailed JSON object containing tags, layers, and architecture. Pro tip: JSON output in the terminal can be hard to read. I usually copy it and paste it into the JSON formatter at toolcraft.app/en/tools/developer/json-formatter. This helps me analyze the image structure much faster than fiddling with extensions.

2. Copy: Move images anywhere

This command allows you to move images flexibly between different formats:

  • docker://: Transfer between standard registries.
  • oci://: Use the Open Container Initiative format.
  • dir://: Save the image to a directory (ideal for backups).

For example, to back up an image to an air-gapped server (no internet), you can just save it to a directory:

skopeo copy docker://alpine:latest dir:/home/dev/backup-alpine

3. Delete: Clean up remote registries

The Docker CLI doesn’t natively allow you to delete images directly from a registry. With Skopeo, if you have admin privileges, cleaning up old builds becomes effortless:

skopeo delete docker://registry.mycompany.com/old-app:v1

Handling Authentication and Private Registries

When working with systems that require authentication like AWS ECR or GitLab, you can pass credentials directly:

skopeo copy \
    --src-creds source_user:source_password \
    --dest-creds target_user:target_password \
    docker://docker.io/myrepo/private-image:latest \
    docker://quay.io/another-repo/image:latest

If you have already performed a docker login, Skopeo will automatically look for the ~/.docker/config.json file to retrieve the token. You won’t need to re-enter your password.

Batch sync with the ‘sync’ command

Imagine having to move 50 tags of a project from Docker Hub to Google Cloud. Instead of typing the command 50 times, you can just create a sync.yaml file:

'docker.io/itfromzero':
    images:
        nginx: ['1.21', '1.22', 'latest']
        redis: ['6.2', '7.0']

Then run the sync command: skopeo sync --src yaml --dest docker sync.yaml gcr.io/my-project. In just a few minutes, your entire image repository will be “cloned” to its new home.

Real-world implementation tips

Handling SSL errors with internal registries

If you use a self-hosted registry without a valid SSL certificate, Skopeo will throw a certificate error. Don’t worry, just add the --dest-tls-verify=false flag to bypass security checks.

Optimizing for CI/CD Pipelines

In Jenkins or GitLab Runners, I always prioritize Skopeo over Docker. It keeps the Runner VM completely clean after execution. You’ll no longer face pipeline hangs due to “No space left on device” errors caused by accumulated image junk.

In summary, if you frequently manage images or switch between cloud providers, Skopeo is an indispensable tool. It’s lightweight, fast, and makes your workflow much more professional.

Share: