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

Updating .NET Linux Build for .NET 8 #83428

Closed
richlander opened this issue Mar 14, 2023 · 5 comments
Closed

Updating .NET Linux Build for .NET 8 #83428

richlander opened this issue Mar 14, 2023 · 5 comments

Comments

@richlander
Copy link
Member

richlander commented Mar 14, 2023

Updating .NET Linux Build for .NET 8

.NET Core started out life as a cross-platform project. We naturally wanted to encourage usage on Linux. Across the first couple versions, we figured out how to build a single set of binaries that worked everywhere (e.g. for Linux x64). A key design point of that project was building on an old Linux so that our choice of build OS didn’t unnecessarily limit where .NET apps could be run. That has worked well, using CentOS 7, but it will soon go out of support. There isn't an obvious replacement for CentOS 7, requiring us to adopt a new approach.

We intend to use a combination of Mariner and a streamlined copy of Ubuntu going forward.

Breadth Targeting

The primary aspect of breadth targeting on Linux is linking with the C standard library (libc). Native code (like the .NET runtime) is compiled with a given libc and then is only able to run on distros with a libc version at least that high.

There are two libc variants (that we support) on Linux: glibc, and musl.

The following technique can be used to determine the glibc version of a given distro.

% docker run --rm ubuntu:16.04 ldd --version 
ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23 
Copyright (C) 2016 Free Software Foundation, Inc. 

The following technique can be used with Alpine (for musl).

% docker run --rm alpine:3.17 /lib/libc.musl-aarch64.so.1  
musl libc (aarch64) 
Version 1.2.3 

CentOS 7

CentOS 7 has been our workhorse build distro since the early days of .NET Core. We have used it to build the Linux+glibc+x64 product since .NET Core 1.0. We use different methodologies for musl and Arm that already better align with the proposal.

As case in point, the glibc in CentOS 7 is quite old (which is good).

% docker run --rm centos:7 ldd --version  
ldd (GNU libc) 2.17 
Copyright (C) 2012 Free Software Foundation, Inc. 

CentOS was the community (AKA “free”) distro for Red Hat Enterprise Linux (RHEL). We adopted it since it satisfied our need to support both RHEL and Debian distro families. Also, Red Hat was our original Linux distro partner and using CentOS 7 had good alignment with RHEL 7.

CentOS 7 will hit EOL in June 2024, after ten good years of support. CentOS 8 is already EOL. More generally, the CentOS project has been replaced with CentOS Stream, which serves a different market niche than the original project.

Mariner + rootfs

Our plan going forward is to use the newest OS and newest tools to run our build while targeting old Linux. But how?

We intend to switch to Mariner as our build OS (where cmake and the compilers run) and then use the rootfs build technique to target a different distro and to minimize our exposure to it. We will be cross-compiling with the rootfs target, not running the build in the chroot.

We already use the rootfs technique for Arm and musl builds. We will extend that approach to x64. This change will have the advantage that all Linux builds will use the same methodology for breadth targeting.

We plan to use Ubuntu 16.04 for the rootfs target. Ubuntu 16.04 offers us a quite old glibc, offering us significant breadth target compatibility with the Linux ecosystem. For .NET 9, we'd move to Ubuntu 18.04 and for .NET 11 to Ubuntu 20.04. That pattern would continue. Careful readers would realize that we'd be using these Ubuntu versions after they were EOL. We're primarily using them for header files, such that the risk profile is very low.

We plan to adopt LLVM 16 as our toolset for .NET 8. Where possible, we plan to replace our use of GNU binutils with LLVM equivalents.

This approach is roughly similar to manylinux. Our goal is to treat secure supply chain and breadth targeting as high priorities. That's what is motivating the use of the rootfs technique. Similar to manylinux, we will offer our new build environment as a solution for developers that want to build compatible ("breadth targeting") Linux binaries, giving .NET an analogous offering.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Mar 14, 2023
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@richlander
Copy link
Member Author

@dotnet/distro-maintainers

@ghost
Copy link

ghost commented Mar 15, 2023

Tagging subscribers to this area: @dotnet/runtime-infrastructure
See info in area-owners.md if you want to be subscribed.

Issue Details

Updating .NET Linux Build for .NET 8

.NET Core started out life as a cross-platform project. We naturally wanted to encourage usage on Linux. Across the first couple versions, we figured out how to build a single set of binaries that worked everywhere (e.g. for Linux x64). A key design point of that project was building on an old Linux so that our choice of build OS didn’t unnecessarily limit where .NET apps could be run. That has worked well, using CentOS 7, but it will soon go out of support. There isn't an obvious replacement for CentOS 7, requiring us to adopt a new approach.

We intend to use a combination of Mariner and a streamlined copy of Ubuntu going forward.

Breadth Targeting

The primary aspect of breadth targeting on Linux is linking with the C standard library (libc). Native code (like the .NET runtime) is compiled with a given libc and then is only able to run on distros with a libc version at least that high.

There are two libc variants (that we support) on Linux: glibc, and musl.

The following technique can be used to determine the glibc version of a given distro.

% docker run --rm ubuntu:16.04 ldd --version 
ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23 
Copyright (C) 2016 Free Software Foundation, Inc. 

The following technique can be used with Alpine (for musl).

% docker run --rm alpine:3.17 /lib/libc.musl-aarch64.so.1  
musl libc (aarch64) 
Version 1.2.3 

CentOS 7

CentOS 7 has been our workhorse build distro since the early days of .NET Core. We have used it to build the Linux+glibc+x64 product since .NET Core 1.0. We use different methodologies for musl and Arm that already better align with the proposal.

As case in point, the glibc in CentOS 7 is quite old (which is good).

% docker run --rm centos:7 ldd --version  
ldd (GNU libc) 2.17 
Copyright (C) 2012 Free Software Foundation, Inc. 

CentOS was the community (AKA “free”) distro for Red Hat Enterprise Linux (RHEL). We adopted it since it satisfied our need to support both RHEL and Debian distro families. Also, Red Hat was our original Linux distro partner and using CentOS 7 had good alignment with RHEL 7.

CentOS 7 will hit EOL in June 2024, after ten good years of support. CentOS 8 is already EOL. More generally, the CentOS project has been replaced with CentOS Stream, which serves a different market niche than the original project.

Mariner + rootfs

Our plan going forward is to use the newest OS and newest tools to run our build while targeting old Linux. But how?

We intend to switch to Mariner as our build OS (where cmake and the compilers run) and then use the rootfs build technique to target a different distro and to minimize our exposure to it. We will be cross-compiling with the rootfs target, not running the build in the chroot.

We already use the rootfs technique for Arm and musl builds. We will extend that approach to x64. This change will have the advantage that all Linux builds will use the same methodology for breadth targeting.

We plan to use Ubuntu 16.04 for the rootfs target. Ubuntu 16.04 offers us a quite old glibc, offering us significant breadth target compatibility with the Linux ecosystem. For .NET 9, we'd move to Ubuntu 18.04 and for .NET 11 to Ubuntu 20.04. That pattern would continue. Careful readers would realize that we'd be using these Ubuntu versions after they were EOL. We're primarily using them for header files, such that the risk profile is very low.

This approach is roughly similar to manylinux. Our goal is to treat secure supply chain and targeting as high priorities. That's what is motivating the use of the rootfs technique. Similar to manylinux, we will offer our new build environment as a solution for developers that want to build compatible ("breadth targeting") Linux binaries, giving .NET an analogous offering.

Author: richlander
Assignees: -
Labels:

area-Infrastructure, untriaged

Milestone: -

@richlander
Copy link
Member Author

This work is complete. It went out in stages, in Preview 4 and 5.

The results of this project are (in large part) captured at https://github.com/dotnet/runtime/blob/main/docs/workflow/building/coreclr/linux-instructions.md

Many thanks to @sbomer for his efforts on the project! It was not straightforward, at all.

@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Aug 17, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Sep 17, 2023
@richlander
Copy link
Member Author

Related: #69361

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

2 participants