SKOPEO-SYNC(1)
π skopeo-sync(1): sync images, bestie edition π
πΈ NAME πΈ
skopeo-sync β synchronize images between registry repositories and local directories. π
β¨ SYNOPSIS β¨
skopeo sync [options] --src transport --dest transport source
destination
π¦ DESCRIPTION π¦
Okay so skopeo sync synchronizes images between registry repositories and local directories. It does this by copying all the images it finds at source over to destination β which is lowkey perfect for syncing a local container registry mirror, or for populating registries running inside air-gapped environments. π
Unlike other skopeo commands, skopeo sync makes you specify both the source and destination transports separately from source and destination. Why? Because if you prefix a destination with its transport, the registry docker://hostname:port would be wrongly interpreted as an image reference at a non-fully qualified registry, with hostname and port becoming the image name and tag. Messy. π So we keep them separate, periodt.
π Available source transports
docker(i.e.--src docker) β source is a repository hosted on a container registry (e.g.:registry.example.com/busybox). If no image tag is specified,skopeo synccopies all the tags found in that repository. β¨dir(i.e.--src dir) β source is a local directory path (e.g.:/media/usb/). Refer toskopeo(1)dir:pathfor the local image format. πyaml(i.e.--src yaml) β source is a local YAML file path. The YAML file should specify the list of images copied from different container registries (local directories are not supported). Refer toEXAMPLESfor the file format. π
π― Available destination transports
docker(i.e.--dest docker) β destination is a container registry (e.g.:my-registry.local.lan). π³dir(i.e.--dest dir) β destination is a local directory path (e.g.:/media/usb/). One directory per sourceimage:tagis created for each copied image. πΎ
When the --scoped option is specified, images are prefixed with the source image path so that multiple images with the same name can be stored at destination. Slay. π
β¨ OPTIONS β¨
Also check out skopeo(1) for options placed before the subcommand name. π
--all,-aβ If one of the images in src refers to a list of images, instead of copying just the image which matches the current OS and architecture (subject to the use of the global--override-os,--override-archand--override-variantoptions), attempt to copy all of the images in the list, and the list itself. π«Ά--authfilepath β Path of the primary registry credentials file. On Linux, the default is${XDG_RUNTIME_DIR}/containers/auth.json. Seecontainers-auth.json(5)for more details about the credential search mechanism and defaults on other platforms. Useskopeo loginto manage the credentials. The default value of this option is read from theREGISTRY_AUTH_FILEenvironment variable. π--src-authfilepath β Path of the primary registry credentials file for the source registry. Uses path given by--authfile, if not provided. π--dest-authfilepath β Path of the primary registry credentials file for the destination registry. Uses path given by--authfile, if not provided. π--dry-runβ Run the sync without actually copying data to the destination. π--src,-stransport β Transport for the source repository. π--dest,-dtransport β Destination transport. π―--format,-fmanifest-type β Manifest Type (oci,v2s1, orv2s2) to use when syncing image(s) to a destination (default is manifest type of source, with fallbacks). π§--help,-hβ Print usage statement. π--scopedβ Prefix images with the source image path, so that multiple images with the same name can be stored at destination. π--append-suffixtag-suffix β String to append to destination tags. π--digestfilepath β After copying the images from source, write the digest of the resulting images along with Image Reference. Like this:
sha256:bf91f90823248017a4f920fb541727fa8368dc6cf377a7debbd271cf6a31c8a7 docker://myhost.com/alpine:edge
sha256:31603596830fc7e56753139f9c2c6bd3759e48a850659506ebfb885d1cf3aef5 docker://myhost.com/postgres:14.3
--preserve-digestsβ Preserve the digests during copying. Fail if the digest cannot be preserved. This option does not change what will be copied; consider using--allat the same time. π₯--remove-signaturesβ Do not copy signatures, if any, from source-image. This is necessary when copying a signed image to a destination which does not support signatures. π«--remove-list-signaturesβ Do not copy the manifest list signature while preserving per-instance signatures. This provides more granular control than--remove-signatures, which removes all signatures. π―--sign-bykey-id β Add a βsimple signingβ signature using that key ID for an image name corresponding to destination-image. βοΈ--sign-by-sigstoreparam-file β Add a sigstore signature based on the options in the specified containers sigstore signing parameter file, param-file. Seecontainers-sigstore-signing-params.yaml(5)for details about the file format. π--sign-by-sigstore-private-keypath β Add a sigstore signature using a private key at path for an image name corresponding to destination-image. π--sign-by-sq-fingerprintfingerprint β Add a βsimple signingβ signature using a Sequoia-PGP key with the specified fingerprint. π§--sign-passphrase-filepath β The passphrase to use when signing with--sign-by,--sign-by-sigstore-private-keyor--sign-by-sq-fingerprint. Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable. π--src-credsusername[:password] β for accessing the source registry. π--dest-credsusername[:password] β for accessing the destination registry. π--src-cert-dirpath β Use certificates (*.crt,*.cert,*.key) at path to connect to the source registry or daemon. π--src-no-credsβ Access the registry anonymously. π΅οΈ--src-tls-verify=boolβ Require HTTPS and verify certificates when talking to a container source registry or daemon. Default to source registry entry inregistry.confsetting. π--dest-cert-dirpath β Use certificates (*.crt,*.cert,*.key) at path to connect to the destination registry or daemon. π--dest-no-credsβ Access the registry anonymously. π΅οΈ--dest-tls-verify=boolβ Require HTTPS and verify certificates when talking to a container destination registry or daemon. Default to destination registry entry inregistry.confsetting. π--src-registry-tokenβ Bearer token for accessing the source registry. ποΈ--dest-registry-tokenβ Bearer token for accessing the destination registry. ποΈ--retry-timesβ The number of times to retry. By default, no retries are attempted. π--retry-delayβ Fixed delay between retries. If not set (or set to0s), retry wait time will be exponentially increased based on the number of failed attempts. β³--keep-goingβ If any errors occur during copying of images, those errors are logged and the process continues syncing rest of the images and finally fails at the end. π--src-usernameβ The username to access the source registry. π€--src-passwordβ The password to access the source registry. π--dest-usernameβ The username to access the destination registry. π€--dest-passwordβ The password to access the destination registry. π
πΈ EXAMPLES πΈ
okay bestie, this is the receipts section π. Every command below is copy-pasteable exactly as written β no cap.
π Synchronizing to a local directory π
$ skopeo sync --src docker --dest dir registry.example.com/busybox /media/usb
Images are located at:
/media/usb/busybox:1-glibc
/media/usb/busybox:1-musl
/media/usb/busybox:1-ubuntu
...
/media/usb/busybox:latest
The ... is literally part of the list, so donβt come for me π
β itβs giving βthere are more tags, obviously.β
π Synchronizing to a container registry from local π
Images are located at:
/media/usb/busybox:1-glibc
Sync run:
$ skopeo sync --src dir --dest docker /media/usb/busybox:1-glibc my-registry.local.lan/test/
Destination registry content:
REPO TAGS
my-registry.local.lan/test/busybox 1-glibc
Local dir to registry pipeline? Ate. π₯
π Synchronizing to a local directory, scoped π
$ skopeo sync --src docker --dest dir --scoped registry.example.com/busybox /media/usb
Images are located at:
/media/usb/registry.example.com/busybox:1-glibc
/media/usb/registry.example.com/busybox:1-musl
/media/usb/registry.example.com/busybox:1-ubuntu
...
/media/usb/registry.example.com/busybox:latest
Scoped means the registry hostname is right there in the path, so your filesystem knows exactly where these babies came from π«Ά.
π Synchronizing to a container registry π
$ skopeo sync --src docker --dest docker registry.example.com/busybox my-registry.local.lan
Destination registry content:
REPO TAGS
registry.local.lan/busybox 1-glibc, 1-musl, 1-ubuntu, ..., latest
Keep the REPO and TAGS exactly as shown, bestie β this is the vibe check and the fact check at the same time β¨.
π Synchronizing to a container registry keeping the repository π
$ skopeo sync --src docker --dest docker registry.example.com/repo/busybox my-registry.local.lan/repo
Destination registry content:
REPO TAGS
registry.local.lan/repo/busybox 1-glibc, 1-musl, 1-ubuntu, ..., latest
The repo path stays the repo path: repo/busybox does not lose its main character energy. π
π Synchronizing to a container registry with tag suffix π
$ skopeo sync --src docker --dest docker --append-suffix '-mirror' registry.example.com/busybox my-registry.local.lan
Destination registry content:
REPO TAGS
registry.local.lan/busybox 1-glibc-mirror, 1-musl-mirror, 1-ubuntu-mirror, ..., latest-mirror
Suffixes go brrr π β every tag gets -mirror appended, exactly like it says.
π YAML file content (used source for --src yaml) π
Okay this is the big YAML moment π§. Hereβs the content, verbatim:
registry.example.com:
images:
busybox: []
redis:
- "1.0"
- "2.0"
- "sha256:0000000000000000000000000000000011111111111111111111111111111111"
images-by-tag-regex:
nginx: ^1\.13\.[12]-alpine-perl$
images-by-semver:
alpine: ">= 3.12.0"
credentials:
username: john
password: this is a secret
tls-verify: true
cert-dir: /home/john/certs
quay.io:
tls-verify: false
images:
coreos/etcd:
- latest
If the yaml filename is sync.yml, sync run:
$ skopeo sync --src yaml --dest docker sync.yml my-registry.local.lan/repo/
This will copy the following images:
- Repository
registry.example.com/busybox: all images, as no tags are specified. - Repository
registry.example.com/redis: images tagged"1.0"and"2.0"along with image with digest"sha256:0000000000000000000000000000000011111111111111111111111111111111". - Repository
registry.example.com/nginx: images tagged"1.13.1-alpine-perl"and"1.13.2-alpine-perl". - Repository
quay.io/coreos/etcd: images tagged"latest". - Repository
registry.example.com/alpine: all images with tags match the semantic version constraint">= 3.12.0"("3.12.0, "3.12.1", ... ,"4.0.0", ...)
The full list of possible semantic version comparisons can be found in the upstream libraryβs documentation: https://github.com/Masterminds/semver/tree/v3.2.0#basic-comparisons.
Version ordering and precedence is understood as defined here: https://semver.org/#spec-item-11.
For the registry registry.example.com, the "john"/"this is a secret" credentials are used, with server TLS certificates located at /home/john/certs.
TLS verification is normally enabled, and it can be disabled setting tls-verify to false. In the above example, TLS verification is enabled for registry.example.com, while it is disabled for quay.io.
π SEE ALSO π
Go read these too, bestie β theyβre all part of the same Unix friend group π«Ά:
skopeo(1)skopeo-login(1)docker-login(1)containers-auth.json(5)containers-policy.json(5)containers-transports(5)
π AUTHORS π
- Flavio Castelli
fcastelli@suse.comβ¨mailto:fcastelli@suse.comβ© - Marco Vedovati
mvedovati@suse.comβ¨mailto:mvedovati@suse.comβ©
xoxo, your Unix bestie π
β this pageβs footer source/version is skopeo-sync(1)(), and the date is right there in the footer, periodt π«Ά.
π¦ where this page comes from
- arch rolling: skopeo 1.24.1-1 Β· Apache-2.0
- nixpkgs unstable: skopeo 1.24.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms