-
Notifications
You must be signed in to change notification settings - Fork 265
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
Feature installation order #43
Comments
@chrmarti I think we'll still need some way to allow users to specify explicit ordering in the feature object in devcontainer.json. Not every feature will know about all other features even long term - and there's other reasons below. Right now this is impossible, which has been problematic for early adopters. One way to do that could be to allow "installAfter" to also be explicitly mentioned by users in the object syntax in devcontainer.json as well. e.g.
This would enable similar ordering to an array with a slight variation on syntax for those that value predictability. Otherwise, I think we'd likely need an array with a mode that allows you to opt into implicit vs explicit ordering, but I don't think we'd want the array syntax to be temporary if that's the direction we go. To recap, explicit ordering allows end users to:
|
I believe we should provide some supported (permanent) mechanism for allowing an end-user to control feature installation. I think it is preferable that a user does not need to concern themselves with install order, but as a "break glass" solution it should be intuitive how to order when the need arises. Our "first party" features are written in such a way that most installation orders will work (no errors), although in some situations there is a preferred order. Most of the time the preferred order will eliminate the need for a "soft dependency" for a given feature to be installed twice. We try to optimize our scripts to re-use existing tools if present already in the container, but that isn't going to always be trivial to account for. Today we force our preferred order, regardless of any order specified from the user. We can do this since we have full control over the ecosystem at the moment (aside from a few adventurous preview users). That ordering is declared from this file. When we factor in community ("third party") feature contributions, we now have significantly less control over how the features are implemented. Additionally, we currently don't have a proposal for a centralized "repository" of features, instead opting for a more "Self-hosted" model. We don't plan to strictly moderate the implementation of features, and thus authors are allowed flexibility in authorship. We are pushing a lot of added responsibility onto community authors to "get it right". Many times features will install fine without a specified order, but in the instances where there is an obvious ordering problem that our tooling did not properly infer, I believe the most useful solution we can provide to users for that problem is allowing a specified order.
I agree. One solution to this is the array notation (proposed here). I believe our tooling can (and should) implement some "ordering logic" that helps prevent a user from hitting obvious/identifiable error, but as a final solution a user should be given the tools to solve a problem themselves that could result from ordering. I especially like @Chuxel 's point (2), where users may want to prototype a feature locally or perform a simple extension of already installed features. The implementation of container features today is inherently ordered due to the programatic injection of Dockerfile |
The argumentation seems to have two sides
If this observation is correct, it seems to me that the syntax should explicitly express both of those aspects. I.e. the syntax should not suggest to me that by default I do have to worry about the sequence and when I look at a devcontainer file it should immediately be clear to me that it defines order to clean up a messy situation. Thus, it would make sense to me that
|
A separate On reproducible image builds: We will compute a fixed order based on the soft-dependencies (using a stable sorting where soft-dependencies do not require an order). We will also need a lockfile to make the build reproducible over time as feature scripts update. On local feature scripts: We can install features that do not participate in the soft-dependencies graph last. They will not participate either on purpose or by accident, running them last should work in both cases. A local feature can then still choose to participate in the soft-dependencies. |
My main worry with |
@kieferrm 100%. I was thinking of a property inline in the object syntax - but something like an override property would work as well. Strict ordering should not be the default, but possible to do. I'd talked with @craiglpeters yesterday on the Codespaces team and we both were leaning towards the object semantic as the default with an override form for the reasons you mention.
@chrmarti I'm pretty confident that if people find out that they need to use this property frequently that we'll get feedback on something being wrong. The idea really is that you shouldn't have to do this. The core challenge is that, unlike a classic package or module system, we only have complete control of the "packaging" aspect of the overall process. How the installation itself affects other things is dictated by things like apt, npm, pip, nix, etc. So that inherently puts us in a spot where predictability is difficult. However, I strongly believe we should look for ways to avoid these problems as well, so agree with that point. I also agree with your thought that we should probably consider a way to make user creation something that can be done independent of features since its placement has a dramatic affect on ordering right now.
Yeah the specific issue is when you add one more thing, that can end up in a (to the user) random spot in the ordering and affect things in ways we cannot predict. In primary cases, that won't be a problem, but we'll need a way to handle exceptions. We've seen enough already at this early stage that having some mechanism will help a lot.
This is a good idea - I like it! The one thing it does not solve is where you need that to happen between two features as a fix, but with an override, this should reduce the number of incidents significantly. Love that. |
I want to emphasize this point made by Chuck. We currently are NOT building a package manager (we have no centralized database of features, there is no lock file, we have no proposal for a strict versioning schema other than "what makes sense" to an author). We have also explored building on top of an existing package manager, but @edgonmsft 's investigations concluded it did not make sense given the specific case studies we investigated. We indeed have control over packaging via our provided GitHub action (https://github.com/microsoft/publish-dev-container-features-action, soon to be migrated over to the |
I just want to voice that I don't think (2) is necessarily a hard requirement, although that is certainly the way the discussion is heading. I think that our tooling should provide some sortof mechanism for detecting invalid orderings, but installing tools into a Docker image in inherently ordered and thus by us taking the ability to define an order away from a user, we're necessitating moving that complexity onto someone else (feature authors and ourselves as developers of the ordering algorithm).
Agreed, this makes the most sense in a completely opaque ordering model! Although - if a user wanted to then utilize several "local" features, we run into the exact same problem as if a user wanted to utilize several "remote" features. Perhaps the core take-away is that we don't have enough user feedback yet on how one wants to utilize and stretch the power we provide with features. |
@joshspicer I think this is representative of our aspiration. We have a checkbox UX right now with this in mind... pick your base, then add a few optional features and you are done. Practically speaking we've found it is more complicated than just that, but this is also not an absolute either. Anything that's a straight CLI you curl and drops in The core issue that tends to cause things like Go to need ordering is that it needs to set privs to enable a non-root user to access or install contents in folders it creates. Given how common that is, I could totally see us going down the path where In fact, we could pass that user name into the features, which would simplify logic we have now to figure out what that user is. (e.g. it's there as a DEV_CONTAINERS_REMOTE_USER env var). This is not really practical with the script form where many of these scripts started, but with dedicated features, it would work really well and also simplify authoring. |
I was thinking that a local feature could also use the "installAfter" property to get in control of the order. We just order features without any dependencies or dependents last to increase the chances of success for features that are unaware of their dependencies (and need to be fixed). |
I want to publicly share an example proposal of @Chuxel 's shared in a different medium.
This idea of "modes" This seems like a nice compromise. The "magic" dependency detection exploration can continue, while users today are not blocked from using features in a way that works for them. I expect that users in "auto" mode will have their devcontainers break as the team continues to iterate on automatic feature re-ordering. These "modes" will provide a way for users to unblock themselves and continue to stay in our ecosystem. The alternative would be to leave features altogether in favor of manually writing their Dockerfile. |
I have put together a PR demonstrating an implementation of the proposal: devcontainers/cli#56 |
Makes sense! In isolation all the local features could then be completely controlled. |
Another thing is that going with a map syntax doesn't allow features to be called multiple times, and for the cases where that makes sense then features and their parameters need to be more complicated. |
@edgonmsft This does not bother me - features have to be specifically designed to be invoked twice anyway, so supporting a list of things to install really isn't that difficult. It does imply though that we should support an So recapping where we here:
|
We have two pending changes in this proposal: 1. The top-level 2. The implicit behavior that "local features" are automatically re-ordered and applied after all "remotely acquired" features. In addition to (1) and (2), I propose a third (3) optional, "break-glass" top-level setting: The property is an These features will be applied to the underlying Dockerfile for installation in the specified order. Any features in the NOTE: In this example, NOTE: "local features" are features referenced from the local filesystem. They are part of the spec and are currently (as of Jun 17 2022) in PR to be added to the reference implementation. Example{
"image": "azcr.io/joshspicer/my-debian",
"features": {
"person/features/cool-azure-cli-extension": "",
"docker-in-docker": {
"version": "20.01"
},
"devcontainers/features/azure-cli": {
"version": "latest"
},
"/home/alice/localFeatures/setupDev": {
"doComplicatedStep": true
},
"/home/alice/localFeatures/setupProxy": {
"ipAddress": "127.0.0.1"
},
"homebrew": {
"version": "latest"
},
"acmecorp/features/proprietaryCode": {
"optionA": true,
"optionB": false
},
"common": {
"userUID": "1000"
}
},
"featureInstallOrder": [
"/home/alice/localFeatures/setupProxy",
"common",
"devcontainers/features/azure-cli",
"person/features/cool-azure-cli-extension"
]
} Thus the resulting Dockerfile will have
The three buckets above are:
If no |
I like this proposal for |
@craiglpeters - We have many use-cases today that have arisen from using features in our own base images. I've also provided 5 generalized example use cases in my first EDIT: I also want to point out my previous comment, where I highlight that today, all of our first party features follow a strict installation order that cannot be modified by the user. This is to protect the user from doing something invalid. My stance is that it will be exceeding difficult to always auto-determine the correct order, and thus as a "bailout"/"break glass" solution we must provide users the tools to do so. When users dabble in our preview functionality of self-authoring features, "mixing" self-authored and our first party set of features may result in inconsistent behavior as the automatic ordering is iterated on. |
Noted! Scroll-back is my friend |
In addition to this, we also identified four things to split out as separate proposals/discussions: High confidence proposals:
Warrants further discussion:
|
For completeness -- an alternative approach to my proposal above is around providing metadata "hints" in the feature options. These "hints" would start with a leading This proposal is inspired by configuring firewall rules on something like an Azure NSG. NOTE: My proposal above is most likely a better fit for the specification, but I leave the idea here open for possible discussion. Eg: {
"image": "azcr.io/joshspicer/my-crazy-complicated-docker-image",
"features": {
"person/features/cool-azure-cli-extension": {
"_installPriority": 105
},
"docker-in-docker": {
"version": "20.01"
},
"devcontainers/features/azure-cli": {
"_installPriority": 100
},
},
"overrideFeatureInstallationMode": "manual" // (manual|auto) Default: auto
} When in For all remaining features, or if we are in the default For this example, the build order would be:
|
I'm missing a way to ensure we or the feature author will learn about users having to use Possible ways of improving this feedback loop:
|
@chrmarti I don't think we should drop But, we can also do outreach to verify once we've got more people using it to understand why they are using the property - if they do. For feature authors, I'd be surprised if people did not complain given the use of the property means that default behaviors wouldn't work - and enough people will not read docs that they'll raise issues on it. |
|
Sounds good to me. |
Yep I like the name. |
As we are preparing to open up features to community contributions, we found that some features need to install after other features. This issue proposes to add support for soft-dependencies to arrive at a reproducible ordering following these ordering requirements:
A feature can declare a list of other features that should be installed first if they are configured to be installed. (The soft-dependency itself does not add another feature to the list of features to be installed.)
E.g., the NodeJS feature would list the Python feature because it has to install a system version of Python if no version of Python is already installed:
Features that an install in any order will be installed in a fixed order (e.g., ordered by id) to ensure the result is always the same.
The "features" map in the devcontainer.json will remain a map. See https://github.com/devcontainers/spec/pull/27/files#r869018039 for a discussion.
To allow for progress on user contributable features, we can use a stop-gap measure like an ordered list of features that depend on a specific installation order and either bake that into the CLI at build time or fetch it at runtime. This list will be temporary and documented as such.
/cc @Chuxel @jkeech @edgonmsft @joshspicer @bamurtaugh @alexdima
The text was updated successfully, but these errors were encountered: