Skip to content
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

Rename RID with alpine in name #3075

Closed
Petermarcu opened this issue Mar 11, 2018 · 29 comments
Closed

Rename RID with alpine in name #3075

Petermarcu opened this issue Mar 11, 2018 · 29 comments

Comments

@Petermarcu
Copy link
Member

@kasper3 commented on Sun Mar 11 2018

Sabotage Linux - http://sabotage.tech/
Void Linux - https://www.voidlinux.eu/
NodeOS - http://node-os.com/

are some examples of musl-libc based linux distributions. Here is a full list: https://wiki.musl-libc.org/projects-using-musl.html.

Currently microsoft/dotnet:2.1-sdk-alpine docker image has hardcoded alpine name in it and unlike dotnet-sdk-latest-linux-x64.tar.gz distro-agnostic package, there is no way of using alpine package on any-musl distro.

Please consider renaming alpine docker and tarball to have musl in its name instead of alpine, so other distros based on this libc can get the (non-official) support.

Example of using .NET Core on some non-officially supported glibc-based distros:

CC @janvorli @MichaelSimons


@Petermarcu commented on Sun Mar 11 2018

You should be able to publish for Alpine and use it on other musl-libc based distros.

My understanding is that in addition to just supporting musl-libc, we would have to make sure the binaries are created in a distro agnostic way with respect to other dependencies like openssl and libunwind.


@kasper3 commented on Sun Mar 11 2018

@Petermarcu, sure the same way there are fallback lookup paths for dependency lib names in glibc-based distros. Those fallback paths in core-setup/coreclr/corefx repos can even be added later.

However, with alpine hardcoded in RID name without a base RID with musl-libc is not neutral. Before 2.1 if this gets renamed to *musl-libc* that would be a great achievement in terms of future proofing, otherwise we are going to stick with alpine-* forever or encounter a breaking change when it's time to support the second musl-libc distro.


@Petermarcu commented on Sun Mar 11 2018

I think thats something we can consider. We'd have to make the graph something like this: linux-x64->musl-linux-x64->alpine-x64->alpine.3.6-x64. And make sure the implementations that are in the alpine.3.6-x64 packages end up in the linux-musl-x64 packages. I'm going to move this to the core-setup repo where it can be tracked.

@Petermarcu
Copy link
Member Author

We can consider this for 2.1. I'm not sure how the generic naming will help the docker layering. @MichaelSimons can give more insight on how that may work.

@ghost
Copy link

ghost commented Mar 11, 2018

how the generic naming will help the docker layering.

I think for docker it is fine to have OS name.

@Petermarcu
Copy link
Member Author

@janvorli , I believe you explored this when we first brought up Alpine. Were there any challenges we should be aware of? IIRC we just put it under a specific Alpine because it was the safest and easiest choice at the time.

@ghost
Copy link

ghost commented Mar 11, 2018

@Petermarcu, also for some reason the alpine package name has hardcoded version of alpine

https://dotnetcli.blob.core.windows.net/dotnet/Sdk/master/dotnet-sdk-latest-alpine.3.6-x64.tar.gz
vs.
https://dotnetcli.blob.core.windows.net/dotnet/Sdk/release/2.0.0/dotnet-sdk-latest-linux-x64.tar.gz

and 3.6 is already not the latest version of OS, it's 3.7 since Nov 2017 https://alpinelinux.org/

@Petermarcu
Copy link
Member Author

Yeah, thats what I meant by making sure things end up in linux-musl-x64 packages. When we have specific versions like 3.6, they are the minimum, so if the binaries work on 3.6 and 3.7 then we would have 3.7.

@Petermarcu
Copy link
Member Author

@janvorli I want to make sure you think the alpine binaries we have today are good enough to put in a generic musl rid package or if you would have concerns.

@Petermarcu
Copy link
Member Author

Noting a few PR's that will be helpful if we make this change:

dotnet/core-setup#3212
dotnet/core-setup#3483
dotnet/core-setup#3525

@janvorli
Copy link
Member

While I think it should work, we will need to test it. There were some surprises between Alpine 3.5 and 3.6 in term of the availability of the lttng stuff, so there may be others in the Alpine 3.7 and even more likely the other MUSL based Linux distros.

The Void Linux has an additional difference that needs to be taken care of in the core-setup stuff. It's /etc/os-release doesn't contain any version number. I remember that when I was testing glibc based version of the void Linux in the past, the dotnet tool was crashing because of that.

As for the RID hieararchy linux-x64->musl-linux-x64->alpine-x64->alpine.3.6-x64, I believe we have already discussed this in the past. This hierarchy is not correct, since it makes Linux-x64 a fallback for musl-linux-x64, which would not work due to the different libc. I think the suggestion back then was to make musl-linux-x64 child of unix-x64 instead. Since linux-x64 is essentially glibc-linux-x64 but we didn't want to change the linux-x64 to that.

@MichaelSimons
Copy link
Member

I don't see this impacting the docker layering. The base images wouldn't change as a result of this.

@omajid
Copy link
Member

omajid commented Mar 12, 2018

The Void Linux has an additional difference that needs to be taken care of in the core-setup stuff. It's /etc/os-release doesn't contain any version number. I remember that when I was testing glibc based version of the void Linux in the past, the dotnet tool was crashing because of that.

That should be fixed now: dotnet/core-setup#2381

@ghost
Copy link

ghost commented Mar 12, 2018

@janvorli, alpine 3.6 tarball is apparently working quite well on alpine 3.7 docker https://github.com/dotnet/cli/issues/8767. Maybe they have added all the required dependencies permanently in their pkgmanager and we can continue to use it for all 3.x versions? So tarball name can also be made neutral dotnet-sdk-latest-alpine.3.6-x64.tar.gz =>dotnet-sdk-latest-alpine.3-x64.tar.gz (or even without 3).

@ghost
Copy link

ghost commented Mar 17, 2018

Instead of linux-x64->musl-linux-x64->alpine-x64->alpine.3.6-x64,
can musl-linux-x64 be made as a sibling of linux-x64 instead of child?

@janvorli
Copy link
Member

can musl-linux-x64 be made as a sibling of linux-x64 instead of child

That's what I've said above:
"I think the suggestion back then was to make musl-linux-x64 child of unix-x64 instead."

@eerhardt
Copy link
Member

@Petermarcu - is this necessary for 2.1? I don't see anyone assigned to it. Note that most of this work will need to be done in dotnet/corefx and dotnet/coreclr. dotnet/core-setup just follows the lead of those repos.

@Petermarcu
Copy link
Member Author

I think if we're going to make it a sibling of Linux, we'd have to do it now because it would be breaking to do later. I'd like to not have to do this now if we don't have to and make it so the alpine build can be promoted I am happy to discuss.

@Petermarcu
Copy link
Member Author

@eerhardt if the only change is to leave everything in alpine packages but to change the parent of alpine to musl-linux and then that be parented to unix would anything other than the rid graph in corefx need to change?

I'm still not sure I like removing the linux parent from musl-linux. There could very well be linux assets that are c library agnostic and could be represented as linux and apply equally to alpine and ubuntu, right?

@ghost
Copy link

ghost commented Mar 28, 2018

@Petermarcu, there is a BSD LIBC used by non-Linux OSes. It would make more sense to realize libc as lower level artifact as possible. In theory there could be a non-Unix OS using bionic-libc.

Architecture -> LibC -> OSFamily -> OSKernel -> OS -> Distro

@eerhardt
Copy link
Member

After discussing this with @Petermarcu and @janvorli, here are our plans for .NET Core 2.1:

  1. We need to fix up our RID graph in order to support other non-glibc based distros.
    • Add musl-linux RID, with parent unix.
    • Change the alpine's parent to musl-linux.
    • While we are fixing the RID graph, we should also change android to be parented under unix instead of any that is today.
  2. We should investigate building our alpine runtime assets with -portableBuild=true, which should allow them to work on musl-based Linux distros. Note that the NuGet packages and tarballs we produce will still be branded alpine.

We will fix the RID graph with this issue. I've opened https://github.com/dotnet/corefx/issues/28554 for issue 2.

@eerhardt eerhardt self-assigned this Mar 28, 2018
eerhardt referenced this issue in eerhardt/corefx Mar 28, 2018
- Add `musl-linux` RID
- Set `alpine`'s parent to `musl-linux`
- Add `alpine.3.7` to the graph
- Fix up `android` to inherit from `unix` while we are here

Fixes https://github.com/dotnet/core-setup/issues/3817
eerhardt referenced this issue in eerhardt/corefx Mar 29, 2018
- Add `linux-musl` RID
- Set `alpine`'s parent to `linux-musl`
- Add `alpine.3.7` to the graph
- Fix up `android` to inherit from `unix` while we are here

