-
Notifications
You must be signed in to change notification settings - Fork 178
Description
zot version
v2.1.13
Describe the bug
For example, when I use docker pull zot.mydomain.com/repo1/image1:latest to pull image1 from zot registry, the log at zot shows that it tries to sync image from external sources, even if /repo1/image1:latest locally exists.
│ {"time":"2026-01-21T02:50:05.611280445Z","level":"info","message":"trying to get updated image by syncing on demand","repository":"repo1/image1","referenc │
│ e":"latest","caller":"zotregistry.dev/zot/v2/pkg/api/routes.go:2182","func":"zotregistry.dev/zot/v2/pkg/api.getImageManifest","goroutine":3810} │
│ {"time":"2026-01-21T02:50:05.611345174Z","level":"debug","message":"starting on-demand image sync","repo":"repo1/image1","reference":"latest","serviceID": │
│ 0,"timeout":10800000000000,"caller":"zotregistry.dev/zot/v2/pkg/extensions/sync/on_demand.go:193","func":"zotregistry.dev/zot/v2/pkg/extensions/sync.(*Base │
│ OnDemand).syncImage","goroutine":3807} │
│ {"time":"2026-01-21T02:50:05.611387652Z","level":"info","message":"will not sync image, filtered out by content","remote":"registry-1.docker.io","repo":"de │
│ vops/k8sctl","reference":"latest","caller":"zotregistry.dev/zot/v2/pkg/extensions/sync/service.go:306","func":"zotregistry.dev/zot/v2/pkg/extensions/sync.( │
│ *BaseService).SyncImage","goroutine":3807} │
│ {"time":"2026-01-21T02:50:05.611425932Z","level":"error","message":"failed to sync image","error":"image is filtered out by sync config","repository":"devo │
│ ps/k8sctl","reference":"latest","caller":"zotregistry.dev/zot/v2/pkg/api/routes.go:2186","func":"zotregistry.dev/zot/v2/pkg/api.getImageManifest","goroutin │
│ e":3810}
The reason is that getImageManifest preferentially uses godigest to check if reference is of format sha256:xxxxxx. But in this case, it is actually latest. This will cause godigest to fail, and fallback to sync externally, if sync extension was enabled.
Lines 2172 to 2180 in 088914b
| _, digestErr := godigest.Parse(reference) | |
| if digestErr == nil { | |
| // if it's a digest then return local cached image, if not found and sync enabled, then try to sync | |
| content, digest, mediaType, err := imgStore.GetImageManifest(name, reference) | |
| if err == nil || !syncEnabled { | |
| return content, digest, mediaType, err | |
| } | |
| } | |
Currently, my workaround is to configure allow lists in sync extension via contents, so that to avoid local (also private) images to trigger sync. Then, as the logic goes on, it will fallbacks (again) to find the referenced image locally (which will success), as in:
Line 2191 in 088914b
| return imgStore.GetImageManifest(name, reference) |
In my use case, the workaround is not convience, because I want zot to be a proxy registry for all images that not exists locally (private). This can not be configured via contents since it only supports glob syntax, which is essentially a allowlist.
Moreover, when local images was triggered to sync externally, it will introduce non-negligible latency in docker pull (also kubelet pull) operation, even causes k8s ImagePullBackOff, when network condition to upstream registry was poor.
My thought on this issue is:
- Introduce some mechanism to exclude repos in sync extension, or,
- Find reference locally before triggers sync (i.e., not validate digest via godiest preferentially). If needed, a configuration can also be added for backward compatibility.
In conclude, my question is:
- Is this behavior by design?
- If there's any suggestion to improve the behavior, I can take time to draft a PR.
To reproduce
- Configuration
- Client tool used
- Seen error
Expected behavior
No response
Screenshots
No response
Additional context
No response