.NET 6 in Ubuntu 22.04

微軟技術棧發表於2022-11-24

.NET 6 is now included in Ubuntu 22.04 (Jammy) , just apt install dotnet6 can be installed. This change is a major improvement and simplification for Ubuntu users. We also released .NET with Chiseled Ubuntu Containers, a new small and secure container product from Canonical. These improvements are the result of a collaboration between Canonical and Microsoft.

Here are the commands to install the .NET 6 SDK on Ubuntu 22.04 :

 sudo apt update
sudo apt install dotnet6

We also announced that .NET 6 is available for Chiseled Ubuntu containers . Our friends at Canonical developed a new chisel method to make ultra-small container images. We are very happy about it. The Chiseled Ubuntu image is smaller than the Ubuntu image you used earlier 100MB !

Here is the command to pull the new ASP.NET Chiseled image:

 docker pull mcr.microsoft.com/dotnet/nightly/aspnet:6.0-jammy-chiseled

We've also updated the dotnetapp and aspnetapp samples so you can try out .NET in a Chiseled Ubuntu container.

  • These new container images significantly improve the security posture:
  • Very small images (reduces size and attack surface)
  • No package manager (avoids a whole class of attacks)
  • No shell (avoids a whole class of attacks)
  • non-root (avoids a whole class of attacks)

Most importantly, Canonical and Microsoft are committed to working together to ensure that new .NET releases work well with new Ubuntu releases. This includes security updates and secure delivery of container images. We are very excited that .NET 6 is available in Ubuntu 22.04 and that Canonical has chosen to work with us as a publishing partner for their Chiseled Ubuntu images. That's what Canonical has to say about the project.


"Ubuntu now has the story from the development side to the production side, starting with the .NET platform, with support for ultra-small container images," said Valentin Viennot, Canonical Product Manager. "We think this is a huge step forward for both our communities; Working with Microsoft's .NET team allows us to go above and beyond.


Canonical and Microsoft

Canonical and Microsoft started working together a few months ago with the goal of making Ubuntu a better .NET development environment.

We have two main goals:

  • Simplified with .NET on Ubuntu.
  • Shorten the supply chain between Canonical and Microsoft.

Over the years, we have known that many .NET developers use Ubuntu. After our conversation, it became clear that there are things we can do to improve this experience. Let me tell you what we delivered.

.NET in APT

You can now install .NET 6 using APT built by Canonical via source-build . These packages are available for Ubuntu 22.04 (Jammy) and later. This is a good reason to upgrade to Jammy !


Note: Now that .NET 6 is included in Ubuntu, check out our advice on using packages.microsoft.com on Ubuntu 22.04 .


There are multiple packages :

I'll show you how to install these images using Docker (same model applies elsewhere):

 rich@kamloops:~$ docker run --rm -it ubuntu:jammy
root@7d4dfca0ef55:/# apt update && apt install -y dotnet6
root@7d4dfca0ef55:/# dotnet --version
6.0.108

If this doesn't work, you need to register the following sources in /etc/apt/sources.list:

 deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe

Canonical and Microsoft will work together to ensure that these packages are updated in the monthly .NET team release schedule. This includes Microsoft sharing CVE information (description and code) with Canonical prior to public release. Likewise, Canonical will share security information in the other direction.

Notice:

  • We are currently missing the Arm64 version. These will come soon. Both companies are strong supporters of Arm64.
  • The .NET 7 version is not yet available and may not be available until after .NET 7 GA.
  • The .NET SDK workload is not available in the package (for any Linux distribution). Also, Linux does not support .NET MAUI workloads.

    .NET in a Chiseled Ubuntu container

You can now use .NET in Chiseled Ubuntu containers . Chiseling offers the smallest container footprint while still being the Ubuntu you know and trust. It is similar to traditional distroless with a custom tool for slicing .deb package.

These images are smaller than the Ubuntu images we currently provide 100MB and don't include root!

