$ -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y skopeo jq
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y skopeo jq
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install -y skopeo jq
skopeo --version
skopeo --version
skopeo --version
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq '{Name, Digest, Created, Architecture, Os, Layers}'
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq '{Name, Digest, Created, Architecture, Os, Layers}'
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq '{Name, Digest, Created, Architecture, Os, Layers}'
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest'
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest'
skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest'
skopeo list-tags -weight: 500;">docker://-weight: 500;">docker.io/library/alpine | jq '.Tags[:20]'
skopeo list-tags -weight: 500;">docker://-weight: 500;">docker.io/library/alpine | jq '.Tags[:20]'
skopeo list-tags -weight: 500;">docker://-weight: 500;">docker.io/library/alpine | jq '.Tags[:20]'
DIGEST=$(skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest')
printf '%s\n' "$DIGEST"
DIGEST=$(skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest')
printf '%s\n' "$DIGEST"
DIGEST=$(skopeo inspect -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 | jq -r '.Digest')
printf '%s\n' "$DIGEST"
mkdir -p ./mirror/alpine
skopeo copy \ --preserve-digests \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine@${DIGEST}" \ oci:./mirror/alpine:3.20
mkdir -p ./mirror/alpine
skopeo copy \ --preserve-digests \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine@${DIGEST}" \ oci:./mirror/alpine:3.20
mkdir -p ./mirror/alpine
skopeo copy \ --preserve-digests \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine@${DIGEST}" \ oci:./mirror/alpine:3.20
find ./mirror/alpine -maxdepth 2 -type f | sort
find ./mirror/alpine -maxdepth 2 -type f | sort
find ./mirror/alpine -maxdepth 2 -type f | sort
mkdir -p ./archives
skopeo copy \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20" \ -weight: 500;">docker-archive:./archives/alpine-3.20.tar:-weight: 500;">docker.io/library/alpine:3.20
mkdir -p ./archives
skopeo copy \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20" \ -weight: 500;">docker-archive:./archives/alpine-3.20.tar:-weight: 500;">docker.io/library/alpine:3.20
mkdir -p ./archives
skopeo copy \ "-weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20" \ -weight: 500;">docker-archive:./archives/alpine-3.20.tar:-weight: 500;">docker.io/library/alpine:3.20
skopeo list-tags -weight: 500;">docker-archive:./archives/alpine-3.20.tar | jq
skopeo list-tags -weight: 500;">docker-archive:./archives/alpine-3.20.tar | jq
skopeo list-tags -weight: 500;">docker-archive:./archives/alpine-3.20.tar | jq
# sync.yml
-weight: 500;">docker.io: images: library/alpine: - "3.20" library/busybox: - "1.36"
quay.io: images: libpod/alpine: - "latest"
# sync.yml
-weight: 500;">docker.io: images: library/alpine: - "3.20" library/busybox: - "1.36"
quay.io: images: libpod/alpine: - "latest"
# sync.yml
-weight: 500;">docker.io: images: library/alpine: - "3.20" library/busybox: - "1.36"
quay.io: images: libpod/alpine: - "latest"
mkdir -p /tmp/skopeo-mirror
skopeo sync --dry-run --src yaml --dest dir sync.yml /tmp/skopeo-mirror
mkdir -p /tmp/skopeo-mirror
skopeo sync --dry-run --src yaml --dest dir sync.yml /tmp/skopeo-mirror
mkdir -p /tmp/skopeo-mirror
skopeo sync --dry-run --src yaml --dest dir sync.yml /tmp/skopeo-mirror
skopeo sync --src yaml --dest dir sync.yml /tmp/skopeo-mirror
skopeo sync --src yaml --dest dir sync.yml /tmp/skopeo-mirror
skopeo sync --src yaml --dest dir sync.yml /tmp/skopeo-mirror
find /tmp/skopeo-mirror -maxdepth 3 -type f | sort
find /tmp/skopeo-mirror -maxdepth 3 -type f | sort
find /tmp/skopeo-mirror -maxdepth 3 -type f | sort
skopeo copy \ --preserve-digests \ -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 \ -weight: 500;">docker://registry.example.com/base/alpine:3.20
skopeo copy \ --preserve-digests \ -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 \ -weight: 500;">docker://registry.example.com/base/alpine:3.20
skopeo copy \ --preserve-digests \ -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 \ -weight: 500;">docker://registry.example.com/base/alpine:3.20
skopeo login registry.example.com
skopeo login registry.example.com
skopeo login registry.example.com
skopeo inspect -weight: 500;">docker://registry.example.com/base/alpine:3.20 | jq '{Name, Digest}'
skopeo inspect -weight: 500;">docker://registry.example.com/base/alpine:3.20 | jq '{Name, Digest}'
skopeo inspect -weight: 500;">docker://registry.example.com/base/alpine:3.20 | jq '{Name, Digest}'
${XDG_RUNTIME_DIR}/containers/auth.json
${XDG_RUNTIME_DIR}/containers/auth.json
${XDG_RUNTIME_DIR}/containers/auth.json
skopeo copy --all -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 oci:./mirror/alpine-all:3.20
skopeo copy --all -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 oci:./mirror/alpine-all:3.20
skopeo copy --all -weight: 500;">docker://-weight: 500;">docker.io/library/alpine:3.20 oci:./mirror/alpine-all:3.20 - inspect an image before trusting it
- pin the exact digest your CI should promote
- copy an image into an OCI layout or a -weight: 500;">docker-archive
- mirror a small approved set of images for a disconnected environment - works with remote registries and OCI/Docker image formats
- does not require a daemon for most operations
- usually does not require root unless you target a runtime storage backend
- can inspect remote images without fully pulling them first - CI pipelines that need to validate or promote images
- bastion or utility hosts that should stay lean
- air-gapped preparation workflows
- safer image promotion where you want digest-based control - you can confirm the registry path and digest before promotion
- you can inspect labels and metadata without populating local image storage
- you can use the digest for reproducible downstream steps - an OCI image layout on disk
- a workflow tied to the exact content you inspected
- less risk that a tag changes between validation and promotion - hand off an image file between environments
- preload images onto systems without direct registry access
- feed a controlled artifact into another stage - a reviewable allowlist of images and tags
- a repeatable sync definition you can commit to Git
- a clean boundary for disconnected or regulated environments - ~/.config/containers/auth.json
- ~/.-weight: 500;">docker/config.json
- ~/.dockercfg - skopeo inspect the candidate image
- record the digest
- copy by digest, not by tag
- verify the destination digest
- sync only approved images through a YAML allowlist when building mirrors - Skopeo upstream project: https://github.com/containers/skopeo
- skopeo(1) man page: https://manpages.ubuntu.com/manpages/noble/man1/skopeo.1.html
- skopeo-copy(1) man page: https://manpages.ubuntu.com/manpages/noble/man1/skopeo-copy.1.html
- skopeo-sync(1) man page: https://manpages.ubuntu.com/manpages/noble/man1/skopeo-sync.1.html
- skopeo-list-tags(1) man page: https://manpages.ubuntu.com/manpages/noble/man1/skopeo-list-tags.1.html
- containers-transports(5) man page: https://manpages.ubuntu.com/manpages/noble/man5/containers-transports.5.html
- containers-auth.json(5) man page: https://manpages.ubuntu.com/manpages/noble/man5/containers-auth.json.5.html
- Cover image: Wikimedia Commons, Utah Data Center panorama: https://commons.wikimedia.org/wiki/File:Utah_Data_Center_Panorama_(cropped).jpg