Fixes https://github.com/dotnet/core-setup/issues/3817
@ericstj
Copy link
Member

ericstj commented Mar 29, 2018

As for the RID hieararchy linux-x64->musl-linux-x64->alpine-x64->alpine.3.6-x64, I believe we have already discussed this in the past. This hierarchy is not correct, since it makes Linux-x64 a fallback for musl-linux-x64, which would not work due to the different libc.

I respectfully disagree with this. You're thinking too narrow. RID doesn't mean "libc". RID only means LIBC in the context of a package that is building native assets that depend on a C-library. In the context of that package it needs to consider that it may be placing a lib-c-based asset in the linux-x64 folder in order to get the most opportunistic reach since libc is used by most linux distros. Then it must over-ride that asset on other Linux distros that don't have libc.

Now another package might be building a native asset that is linux specific and doesn't depend on a c-library. Should we force it to cross-compile for Alpine or musil which mean nothing to it? Another package might be building a managed asset that is linux specific. Should we force it to cross-compile as well?

I would always opt for the most potential reuse when we are designing the RID graph. For the cases where we know there is an incompatibility we need to make sure that folks can minimally cross compile to deal with that incompatibility, and the default/lower RID should give them more reach than the more specific one.

@janvorli
Copy link
Member

@ericstj if we were starting from scratch, I would say that we would have Linux-glibc and Linux-musl, both having a parent of Linux. And the linux would likely mean "anything that uses Linux kernel".
But due to the fact that we didn't consider the non-glibc case in the past, our current "Linux" really means linux-glibc and we are missing that one unifying level.

I wonder then if we should consider adding that level and naming it "linux-core" or something like that. linux-core would mean "anything that uses Linux kernel". Its children would be linux (meaning linux-glibc), linux-musl and android for now.

@ericstj
Copy link
Member

ericstj commented Mar 29, 2018

But due to the fact that we didn't consider the non-glibc case in the past, our current "Linux" really means linux-glibc and we are missing that one unifying level

No it doesn't because we do not say linux = glibc in isolation. We are just one package that happens to use RIDs, we aren't defining the RID in our usage. We say a package supports a set of distros, for that set it ensures the right assets apply. In that context it can achieve its desired support with either: {linux , linux-musil} or {linux-glibc, linux-musil}. Both are correct. For the set of supported frameworks both will produce the same result.

NuGet is not a switch statement. It's a hierarchy.

There is nothing wrong with assigning "most common behavior" to the linux RID (consider netstandard2.0 and net461 as a similar example). Worst case scenario someone creates a package that doesn't work on a platform they didn't support. In my opinion a package that tries to load a library and fails is much better than a missing library, at best they're equal. Speaking from experience folks tend to come to the framework or tooling team more often when a file is missing: there is nothing about our system that flags a missing file as "my library doesn't support this platform".

Now we could add a linux-glibc intermediate so that we could fully classify the c-library aspect of linux distros and apply it to all existing RIDs appropriately. That's a compatible change. Then package could decide to use such a RID: we could even do so at the same time we added it. It's not technically more correct than linux and linux-musil if the full set of supported platforms falls into only two categories. It's a choice the package author could make if they wanted their failure mode to be "missing file" as opposed to "wrong file" when a new c-library comes along.

@janvorli
Copy link
Member

I know it is a hierarchy, that's why I was thinking that the hieararchy should follow the real hierarchy of the OSes and distros. Now you got me really confused.
I have always thought that the rid graph hierarchy represents a way to look up assets that are not present for the actual RID of the current OS / distro we are running on. And based on this, I would assume that anything in the parent hierarchy would work. So if I have a package of text files, their RID would be "any". If I have a package of shell scripts, their RID could be "Unix", because they could work on any child of Unix (OSX, Android, FreeBDS, all Linux distros, ...).
But if someone creates a shared native library for linux-x64, it will never work on linux-musl-x64. So I don't understand why the Linux-x64 would be a parent of the Linux-musl-x64.

@ericstj
Copy link
Member

ericstj commented Mar 29, 2018

I would assume that anything in the parent hierarchy would work

Perhaps this is our main point of disagreement. That's actually an incorrect assumption and doesn't match how these hierarchies are used in practice in NuGet.

In the case that you have a more-specific asset, it doesn't matter what's in the parent heirarchy, its only the asset you get out. Often times the whole reason you define the more-specific asset is to obscure the more generic one.

Suppose you have an implementation of a library that works for most linuxes, except you discover that one distro has a quirk, and you need to cross-compile for that. For the purposes of this discussion lets assume that this library doesn't use the C standard library. I would say you could just do this:

runtimes/linux-x64/native/libmine.so
runtimes/quirkyDistro-x64/libmine.so

If I follow your logic this is not correct, since that linux-x64 asset would not actually work on quirkyDistro-x64 it wouldn't be acceptable to place it there, even though it would never be selected on quirkyDistro-x64.

Instead to keep your assumption true we would need to promote the quirk to the RID graph in order to get a representation that holds, something like.

runtimes/linux-noquirk-x64/native/libmine.so
runtimes/linux-quirk-x64/libmine.so

I think a better mental model for the RID graph is that actual software releases are tied to specific RIDs. These are real and have meaning. The intermediate groupings are imaginary groups that can help us share assets between real RIDs. The intermediate groups are named in such a way that makes it clear how we decided to group them, but they are not absolute and can never carry the complete set of things that folks might care about for cross-compilation. In some cases we may decide to only define a group for the exceptional case and let the larger group cover the common case. This isn't wrong, its an optimization or shorthand.

I'll reiterate that I've already said it is reasonable and not incorrect to add grouping for linux-glibc. My point is that it isn't breaking and it isn't technically required because folks have a pattern to follow without it that works for representing cross-compiled assets between glibc and musl.

eerhardt referenced this issue in dotnet/corefx Mar 30, 2018
* Support musl-libc based linux RIDs

- Add `linux-musl` RID
- Set `alpine`'s parent to `linux-musl`
- Add `alpine.3.7` to the graph
- Fix up `android` to inherit from `unix` while we are here

Fixes https://github.com/dotnet/core-setup/issues/3817

* Change linux-musl to be parented to linux.

* Reparent android RID to linux.
@ghost
Copy link

ghost commented Apr 14, 2018

@eerhardt, can you please explain what got fixed by your change? I was hoping to get smooth experience with

  • CLI's obtain dotnet script
  • buildtools / init-tools.sh script

I still cannot get to build .net core repos on alpine:latest (3.7), without manually fiddling with scripts to avoid

Installing dotnet cli...
Restoring BuildTools version 2.1.0-preview3-02711-02...
/coreclr/init-tools.sh: line 149: /coreclr/Tools/dotnetcli/dotnet: No such file or directory
ERROR: Could not restore build tools correctly.
Please check the detailed log that follows.
Running: /coreclr/init-tools.sh
Installing 'https://dotnetcli.azureedge.net/dotnet/Sdk/2.1.2/dotnet-sdk-2.1.2-alpine.3.7-x64.tar.gz' to '/coreclr/Tools/dotnetcli/dotnet.tar'
wget: server returned error: HTTP/1.1 404 Not Found

@ghost
Copy link

ghost commented Apr 14, 2018

Fillding with scripts

Manually hardcoding version = 3.6 in few places ..

@Petermarcu
Copy link
Member Author

I think his fixes were aimed at making sure we weren't pinned in a corner WRT the rid graph. We should continue working through this. I think the issue here is that everything is still in the original package names.

@ghost
Copy link

ghost commented Apr 15, 2018

@Petermarcu, it is maybe unclear from https://github.com/dotnet/corefx/issues/28554 what needs to be updated in order to emit musl based RID in .NET Core packages, given we are not suppose to modify the following files?

It would help if we get that working to provide wider support. Maybe I missed the point, but until we had runtime.linux-musl* packages populated at https://dotnet.myget.org/gallery/dotnet-core, the corefx issue could be kept open?

@Petermarcu
Copy link
Member Author

The corefx issue is about how the binaries are built. I think the next phase of this would be to package the same binaries in the core-setup repo into both the alpine packages as well as linux-musl packages.

@eerhardt do you agree?

@eerhardt
Copy link
Member

With https://github.com/dotnet/corefx/issues/28554 I think we've said that the "alpine" build should already be "portable" across any linux-musl based distro. It just doesn't necessarily pass the "portable= true" flag, which would cause the output RID to be linux-x64.

Yes, we can rename our archives and .nupkgs from alpine.3.6 to linux-musl, and then update the dotnet-install and init-tools.sh scripts to match.

@janvorli - can you confirm that our currently built Alpine binaries should work on any musl based distro one last time?

/cc @johnbeisner - FYI on the forth-coming dotnet-install script change.

@msftgits msftgits transferred this issue from dotnet/core-setup Jan 30, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 30, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants