Repository navigation
Conversation
Signed-off-by: chlins <chlins.zhang@gmail.com>
|
Something I don't see called out in this proposal is secrets management. Some models require the acceptance of a EULA and today their access is gated behind a users token that has accepted the EULA. Is there any effort to support these models in this proposal? |
|
Will this proposal make any attempt to differentiate model artifacts from container artifacts in a repository? A confused developer may try and pull one of these converted models expecting an engine to be packaged with it like a NVIDIA NIM and will experience a failure. |
elliott-davis
left a comment
There was a problem hiding this comment.
Overall this proposal aligns with what I would like to accomplish for model syncing in Harbor.
@elliott-davis Good question. Gated models are covered by the existing token mechanism rather than a new secrets subsystem: the user completes the EULA or license acceptance on the hub side with their own account beforehand, and the access token configured in Harbor's registry management (encrypted at rest) carries that entitlement. From Harbor's perspective this is plain token authentication when fetching; it implements no hub-specific consent flow. I've updated the Security Considerations section to make this explicit. |
@elliott-davis Yes. Converted models are model-spec OCI artifacts with their own artifactType and media types, so Harbor's UI can distinguish them from container images and will render them with a distinct icon, the same way charts, SBOMs, and signatures are differentiated today. On the pull path, however, both go through the standard Distribution v2 API, and the server should not intercept or reject pulls based on artifact type. So the safeguard is discoverability (distinct type and icon in the UI, plus the model-spec media types for tooling to inspect), not server-side gating; whether an artifact is runnable is up to the consuming tooling. |
Signed-off-by: chlins <chlins.zhang@gmail.com>
ebc6bbb to
bf76ea7
Compare
|
I don't think the claim that registry adapter won't work holds true, given the determinism the proposal already guarantees (Goal 4). If the packer turns a given revision plus file filters into a byte-identical manifest, the adapter isn't faking registry semantics. It derives them. The same packer could sit behind |
|
I think we still should strive for making it work with adapters, I think it will not only be easier to implement and maintain, but also for users to adapt and understand. The whole ecosystem in build around that too. cli, pulumi, tf proviers and all the scriptiin people has been made over the years. IMO it is worth reusing that. The adapter has policies, cron, executions, bandwidth limits, chunked resume and quota from replication, and pull-through from proxy cache via Now it is only Hugging Face what if other model source become availible and needed replication too and the same capabilities? It is not worth it, there no additional benifits in doing so. |
|
One good example where we failed to do it right in the first place, are the P2P preheat functionality. Harbor has 100lk deployments, theon only reported problem and users of this feature is the company who have made the PR. We never reecieve feature reqeuests, issues regarding that feature excapt from the original authors. and if it breaks it goes unnotices, until the origial team is migrating harbot to new version and notice that error. I don't want to repeat that again. |
|
To compare the two designs on running code, I opened a draft that takes the replication/proxy route: goharbor/harbor#24008. It adds a The adapter builds the manifest from the Hub API for a pinned commit, and the output is deterministic. One raw layer per file; LFS sha256 is the layer digest; non-LFS files are hashed and checked against their git blob id. The same commit always gives the same digest, so replication's digest comparison handles idempotence and no revision cursor is needed. Results on a dev Harbor with
Some points in this proposal hold up, and the PR says where:
Each can be added as a generic replication/registry extension that other adapters also benefit from, so none of them needs a parallel framework. The PR description lists the compromises I made and the Hub quirks that affect both designs, for example the anonymous 401 for missing models, case-sensitive Happy to fold anything from this proposal into that PR, or to work on it together with @chlins and @elliott-davis.
|
| - The `ArtifactRegistry` contract is manifest- and digest-addressed end to end (`PullManifest`, `PullBlob(repository, digest)`, `MountBlob`, ...). Model hubs have neither manifests nor universally digest-addressed content, so an adapter must fabricate registry semantics it cannot honor. | ||
| - Replication's idempotence compares source and destination digests of the *same* artifact. Model sync is a *conversion*: the source has no OCI digest, so the core skip/override semantics do not apply. | ||
| - An earlier proof-of-concept integrating Hugging Face through the replication adapter interface ran into these impedance mismatches directly ([KubeCon session](https://www.youtube.com/watch?v=0eiXSogHxmQ)). | ||
| - Harbor has removed a non-OCI upstream adapter before (ArtifactHub, together with the chartmuseum backend), which is a signal about the long-term cost of pretending non-OCI sources are registries. |
There was a problem hiding this comment.
The main reasons the ArtifactHub adapter was removed were its low-quality, buggy implementation and the upcoming OCI support.
There was a problem hiding this comment.
Fair point, I checked and it went out together with the chartmuseum backend in goharbor/harbor#18191, so it doesn't really say much about non-OCI sources. I'll drop that bullet.
|
|
||
| **2. Extending the OCI replication adapters.** Attractive on the surface: replication already has adapters, policies, filters, and triggers. It was rejected on evidence: | ||
|
|
||
| - The `ArtifactRegistry` contract is manifest- and digest-addressed end to end (`PullManifest`, `PullBlob(repository, digest)`, `MountBlob`, ...). Model hubs have neither manifests nor universally digest-addressed content, so an adapter must fabricate registry semantics it cannot honor. |
There was a problem hiding this comment.
https://github.com/llmmanorg/llmman is a good reference. llmman transfer hf.co/... builds a model-spec manifest straight from HF and streams it into the push without touching local disk.
There was a problem hiding this comment.
Thanks, didn't know about llmman. Streaming straight from HF is what we had in mind too, so this makes the PoC argument kind of outdated. I'll update that part.
|
Thanks for putting goharbor/harbor#24008 together, having running code to compare against is really helpful. Let me sync with @wy65701436 on the direction first, will come back here by next week. |
|
Thanks @Vad1mo and @chlins for putting together — having running code on both sides makes this a much better discussion. I’ve gone through both, Where I agree with:
Where I still think “separate” is right — but narrower than the proposal says
Proposed middle ground:
Does this split work for you? If there’s a reason the policy layer also has to be replication, I’d like to hear it, because that’s the one place I’m still choosing “separate”. |
|
One more structural point. Replication is symmetric by design: a policy has a src_registry and a dest_registry, either side can be the local Harbor, and the same adapter serves as source or target — Harbor-to-Harbor DR and multi-site is the whole reason it exists. Model Sync is strictly one-way: the source is always an external hub, the destination is always this Harbor, and there is no push direction — you can’t sync an OCI artifact back into a Hugging Face repo. Modeling that as a replication rule means a source-only capability flag, a UI that hides the type in the destination picker, a form full of greyed-out push/pull and namespace options, and an adapter where half the interface is MethodNotAllowed stubs. A dedicated Model Sync policy simply doesn’t have those fields: source → model → revision → destination repo. And the two features chain rather than overlap: Model Sync gets the model in, replication moves it between Harbors afterwards — exactly as it does for any other artifact. |
Do I understand your idea correctly here. you want to reuse the existing Harbor replication/proxy logic but provide new user facing interfaces/apis for model? |
|
Yes, that's it. Reuse what's common underneath: the adapter and deterministic packer, the transfer code (chunked copy, bandwidth limit, retry, quota), and the execution/task tables and job. Those which could be shared libraries. What we want to keep separate is the user facing part: models as their own interface, with their own policy, API and UI. Pulling a model in is a different task for the user than mirroring a registry, and keeping it separate also gives Harbor a clear entry point for moving further towards an AI artifact registry later, without piling model specific things onto the replication policy. |
Ok, can you outline what would be the additional functionality on UI, API and what are the specific use cases/scenarios you think the user wants to perform. Based on that I can see and run a multiple experiments, so we can together see and compare the various options, that we think would fit best. |
|
Sure, will put together the use cases and the UI/API delta with @wy65701436. In the meantime there's a PoC environment running the proposal's Model Sync at http://172.237.79.67:8088/harbor/model-sync, probably the quickest way to get a feel for the user side before we compare on paper. |
Is the code to that also in public? |
@Vad1mo No, the code is currently on my local branch. For production, I recommend splitting it into multiple small PRs for review. |
|
Following up on #297 (comment). Instead of comparing on paper, I built both UI directions on the same backend and ran the same scenario through each. Shared backend, identical for both options: the
In both options a run is executed by the replication copy flow, transfer, job and execution/task tables. There is no second packer or transfer. Scenario: Option A: separate Model Sync, modelled on this proposal and the PoCAdministration > Model Sync with its own
Found while building it: one policy is one model (no A1: Model Sync entry in Administration
A2: Policy list
A3: Policy form with resolved preview (include *.json, exclude onnx/, .bin)*
A4: Executions
A5: Task list with log link
A6: Resulting model artifact. The raw descriptor JSON is today's artifact view; the Model panel in Option B is independent of the import path and would work here too
A7: Rerun skipped with the same digest
Option B follows in the next comment. |
Option B: extend Registries, Replication and the artifact viewSame backend and scenario as Option A above. No new policy, table or API besides
The artifact view gets a Model panel for any CNAI artifact (licenses, source, source revision) instead of the raw descriptor JSON. The endpoint form uses the adapter's credential pattern, so Hugging Face only asks for a token.
Bandwidth limit, chunked copy, override, B1: Hugging Face endpoint, token only
B2: Rule form with Hugging Face source: Model, Revision, Files
B3: Preview inside the rule form
B4: Rule form with Docker Hub source, unchanged
B5: Executions succeeded
B6: Model artifact with the Model panel
Where this leaves the comparison: both options deliver the same preview, file filters, revision tags and license display, because those are backend capabilities. The difference is a dedicated entry point and wording (A) against roughly a quarter of the code and no second policy model (B). @chlins @wy65701436 which of your use cases can't be done with Option B? That is what I'd like to understand before we decide. Both branches are ready to push if you want to run them. |
|
Option B seems more simple would be easier to maintain. |















This pull request introduces a comprehensive proposal for a new Model Sync Adapter Framework in Harbor, aimed at enabling seamless synchronization of AI models from upstream model hubs (starting with Hugging Face) into Harbor as OCI artifacts. The framework is designed to be extensible, policy-driven, and deterministic, while reusing Harbor's proven architectural patterns without modifying the existing OCI replication system.
The most important changes are:
Framework Design and Architecture
fetch → convert → pushpipeline.Adapter Contract and Extensibility
resolve+stream) to make adding new model sources straightforward and maintainable, with Hugging Face as the reference implementation.Deterministic Packaging and Provenance
API, Data Model, and UI Integration