Skip to content

Conversation

@raphaelzoellner
Copy link
Contributor

@raphaelzoellner raphaelzoellner commented Nov 5, 2024

Comprehensive Summary of your change

Harbor Proxies will push a manifest referencing a digest and tag to the local repo if both are known.

Issue being fixed

Fixes #21122

Please indicate you've done the following:

  • Well Written Title and Summary of the PR
  • Label the PR as needed. "release-note/ignore-for-release, release-note/new-feature, release-note/update, release-note/enhancement, release-note/community, release-note/breaking-change, release-note/docs, release-note/infra, release-note/deprecation"
  • Accepted the DCO. Commits without the DCO will delay acceptance.
  • Made sure tests are passing and test coverage is added if needed.
  • Considered the docs impact and opened a new docs issue or PR with docs changes if needed in website repository.

@stonezdj
Copy link
Contributor

Thanks for your contribution! because the current code change doesn't fix the issue #21122, and might result in regression issue, so we will close this PR.

@stonezdj stonezdj closed this Nov 11, 2024
@raphaelzoellner
Copy link
Contributor Author

Hello @stonezdj,

could you give a hint why this code change (creating the manifest referenced by the tag) wouldn't solve or at least improve the described behavior in #21122, so one can think about another solution?

Is this maybe a misunderstanding with the PR #21123, which is already closed?

}
}