We provide three-tier Chiseled Ubuntu container images for Arm64 and x64 and .NET 6 and 7:

 mcr.microsoft.com/dotnet/nightly/runtime-deps:6.0-jammy-chiseled
 mcr.microsoft.com/dotnet/nightly/runtime:6.0-jammy-chiseled
 mcr.microsoft.com/dotnet/nightly/aspnet:6.0-Jammy-chiseled

Note: Images will be available in our 夜間 repository while chiseled products are in preview. We will make another announcement when they are supported in production. It's going to be sometime this year, but we haven't picked a timeline yet as we've been focusing on the basic enablement.

Canonical also publishes Chiseled Ubuntu container images for .NET via Docker Hub, which include new APT packages:

Let's look at scale wins. All sizes below are uncompressed (on disk, not registry/wire sizes).
First, the runtime-deps layer.

  • Ubuntu 22.04 (Jammy): 112MB
  • Chiseled Ubuntu 22.04 (Jammy): 12.9MB

On the other end of the spectrum, the aspnet layer.

  • Ubuntu 22.04 (Jammy): 213MB
  • Chiseled Ubuntu 22.04 (Jammy): 104MB

What an amazing difference! The folks at Canonical have figured out how to remove 100MB of binaries and other content from these images. When we first started talking, we didn't know we would be talking about such a big difference!

The attentive reader will notice that chiseled aspnet is smaller than the existing runtime-deps layer. This is really nice.

