Use image-syncer to migrate container images
Migrating container images with docker pull and docker push is impractical at scale — it requires storing images on disk, depends on a Docker daemon that limits concurrency, and fails frequently on large repositories. image-syncer eliminates these constraints by streaming image blobs directly from source to destination over the network, without writing to disk. Use it to migrate hundreds of repositories or TB-level data to Alibaba Cloud Container Registry (ACR) when moving workloads to Container Service for Kubernetes (ACK).
How it works
image-syncer transfers image blobs directly over the network using memory only — it does not write images to disk. This makes it suitable for large-scale migrations, including repositories larger than 3 TB.
Each sync job:
-
Reads authentication and sync rules from a configuration file.
-
Pulls image blobs from the source registry.
-
Pushes blobs to the destination registry without writing to disk.
-
Records synced blobs so that subsequent runs skip already-synced images (incremental synchronization).
-
Automatically retries failed tasks to handle transient network errors.
image-syncer supports any registry based on Docker Registry V2, including ACR, Docker Hub, Quay.io, and Harbor. It does not require a Docker daemon.
Prerequisites
Before you begin, make sure that:
-
The server running image-syncer has network access to both the source and destination registries.
-
You have credentials (username and password) for each registry, or those registries allow anonymous access.
-
The server has enough memory for your concurrent sync workload. Memory usage is at most:
concurrent images × size of largest image layer.
Configure image-syncer
image-syncer reads from a single JSON configuration file with two top-level fields: auth and images.
{
"auth": {
"quay.io": {
"username": "<your-username>",
"password": "<your-password>",
"insecure": true
},
"registry.cn-beijing.aliyuncs.com": {
"username": "<your-username>",
"password": "<your-password>"
},
"registry.hub.docker.com": {
"username": "<your-username>",
"password": "<your-password>"
}
},
"images": {
"quay.io/coreos/kube-rbac-proxy": "registry.cn-beijing.aliyuncs.com/<namespace>/kube-rbac-proxy",
"registry.hub.docker.com/<namespace>/myapp:v1.0,v1.1": "registry.cn-beijing.aliyuncs.com/<namespace>/myapp"
}
}
Replace the placeholders with your actual values:
| Placeholder | Description |
|---|---|
<your-username> |
Username for the registry |
<your-password> |
Password for the registry |
<namespace> |
Namespace in the destination registry |
auth field
Each entry in auth maps a registry URL to its credentials. If no entry exists for a registry, image-syncer accesses it in anonymous mode.
| Field | Required | Default | Description |
|---|---|---|---|
username |
No | — | Username for the registry |
password |
No | — | Password for the registry |
insecure |
No | false |
Set to true to access the registry over HTTP. Requires image-syncer v1.0.1 or later. |
The registry URL inauthmust exactly match the registry portion of the image URLs inimages.
images field
Each entry in images is a sync rule: the key is the source image URL and the value is the destination image URL. Both URLs use the format registry/namespace/repository:tag.
Sync rules
| Source URL | Destination URL | Behavior |
|---|---|---|
registry/ns/repo (no tag) |
registry/ns/repo |
Syncs all tags; destination keeps original tags |
registry/ns/repo:tag |
registry/ns/repo |
Syncs the specified tag; destination keeps original tag |
registry/ns/repo:tag |
registry/ns/repo:newtag |
Syncs the specified tag and renames it at the destination |
registry/ns/repo:tag1,tag2,tag3 |
registry/ns/repo |
Syncs multiple tags; destination URL cannot contain a tag |
registry/ns/repo |
"" (empty string) |
Syncs to a same-name repository in the default namespace of the default registry |
Each sync rule applies to one repository only. To sync an entire namespace, add a separate rule for each repository.
Limitations
-
Each sync rule applies to one repository. Syncing an entire namespace or registry requires a rule per repository.
-
The source URL cannot be empty.
-
When the source URL contains multiple comma-separated tags, the destination URL cannot include a tag.
-
When the source URL has no tag, the destination URL cannot include a tag.
-
Memory usage scales with concurrent image count and the largest image layer size. Reduce the number of concurrent workers if the server runs low on memory.
-
The
insecureparameter (HTTP access) requires image-syncer v1.0.1 or later.