devcontainers / spec

Development Containers: Use a container as a full-featured development environment.
https://containers.dev
Creative Commons Attribution 4.0 International
3.38k stars 207 forks source link

[Features] Supported Architectures/OS #58

Open joshspicer opened 2 years ago

joshspicer commented 2 years ago

This proposal is an enhancement idea to the current dev container features proposal.


@edgonmsft @chrmarti @joshspicer @craiglpeters One other thought. I think at one point we'd discussed the idea that a feature could declare the operating systems and architectures it supports. Given the number of hiccups we've seen with arm64 installs with existing features and PRs like https://github.com/microsoft/vscode-dev-containers/pull/1513 (for Gentoo) driving things into different base OS distros, I think it may be a good idea to include this in the spec from the beginning.

We could have normalized architecture values and then support for /etc/os-release detection based on ID or ID_LIKE for distribution. We can also detect the version in a similar way. Most of the features have some code in them to detect and block based on these values. Moving it into the core spec just makes things easier for feature authors and we can provide UX hints if a feature isn't expected to work given the current environment.

e.g., something like this might work

"architectures": [ "x86_64", "arm64"],
"os": "linux",
"version": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine": true
}

...where "true" means any version.

Originally posted by @Chuxel in https://github.com/devcontainers/spec/issues/48#issuecomment-1170035230

chrmarti commented 2 years ago

Makes sense. "version" could be "distro"? And "os": "linux" can be omitted (at least for now).

Chuxel commented 2 years ago

Yeah that's reasonable - to make it clear this is OS stuff, we could do osVersion just to make it clear that's what the version is for. Agree that right now "linux" is implied, so probably no point in adding it until we need to.

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine": true
}

If no osVersion is specified, it's assumed that it works for everything.

eitsupi commented 1 year ago

This may be an uncommon case, but one of the Features I maintain runs on various architectures in Debian, but only on amd64 in Ubuntu. I know it is difficult to balance simplicity and fineness, but if such cases could be covered (or at least the Feature could be executed ignoring warnings), it would be better.

BusHero commented 1 year ago

"alpine": true is a little counterintuitive. Why not just alpine?

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine"
}
Chuxel commented 1 year ago

"alpine": true is a little counterintuitive. Why not just alpine?

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine"
}

Unfortunately that wouldn't be valid json.

This may be an uncommon case, but one of the Features I maintain runs on various architectures in Debian, but only on amd64 in Ubuntu. I know it is difficult to balance simplicity and fineness, but if such cases could be covered (or at least the Feature could be executed ignoring warnings), it would be better.

This is a good point. There could be an OS and version specific override for architectures since that would be a bit of an exception case. But I've definitely seen situations where a 3p Linux package feed only contains x86 for certain distros.

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": { "architectures": ["x86_64"] },
   "alpine": true
}

or if it was only a specific version:

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": [ "22.04", { "version": "20.04", "architectures": ["x86_64"] } ],
   "alpine": true
}

We also need to decide if we're aligning on codenames for versions or version numbers. For x86, we'd also need to decide between "amd64" which you see pretty frequently or x86_64. Or I guess we could support both.

BusHero commented 1 year ago

"alpine": true is a little counterintuitive. Why not just alpine?

"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine"
}

Indeed, this is not a valid JSON.

What about making osVersion an array rather than an object? In that case, it can accept both objects and strings:

"architectures": ["x86_64", "arm64"],
"osVersion": [
   {
      "name": "debian",
      "versions": ["10", "11"]
   },
   {
      "name": "ubuntu",
      "versions": ["20.04", "18.04"]
   },
   "alpine"
]
Chuxel commented 1 year ago

Hmmm. That would be more verbose for the more common case of only a subset of versions working.

aschillingpayne commented 1 year ago

I'm not sure why you would make the alpine section any different to the debian or ubuntu. Its a stretch to imply alpine: true means every possible version of alpine is supported. For consistency, why not have the version array for alpine too, and it imply the set of OS versions that the component developer has tested or supports. Any JSON validation then doesn't have to have exception rules to differentiate between a string array and a boolean.

{
"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine": ["3.16", "3.17.1"]
}

Using a generalized convention labels may help avoid over-specification: "3" (all 3.x.x minor and incremental versions), "3.16" (all 3.16.x incremental versions), "3.16.3" (a specifically identified version).

Chuxel commented 1 year ago

I'm not sure why you would make the alpine section any different to the debian or ubuntu. Its a stretch to imply alpine: true means every possible version of alpine is supported. For consistency, why not have the version array for alpine too, and it imply the set of OS versions that the component developer has tested or supports. Any JSON validation then doesn't have to have exception rules to differentiate between a string array and a boolean.

{
"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine": ["3.16", "3.17.1"]
}

Using a generalized convention labels may help avoid over-specification: "3" (all 3.x.x minor and incremental versions), "3.16" (all 3.16.x incremental versions), "3.16.3" (a specifically identified version).

It's not specific to alpine. An alternative would be "debian": [ "*" ] - it means the feature owner is not putting a specific version restriction in place.

aschillingpayne commented 1 year ago

I'm not sure why you would make the alpine section any different to the debian or ubuntu. Its a stretch to imply alpine: true means every possible version of alpine is supported. For consistency, why not have the version array for alpine too, and it imply the set of OS versions that the component developer has tested or supports. Any JSON validation then doesn't have to have exception rules to differentiate between a string array and a boolean.

{
"architectures": [ "x86_64", "arm64"],
"osVersion": {
   "debian": ["10", "11"],
   "ubuntu": ["20.04", "18.04"],
   "alpine": ["3.16", "3.17.1"]
}

Using a generalized convention labels may help avoid over-specification: "3" (all 3.x.x minor and incremental versions), "3.16" (all 3.16.x incremental versions), "3.16.3" (a specifically identified version).

It's not specific to alpine. An alternative would be "debian": [ "*" ] - it means the feature owner is not putting a specific version restriction in place.

Agreed, a wildcard version identifier also occured to me, and it makes sense that it apply to any osVersion, as well as the architectures.

joshuanianji commented 8 months ago

Can we also let a feature declare the shells they support? Some features only support bash, so when I set configureZshAsDefaultShell in common-utils it generates some unexpected errors.

chrmarti commented 7 months ago

At image build time we can check against /etc/os-release to decide if a feature can be installed. Other cases we might want to consider:

phorcys420 commented 2 months ago

Using a generalized convention labels may help avoid over-specification: "3" (all 3.x.x minor and incremental versions), "3.16" (all 3.16.x incremental versions), "3.16.3" (a specifically identified version).

It's not specific to alpine. An alternative would be "debian": [ "*" ] - it means the feature owner is not putting a specific version restriction in place.

I know this issue is kind of old but I think this feature deserves some love :-) Why not use semver version ranges like npm does?