It is reasonable to ask what Alpine looks like. This is a newer distro, designed from the start to be ultra-small and componentized. Alpine is 9.84MB for runtime-deps:6.0-alpine aspnet:6.0-alpine and 100MB for ---78409546066e487cd8c0f8c342b59363--- . These are uncompressed and impressive numbers. This is a key reason why Alpine is so popular (and why we've released .NET images for it over the years).

Alpine is great (and we're friends with these people too), but it's not for everyone and every application because it uses musl , a different (and incompatible) libc variant. This only matters if your application includes native libraries. If not (most .NET applications don't), you don't need to worry about this detail. The .NET product itself is happy to run with musl or glibc , and every PR runs on dotnet/runtime tests.

From this perspective, this is really good news if you use Ubuntu for development and have always wanted to put a small Ubuntu into production. You now have a direct path from the development box to the cloud without any distribution compatibility issues. It's amazing (and very surprising) to see Ubuntu on the same ballpark as Alpine. Kudos to the folks at Canonical for their tremendous engineering achievements.

It is worth mentioning that Chainguard is looking for minimal container images for future security. The project has run out of distroless GitHub org. We're following this project and it's great to see more interest in smaller, safer container images. We believe minimal + non-root container images are the future.

Like our Alpine image , we chose not to include ICU . It might double the size of the image. This means that we have globalization invariant mode enabled. That's fine for some applications, and a win at scale is great. For others, it's a deal breaker. We may need to adjust this part of the plan based on feedback. We have documented the mode for adding ICU to the image.

Let me demonstrate these images a bit to illustrate how these images are (intentionally) restricted.

 % docker run --rm mcr.microsoft.com/dotnet/nightly/runtime-deps:6.0-jammy-chiseled-amd64
docker: Error response from daemon: No command specified.
See 'docker run --help'.

Let's try again.

 % docker run --rm mcr.microsoft.com/dotnet/nightly/runtime-deps:6.0-jammy-chiseled-amd64 bash
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknown.

Um? How is this going? They don't work! That's the point. These are container images for similar devices. They are stripped to a minimum. They just do what you designed them to do. That's what makes them safer. If this experience is uncomfortable, you can always use a regular Ubuntu image. We will continue to provide them. They are not going away.

For runtime and aspnet images, we decided to use dotnet --info as ENTRYPOINT to make the experience more friendly and useful.

 % docker run --rm mcr.microsoft.com/dotnet/nightly/runtime:6.0-jammy-chiseled

        global.json file:
  Not found

Host:
  Version:      6.0.8
  Architecture: arm64
  Commit:       55fb7ef977

.NET SDKs installed:
  No SDKs were found.

.NET runtimes installed:
  Microsoft.NETCore.App 6.0.8 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Download .NET:
  https://aka.ms/dotnet-download

Learn about .NET Runtimes and SDKs:
  https://aka.ms/dotnet/runtimes-sdk-info

We do not provide chiseled SDK images. Because there is no obvious strong demand. In fact, chiseled SDK images can be difficult to use in some cases. You can continue to use the existing Jammy SDK image: mcr.microsoft.com/dotnet/sdk:6.0-jammy . If a chiseled SDK image is required, we'd be happy to reconsider.

Use chiseled container images

For most applications, using these new container images will not have any noticeable effect on the appearance of the Dockerfile. We updated our example to use these new container images:

I'll show you how easy it is to use dotnetapp.
Dockerfile is almost no different.

 FROM mcr.microsoft.com/dotnet/sdk:7.0-jammy AS build
WORKDIR /source
# 複製 csproj 並恢復為不同的層
COPY *.csproj .
RUN dotnet restore --use-current-runtime
# 複製和釋出應用程式和庫
COPY . .
RUN dotnet publish -c Release -o /app --use-current-runtime --self-contained false --no-restore
# 最後階段/影像
FROM mcr.microsoft.com/dotnet/nightly/runtime:7.0-jammy-chiseled
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "dotnetapp.dll"]

Only the last FROM statement is really different from our standard Ubuntu Dockerfile.

I will now build the example:

 rich@MacBook-Air-2 dotnetapp % pwd
/Users/rich/git/dotnet-docker/samples/dotnetapp
rich@MacBook-Air-2 dotnetapp % docker build -t dotnetapp-chiseled -f Dockerfile.chiseled .
rich@MacBook-Air-2 dotnetapp % docker images | grep dotnetapp-chiseled
dotnetapp-chiseled
                 latest      bf7e125bd182   20 seconds ago   90.5MB

Note: I am not using any .NET trimming functionality. Of course, this image can be made smaller. Let's start the container:

 rich@MacBook-Air-2 dotnetapp % docker run --rm dotnetapp-chiseled
         42
         42              ,d                             ,d
         42              42                             42 
,adPPYb,42  ,adPPYba, MM42MMM 8b,dPPYba,   ,adPPYba, MM42MMM
a8"    `Y42 a8"     "8a  42    42P'   `"8a a8P_____42   42
8b       42 8b       d8  42    42       42 8PP"""""""   42
"8a,   ,d42 "8a,   ,a8"  42,   42       42 "8b,   ,aa   42,
 `"8bbdP"Y8  `"YbbdP"'   "Y428 42       42  `"Ybbd8"'   "Y428

.NET 7.0.0-preview.7.22375.6
Linux 5.10.104-linuxkit #1 SMP PREEMPT Thu Mar 17 17:05:54 UTC 2022

OSArchitecture: Arm64
ProcessorCount: 4
TotalAvailableMemoryBytes: 3.83 GiB

Then, let's try to enter:

 rich@MacBook-Air-2 dotnetapp % docker run --rm --entrypoint bash dotnetapp-chiseled
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknown.
rich@MacBook-Air-2 dotnetapp % docker run --rm --entrypoint apt  dotnetapp-chiseled install -y bash curl
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "apt": executable file not found in $PATH: unknown.

My "red team" skills let me down. Note that docker exec will have the same result. Now I will describe the Chiseled image in more detail, as you can see in action.

Chiseled Ubuntu Containers

Chiseled Ubuntu containers are Canonical's interpretation of the concept of distroless, originally popularized by Google . In the original implementation, the distribution was stripped and only the necessary packages were installed. Chiseling goes a step further and installs only the necessary directories and files in each package .

Another challenge with the initial implementation was that it was not necessarily supported by either party. Chiseled Ubuntu containers are top-notch Canonical deliverables. This means you can use ultra-small container images and get support as a Canonical customer.

Thank you Google for putting us all on this path.

As mentioned, this approach has a lot of value:

  • Very small images (reduces size and attack surface)
  • No package manager (avoids a whole class of attacks)
  • No shell (avoids a whole class of attacks)

Chiseled Ubuntu containers are currently in preview. We will make a separate announcement when they are stable and supported in production.

non-rooted image

We've configured all new .NET Chiseled Ubuntu containers with a non-root user. These images do not contain the root user or contain commands that elevate root privileges, such as sudo or su . This means that functions and operations that require root cannot be performed.

In addition to removing shells like bash , non-root images are an additional security mitigation. Non-root images are logically independent and complement daemons that run without root . Every reduction in privilege helps .

If you need access to privileged resources, you can add root user in Dockerfile b77e0a95a7038963b2ff2e7292a235a1---. You won't be blocked, but it's your specific security decision to make.

Chiseled images are device-like, not generic. We feel like they offer us the opportunity to finally deliver a non-rooted image . This informs our future policy. Device-like images will be delivered as a non-root user, while generic images will be delivered according to the base image's policy (possibly configured with root user). However, this Canonical project inspired us to look for an intermediate option, which is to serve an image that doesn't support root .

secure supply chain

Canonical has a secure process in place to deliver Ubuntu virtual machine images directly to Azure for use by customers. It occurred to us that Canonical could do the same with the Ubuntu container base images we use to build Ubuntu based .NET images (regular and Chiseled). That's what we use now instead of pulling from Docker Hub. We now have an effective zero-distance supply chain for all Canonical assets with known custody/ provenance.

We are doing something similar with shared CVE fixes. We have a shared private virtual mono repository for sharing monthly patches. It is also shared with Red Hat. This means we can work together to make the right fix at the right time in a coordinated way.

.NET container images are not signed yet, but are coming soon. We regularly work to improve our security-focused capabilities.

support

Canonical and Microsoft have been working together to give you a better experience. This includes support. You can report issues in familiar .NET repositories such as dotnet/core and dotnet/runtime . If you want commercial support, you should start with Canonical Support . Canonical is the best place to support Ubuntu packages. Canonical may contact Microsoft as needed to assist with problem resolution.

Security researchers who find vulnerabilities in Canonical-provided .NET packages are still eligible to participate in the Microsoft .NET Bounty Program .

Microsoft continues to maintain .NET packages for Ubuntu in its packages.microsoft.com source code, and we intend to continue to do so in the future. For most users, we recommend using the dotnet6 package that comes with Ubuntu Jammy+. This is what I did. This is the same guide we provide for Red Hat users.


Note: Now that .NET 6 is included in Ubuntu, check out our advice on using packages.microsoft.com on Ubuntu 22.04 .


There are two main reasons for continuing to use Microsoft packages:

  • You want to use the .NET version from Microsoft, not any other vendor.
  • Microsoft packages target later .NET SDK feature bands (eg 6.0.4xx ), while the source build tracks 6.0.1xx . This is more relevant for Windows users, but may be important for some Linux users.

New packages are available for .NET 6+ and Ubuntu 22.04+. Previous .NET and Ubuntu versions (with new packages) are not supported. You must use an existing packages.microsoft.com feed to use .NET on earlier Ubuntu versions. Also, Ubuntu 22.04 does not support earlier .NET versions because they do not support OpenSSL v3.

next steps

We've identified many opportunities to make Canonical easier to work with .NET source code . We will focus on these in the short term. These improvements will also benefit other users who build and distribute .NET from source.

We recently set up a release maintenance group for .NET. Canonical is a member of this group. We have started discussing potential source build improvements in this forum. Other distributions (building .NET from source) are welcome to join. For more information, please contact dotnet@microsoft.com .

Canonical is starting to support x64 and will soon add .NET packages for Arm64. This is an exciting time for an industry that needs to support multiple mainline chip architectures. Ubuntu and .NET have a long history of supporting multiple architectures.

圖片

.NET has been open source for over 5 years. Our partnership with Canonical felt out of reach in the early stages of our GitHub project. We've learned a lot about how to structure an OSS project so that it becomes a candidate for a Linux distribution. Thanks to other partners who have taught us a lot, especially Fedora and Red Hat . Looking back, it's easy to see that open source, trust, and industry relationships are more important now than when we started. We are delighted and honored to be working with Canonical.


Click here to know more~

相關文章