func (m *ManifestCache) push(art lib.ArtifactInfo, man distribution.Manifest) error {
Copy link
Contributor

@stonezdj stonezdj Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have replace the m.local.PushManifest(art.Repository, getReference(art), man) with the m.push(art, man),
the intention of this method is push the manifest to the proxy cache project if there is any tag exist in the art, current the art is parsing from the pull request, for a normal image pull request, it is pulled either by digest or by tag. it can't be both.
The previous getReference(art) will return tag if it pull by tag, and return digest if it is pull by digest.
Current code change has no difference with the previous implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have replace the m.local.PushManifest(art.Repository, getReference(art), man) with the m.push(art, man)
Yes my intention is to push the manifest to the local proxy cache project with any reference known (tag, digest or both).

for a normal image pull request, it is pulled either by digest or by tag. it can't be both.
I agree the GET manifest request either uses a tag or digest as reference, but during the storage of the proxied manifest the digest might be looked up in the remote repository and the manifest is then only stored under the digest in the local proxy cache project.

The previous getReference(art) will return tag if it pull by tag, and return digest if it is pull by digest.
I think there are cases where art will contain both a digest and tag here. In this case the getReference(art) will favor digest over tag, ultimately leading to the manifest being stored in the local proxy cache project only under the digest.

This happens during the proxy controller's ProxyManifest call.

For a manifest pull referencing a tag the digest will be looked up in the remote repository.
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/controller.go#L224

Then the digest will be added to the copied artInfo which should until then contain the tag parsed from the the original pull by tag.
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/controller.go#L249

This artInfo containing both tag and digest will then be used in the original call to m.local.PushManifest(art.Repository, getReference(art), man), where getReference(art) leads to the digest being favored over the tag.
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/controller.go#L251C1-L251C69
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/controller.go#L318
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/manifestcache.go#L201
https://github.com/goharbor/harbor/blob/v2.10.2/src/controller/proxy/controller.go#L327-L330

My proposal is to push the manifest with both references (digest and tag) if both are known. This should lead to subsequent manifest pulls referencing the tag being served from the local proxy cache project if the digest has not changed to the remote manifest digest for said tag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @stonezdj,

are there any concerns left, or could I provide anything else?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @raphaelzoellner,
Can you please confirm for my own understanding that for subsequent artefact pulls referencing a tag, there is still a Manifest HEAD request to check the docker-content-digest or etag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @nasseredine ,

I think this should be achieved by the call to proxy controller's UseLocalManifest method in the repoproxy middleware here.
https://github.com/goharbor/harbor/blob/v2.13.0/src/server/middleware/repoproxy/proxy.go#L201

During a manifest get by tag request, art should contain only the tag at this point.
For a subsequent request, the artifact should already exist in the local proxy cache.
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/controller.go#L157

The existence of the manifest will then be checked on the remote registry via the clients ManifestExist method, that performs a HEAD request to lookup the digest among other things.
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/controller.go#L167
https://github.com/goharbor/harbor/blob/main/src/controller/proxy/remote.go#L105
https://github.com/goharbor/harbor/blob/v2.13.0/src/pkg/registry/client.go#L266

For manifests, the digest of the remote manifest is then compared to the digest of the artifact in the local cache to decide whether to serve from the local cache (digest matches) or not (digest doesn't match).
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/controller.go#L181
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/controller.go#L194

For manifest lists the digest is not compared and the manifest list is served without digest comparison.
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/controller.go#L202

But since the proposed changes only update the behavior of ManifestCache CacheContent
the https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/manifestcache.go#L177

and are not affecting ManifestListCache CacheContent
https://github.com/goharbor/harbor/blob/v2.13.0/src/controller/proxy/manifestcache.go#L66

I would assume the behavior for manifest list caches to remain the same.

Copy link

@nasseredine nasseredine Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your detailed explanation, @raphaelzoellner. The provided code references helped me understand the handling logic of proxy cache manifests.

@Vad1mo Vad1mo added the release-note/enhancement Label to mark PR to be added under release notes as enhancement label Dec 1, 2024
Copy link
Member

@Vad1mo Vad1mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve, that we need that functionality. I didn't try it out on the technical side yet.

@raphaelzoellner
Copy link
Contributor Author

Hi, is there any update on this?

@llCorvinSll
Copy link

Hi, It seems we are facing the same issue. (manifests are not cached and while upstream is not available, fetching fails)

@raphaelzoellner
Copy link
Contributor Author

Hi,
this PR has been opened for quite some time. Are there any concerns left or any additional steps necessary?

The proposed changes are blocked by 1 missing approval. Could one more Harbor maintainer review this?
@wy65701436
@AllForNothing
@MinerYang

@chris93111
Copy link

chris93111 commented Mar 24, 2025

Hi, It seems we are facing the same issue, there any update on this?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

@codecov
Copy link

codecov bot commented Apr 16, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 46.51%. Comparing base (c8c11b4) to head (78ae0f8).
Report is 470 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #21141      +/-   ##
==========================================
+ Coverage   45.36%   46.51%   +1.14%     
==========================================
  Files         244      253       +9     
  Lines       13333    14236     +903     
  Branches     2719     2925     +206     
==========================================
+ Hits         6049     6622     +573     
- Misses       6983     7264     +281     
- Partials      301      350      +49     
Flag Coverage Δ
unittests 46.51% <ø> (+1.14%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

see 178 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@stonezdj
Copy link
Contributor

@raphaelzoellner please rebase the code with main branch to merge the code

@raphaelzoellner raphaelzoellner force-pushed the 21122 branch 4 times, most recently from 9ae9fdc to 6637f44 Compare April 28, 2025 20:35
@stonezdj stonezdj enabled auto-merge (squash) April 30, 2025 05:54
Signed-off-by: Raphael Zöllner <raphael.zoellner@regiocom.com>
auto-merge was automatically disabled May 5, 2025 08:59

Head branch was pushed to by a user without write access

@raphaelzoellner
Copy link
Contributor Author

I think the github ci/cd workflow errors of the last run seem to be unrelated to the proposed changes.
I've rebased to see if the APITEST errors persist.

@stonezdj stonezdj enabled auto-merge (squash) May 7, 2025 08:45
@stonezdj stonezdj merged commit bc8653a into goharbor:main May 7, 2025
12 checks passed
wy65701436 pushed a commit to wy65701436/harbor that referenced this pull request May 16, 2025
…or#21141)

Signed-off-by: Raphael Zöllner <raphael.zoellner@regiocom.com>
OrlinVasilev pushed a commit to OrlinVasilev/harbor that referenced this pull request Oct 29, 2025
…or#21141)

Signed-off-by: Raphael Zöllner <raphael.zoellner@regiocom.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs/follow-up release-note/enhancement Label to mark PR to be added under release notes as enhancement target/2.14.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harbor Proxy should serve manifests from local repository if the remote manifest digest matches a local manifest

10 participants