-
Notifications
You must be signed in to change notification settings - Fork 206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
garbage-collection clarification needed #406
Comments
Calling them rules implies there's a spec or policy that applies to every registry. We've avoided defining anything in the OCI spec, possibly to an extreme, and delegated that to each implementation. There are lots of policies and various implementations, each doing this differently. Several examples include:
Most registries will not delete a blob if a manifest references that blob. Tags are a common way to indicate a manifest should not be removed by GC. If we want to begin defining expected GC policies, it may be best to create a new working group to review the various implementations and identify what, if anything, we can define in a spec. |
The way I see these rules is that they specify when a registry GC implementation MAY release an object, not whether it MUST, or even SHOULD. To my mind that's the most important aspect: if there are no rules, then there's no assurance that a given object won't be deleted underfoot by some rogue GC implementation that's nonetheless operating according to the underspecified rules currently in play. Maybe that's OK, but ISTM that everyone in practice depends on the rule that (for example) a manifest and the blobs it refers to won't be deleted as long as there's a tag that refers to the manifest. Another thing, and not strictly GC-related: is there anywhere that specifies that the namespace for digests within a repository is restricted to that repository. That is, it's (at least on some registries!) necessary to push a given blob to a repository even though we know that it's already part of some other repository in the same registry. Or is that another thing thar's implementation-defined? This behaviour was certainly a surprise to me when I wrote my initial PoC code, even though it makes total sense in retrospect. |
I attempted to clarify that references are specific to a repository, rather than anything in a registry, but that hasn't been merged and I'm not sure what will unblock it. |
I guess my main question is, as someone would like to write client code that stores artifacts in an implementation-agnostic fashion, do the rules I've stated actually correspond correctly to the de-facto rules understood and implemented by most registries? Are there any notable exceptions that behave differently? |
Typically, registries will keep manifests that are tagged and child objects of those manifests, recursively (manifests listed in an index, and blobs listed in an image). Exceptions I can think of include:
The subject/referrers API will also impact this. Ideally as long as the subject manifest exists, the referrer to that manifest (the one with the subject field) would not be subject to GC. |
Hi @rogpeppe, The details are all about how the registry implements ref counting on the de-duped objects. I'm looking if the distribution spec defines lifecycle management, but I'm not finding it, yet. @sudo-bmitch, has this been queued up? |
One thing that my rules don't make clear (and that I'm not clear on myself tbh), is whether it's possible that an object pushed to the |
Manifests are uploaded through the manifest api. They just happen to be persisted as blobs, also as a detail. |
I don't think
is necessarily true.
makes me think that a client may be able to copy a manifest list but only the manifest it knows a priori that will be used. This would make it possible to mirror content to a cluster-local registry without breaking a signing scheme, for example. |
Good point, @hdonnay Manifest lists are their own beast, and not consistent across implementations. There’s also some interesting interpretations that have evolved for putting blobs in a “manifestList”, which would be interesting to see what registry implementations have done when the manifest list is deleted. Would the blobs get deleted? |
Another thing that's not entirely clear to me: is it OK for a manifest to contain a reference to another manifest from the same repository as one of its layers/blobs? |
There was some attempts at defining a collection of descriptions, but it was felt too complex to track lifecycle:
Here’s a more explorative attempt; @rogpeppe, what are you looking to achieve? That might help prompt some ideas to guide a path |
Ideally I'd like it to be the case that when someone like me comes to the OCI project for the first time, they have enough information that they can meaningfully use the API, understanding the basic data model, what guarantees it provides, and what it doesn't. Without that, it seems hard to me to be able to write client code that meaningfully works correctly across different registry implementations, or a registry implementation that fulfils client expectations. If there are particular aspects that vary across different registries (like, for example, if there's a registry that doesn't understand about references at all and removes blobs regardless, which would be within the letter of the spec AIUI, if not the spirit), then perhaps some page could provide a matrix of features vs implementations to give some idea to readers of what's "normal". For myself, I don't need anything at this point, because by writing experimental code and running it on a couple of different implementations, I think I have a grasp of the generally understood rules. But I may well be wrong, because I haven't tried all implementations, and I'm sure there are some outliers there. As an example of a point where the current state of affairs seems to become problematic to me, from @sudo-bmitch:
This sounds to me like there's at least one registry out there that will delete a blob even when there's a manifest that references it. Doesn't that break every expectation that people might have of a registry? I upload my docker image, tag it, and suddenly I can't use it because the registry has decided to remove one of the layers it references. I understand that the spec needs to reflect actual current implementation behaviour, but SHOULD and MAY are available, and I am totally the naive outsider here, but isn't it possible to set some expectations in the spec in this respect, at least? |
@rogpeppe have you had a chance to look at https://ttl.sh/. I'd also recommend looking at the following issue: distribution/distribution#3178 |
A blob could reference another blob, or anything, but it's typically opaque data to the registry (exceptions include parsing the image config for a UI, and scanning layer content for vulnerability reports). Registries should only look at manifest content when they implement their GC policy. I suspect there would be a lot of push back if OCI defined blob content that changed that assumption. |
Yes, there's an effort to explicitly support a "sparse manifest" where someone would only mirror the platforms they intend to run in their cluster (copy the entire manifest list byte for byte, but only copy the linux/amd64 and linux/arm64 child images if you don't have mainframes in your environment). And registries that enforce consistency on a manifest list will typically allow you to delete one of those child manifests after the manifest list has been pushed. |
Both interesting reads, thanks! (I will probably use ttl.sh now that I know about it). FWIW the former seems like it could still observe the spirit of things by ensuring that a manifest with a longer TTL can keep a blob with a shorter TTL live. Deleting tags is always possible, and ISTM that all ttl.sh is doing is deleting tags after some time period, not necessarily violating the reference constraints. The latter seems more like a tooling bug to me, although I probably don't properly understand the issue after scanning it briefly. Shouldn't
That's an interesting use case. I guess one way of doing that while abiding by the suggested rules would be to push a manifest that points to the original manifest as a blob, and maintains links to the required remaining blobs directly. That way any referrers to the original manifest would be maintained but the GC would be free to drop the unwanted content.
Is that "should" anywhere in the spec currently? :) |
Yes, it is a bug (or open issue) that's existed for over 3 years in the reference implementation of the registry. I think that still covers your question of whether any registries have a GC that would delete a blob when the manifest is still tagged.
If you're looking for guarantees, I'll reiterate that there are none from OCI. None of this is in the spec yet, so you'd need to check with individual implementations or make sure your code handles the errors. There are a lot of ways even outside of GC that content can get into an inconsistent state. And even if changes were made to the spec (see the working group process) there are quite a few major registries not listed in the OCI conformance page. |
As a newcomer to OCI registries, looking through the docs, I wasn't able to easily find out how the overall referential data model works. For example, until I discovered otherwise, I assumed that a manifest in one repository would be able to directly reference a blob that was uploaded to another repository within the same registry. Likewise, I haven't found a place that explicitly defines when a blob might be deleted by the garbage collector.
I came up with the following form of words to try to explain my understanding of the rules as I've come to understand them over the last few days. Does this accurately describe the intended semantics? Perhaps the spec could contain something like this.
GC rules for OCI registries
A registry holds a set of repositories. Each repository in a registry is logically separate from all other repositories, although actual content MAY be shared between them.
A repository holds a set of objects that it retains references to. When an object is no longer needed by a repository, it is released, which MAY remove the underlying data if it's not referred to by any other repository.
The object of garbage collection is to release any objects that aren't needed by the repository. After garbage collection, all objects not marked as live are released.
When a manifest or tag is created, any objects that it references MUST be live.
There are three categories of object: a manifest, a manifest list, and a blob. Blobs are data-only: they do not hold references to other objects.
The set of live objects is defined as follows:
All live objects MUST be retained by the repository and not deleted.
See also #378
The text was updated successfully, but these errors were encountered: