Ubuntu 22.04 中的 .NET 6

.NET 6 现在包含在 Ubuntu 22.04 (Jammy) 中,只需 apt install dotnet6 即可安装。此更改是 Ubuntu 用户的一项重大改进和简化。我们还发布了带有 Chiseled Ubuntu 容器 的 .NET,这是 Canonical 的一个新的小型且安全的容器产品。这些改进是 Canonical 和 Microsoft 之间合作的成果。

以下是在 Ubuntu 22.04 上安装 .NET 6 SDK 的命令:


sudo apt update
sudo apt install dotnet6

我们还宣布 .NET 6 可用于 Chiseled Ubuntu 容器。我们在 Canonical 的朋友开发了一种新的chisel方法来制作超小型容器图像。我们对此感到非常高兴。Chiseled Ubuntu 图像比您之前使用的 Ubuntu 图像小 100MB

下面是拉取新的 ASP.NET Chiseled 图像的命令:

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

我们还更新了 dotnetapp 和 aspnetapp 示例,以便您可以尝试使用 Chiseled Ubuntu容器中的 .NET。

  • 这些新的容器图像显着改善了安全态势:

  • 超小图像(减小尺寸和攻击面)

  • 没有包管理器(避免一整类攻击)

  • 无外壳(避免一整类攻击)

  • 非root(避免一整类攻击)

最重要的是,Canonical 和 Microsoft 致力于合作以确保新的 .NET 版本与新的 Ubuntu 版本一起很好地协同工作。这包括安全更新和容器图像的安全交付。

我们非常高兴 .NET 6 在 Ubuntu 22.04 中可用,并且 Canonical 选择与我们合作作为其 Chiseled Ubuntu 图像的发布合作伙伴。这就是 Canonical 对该项目所说的。

Canonical 产品经理 Valentin Viennot 说:“Ubuntu 现在拥有从开发端到生产端的故事,从 .NET 平台开始,支持超小型容器图像。” “我们认为这对我们两个社区来说都是一个巨大的进步;与 Microsoft 的 .NET 团队合作使我们能够超越。

  • .NET 6:

    https://devblogs.microsoft.com/dotnet/announcing-net-6/?ocid=AID3045631

  • 包含在 Ubuntu 22.04 (Jammy):

    https://ubuntu.com/blog/install-dotnet-on-ubuntu

  • 在 Ubuntu 22.04 上安装 .NET 6 SDK 的命令:

    https://packages.ubuntu.com/jammy-updates/dotnet6

  • .NET 6 可用于 Chiseled Ubuntu 容器:

    https://github.com/ubuntu-rocks/dotnet/issues/21

  • Canonical:

    https://canonical.com/

  • chisel:

    https://github.com/canonical/chisel

  • dotnetapp:

    https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.chiseled

  • aspnetapp:

    https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.chiseled

Canonical and Microsoft

几个月前,Canonical 和 Microsoft开始合作,目标是让 Ubuntu 成为更好的.NET开发环境。

我们有两个主要目标:

  • 在 Ubuntu 上使用 .NET 进行简化。

  • 缩短 Canonical 和 Microsoft 之间的供应链。

多年来,我们都知道许多 .NET 开发人员使用 Ubuntu。在我们交谈之后,很明显我们可以做一些事情来改善这种体验。让我告诉您我们交付了什么。

APT 中的 .NET

您现在可以使用由 Canonical 通过 source-build 构建的 APT 安装 .NET 6。这些软件包可用于 Ubuntu 22.04 (Jammy) 及更高版本。这是升级到 Jammy 的一个很好的理由!

注意:现在 .NET 6 已包含在 Ubuntu 中,请查看我们关于在 Ubuntu 22.04 上使用 packages.microsoft.com 的建议。

有多个包:

  • dotnet6 — .NET 6 SDK(简称)。

  • dotnet-sdk-6.0 — 同上(全称)。

  • aspnet-runtime-6.0 — ASP.NET Core

  • dotnet-runtime-6.0 — .NET Runtime

我将向您展示如何使用 Docker 安装这些图像(相同的模型适用于其他地方):​​​​​​​


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

如果这不起作用,您需要在 /etc/apt/sources.list 中注册以下源:

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

Canonical 和 Microsoft 将合作确保这些软件包在每月的 .NET 团队发布计划中更新。这包括 Microsoft 在公开发布之前与 Canonical 共享 CVE 信息(描述和代码)。同样,Canonical 将在另一个方向共享安全信息。

注意:

  • 我们目前缺少 Arm64 版本。这些很快就会到来。两家公司都是 Arm64 的坚定支持者。

  • .NET 7 版本尚不可用,并且可能要等到 .NET 7 GA 之后才会提供。

  • .NET SDK 工作负载在包中不可用(对于任何 Linux 发行版)。此外,Linux 不支持 .NET MAUI 工作负载。

  • source-build:

    https://github.com/dotnet/source-build

  • APT 安装 .NET 6:

    https://ubuntu.com/blog/install-dotnet-on-ubuntu

  • Jammy:

    https://ubuntu.com/blog/ubuntu-22-04-lts-released

  • 关于在 Ubuntu 22.04 上使用 packages.microsoft.com 的建议:

    https://github.com/dotnet/core/issues/7699

  • 有多个包:

    https://packages.ubuntu.com/search?suite=default&section=all&arch=any&keywords=dotnet&searchon=names

  • dotnet6:

    https://packages.ubuntu.com/jammy-updates/dotnet6

  • dotnet-sdk-6.0:

    https://packages.ubuntu.com/jammy-updates/dotnet-sdk-6.0

  • aspnet-runtime-6.0:

    https://packages.ubuntu.com/jammy-updates/aspnetcore-runtime-6.0 

  • dotnet-runtime-6.0:

    https://packages.ubuntu.com/jammy-updates/dotnet-runtime-6.0

  • CVE 信息:

    https://github.com/dotnet/core/blob/main/release-notes/6.0/cve.md

  • .NET SDK 工作负载:

    https://github.com/dotnet/designs/blob/main/accepted/2020/workloads/workloads.md

.NET 在Chiseled  Ubuntu 容器中

您现在可以在 Chiseled Ubuntu 容器中使用 .NET。Chiseling 提供最小的容器占用空间,同时仍然是您了解和信任的 Ubuntu。它类似于传统的 distroless,带有一个为切片 .deb 包而定制的工具。

这些图像比我们目前提供的 Ubuntu 图像小 100MB,而且不包括 root 用户!

我们为 Arm64 和 x64 以及 .NET 6 和 7 提供三层 Chiseled Ubuntu 容器图像:

  • 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

注意:图像将在我们的夜间存储库中提供,而chiseled的产品处于预览状态。当它们在生产中得到支持时,我们将发布另一个公告。这将是今年的某个时候,但我们还没有选择一个时间表,因为我们一直专注于基本的启用。

Canonical 还通过 Docker Hub 发布适用于 .NET 的 Chiseled Ubuntu 容器图像,其中包括新的 APT 包:

  • https://hub.docker.com/r/ubuntu/dotnet-deps

  • https://hub.docker.com/r/ubuntu/dotnet-runtime

  • https://hub.docker.com/r/ubuntu/dotnet-aspnet

让我们来看看规模性获胜。以下所有大小都是未压缩的(在磁盘上,不是注册表/线路大小)。

首先,runtime-deps 层。

  • Ubuntu 22.04 (Jammy): 112MB

  • Chiseled Ubuntu 22.04 (Jammy): 12.9MB

在频谱的另一端,aspnet 层。

  • Ubuntu 22.04 (Jammy): 213MB

  • Chiseled Ubuntu 22.04 (Jammy): 104MB

多么惊人的区别!Canonical 的人已经想出了如何从这些图像中删除 100MB 的二进制文件和其他内容。当我们第一次开始交谈时,我们不知道我们会谈论如此大的差异!

细心的读者会注意到chiseled  aspnet 比现有的 runtime-deps 层小。这真是太好了。

咨询Alpine的样子是合理的。这是一个较新的发行版,从一开始就设计为超小型和组件化。对于 runtime-deps:6.0-alpine,Alpine 为 9.84MB,对于 aspnet:6.0-alpine,为 100MB。这些是未压缩并且令人印象深刻的数字。这是 Alpine 如此受欢迎的一个关键原因(也是我们多年来为它发布 .NET 图像的原因)。

Alpine 很棒(我们也是这些人的朋友),但它并不适合所有人和每个应用程序,因为它使用 musl,一种不同(且不兼容)的 libc 变体。这仅在您的应用程序包含本机库时才重要。如果没有(大多数 .NET 应用程序没有),则无需担心此细节。.NET 产品本身很乐意与 musl 或 glibc 一起运行,并且每个 PR 都在 dotnet/runtime 测试上运行。

从这个角度来看,如果您使用 Ubuntu 进行开发并且一直希望将小型 Ubuntu 投入生产,这确实是个好消息。您现在拥有从开发盒到云的直接路径,没有任何发行版兼容性问题。看到 Ubuntu 与 Alpine 在同一个球场上,真是令人惊奇(也非常令人惊讶)。向 Canonical 的人们致敬,感谢他们在工程方面取得的巨大成就。

值得一提的是,Chainguard 正在寻找最小的容器图像,以确保未来的安全。该项目已用完 distroless GitHub org。我们正在关注这个项目,很高兴看到人们对更小、更安全的容器图像更感兴趣。我们相信最小 + 非root容器图像是未来。

就像我们的 Alpine 图像一样,我们选择不包括 ICU。它可能会使图像的大小增加一倍。这意味着我们启用了全球化不变模式。对于某些应用程序来说,这很好,而且规模上的胜利也很棒。对于其他人来说,这是一个交易破坏者。我们可能需要根据反馈调整这部分计划。我们已经记录了将 ICU 添加到图像中的模式。

让我稍微演示一下这些图像,以说明这些图像是如何(有意)受到限制的。​​​​​​​


% 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'.

让我们再试一次。​​​​​​​


% 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.

嗯?这是怎么回事?他们不工作!这才是重点。这些是类似设备的容器图像。它们被剥离到最低限度。他们只是做你设计他们要做的事情。这就是使它们更安全的原因。如果这种体验不舒服,您可以随时使用常规的 Ubuntu 图像。我们将继续提供它们。他们不会消失。

对于runtime和 aspnet 图像,我们决定使用 dotnet –info 作为 ENTRYPOINT,以使体验更加友好和有用。​​​​​​​

% 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

我们不提供chiseled SDK 图像。因为并没有明显的强烈需求。事实上,chiseled SDK 图像在某些情况下可能很难使用。您可以继续使用现有的 Jammy SDK 图像:mcr.microsoft.com/dotnet/sdk:6.0-jammy。如果需要chiseled SDK 图像,我们很乐意重新考虑。

  • 在 Chiseled Ubuntu 容器中使用 .NET:

    https://github.com/ubuntu-rocks/dotnet/issues/21

  • distroless:

    https://hackernoon.com/distroless-containers-hype-or-true-value-2rfl3wat

  • Alpine:

    https://alpinelinux.org/

  • 这些人的朋友:

    https://pkgs.alpinelinux.org/packages?name=dotnet*

  • musl:

    http://musl.libc.org/

  • glibc:

    https://www.gnu.org/software/libc/

  • dotnet/runtime :

    https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md

  • Chainguard:

    https://www.chainguard.dev/

  • 最小的容器图像,以确保未来的安全:

    https://blog.chainguard.dev/minimal-container-images-towards-a-more-secure-future/

  • distroless:

    https://github.com/distroless

  • Alpine 图像:

    https://github.com/dotnet/dotnet-docker/blob/1297d21bbf695bcb87580bea2ccefdced894eeeb/src/runtime-deps/3.1/alpine3.16/amd64/Dockerfile#L19-L20

  • ICU:

    https://icu.unicode.org/

  • 全球化不变模式:

    https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md

  • 模式:

    https://github.com/ubuntu-rocks/dotnet/issues/21

使用chiseled容器图像

对于大多数应用程序来说,使用这些新的容器图像不会对 Dockerfile 的外观产生任何显着影响。

我们更新了我们的示例以使用这些新的容器图像:

  • dotnetapp

    https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.chiseled

  • aspnetapp

    https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.chiseled

我将向您展示使用 dotnetapp 是很容易的事情。

Dockerfile 几乎没有什么不同。​​​​​​​

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"]

只有最后的 FROM 语句与我们的标准 Ubuntu Dockerfile 真正不同。

我现在将构建示例:​​​​​​​


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

注意:我没有使用任何 .NET 修剪功能。当然,这个图像可以做得更小。

让我们启动容器:​​​​​​​

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

然后,让我们尝试进入:​​​​​​​

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.

我的“red team”技能让我失望了。请注意,docker exec 将具有相同的结果。

现在我将更详细地描述Chiseled图像,正如您在实际中看到的那样。

Chiseled Ubuntu 容器

Chiseled Ubuntu 容器 是 Canonical 对 distroless 概念的诠释,最初由 Google 推广。在最初的实现中,分发被剥离,只安装了必要的包。Chiseling 更进一步,只在每个包中安装必要的目录和文件。

最初实施的另一个挑战是它不一定得到任何一方的支持。Chiseled Ubuntu 容器 是一流的 Canonical 可交付成果。这意味着您可以使用超小型容器图像并作为 Canonical 客户获得支持。

感谢 Google 让我们所有人走上这条道路。

如前所述,这种方法有很多价值:

  • 超小图像(减小尺寸和攻击面)

  • 没有包管理器(避免一整类攻击)

  • 无外壳(避免一整类攻击)

Chiseled Ubuntu 容器目前处于预览阶段。当它们稳定并在生产中得到支持时,我们将另行发布公告。

  • 由 Google 推广:

    https://github.com/GoogleContainerTools/distroless

  • 只在每个包中安装必要的目录和文件:

    https://github.com/dotnet/dotnet-docker/blob/fd39ea3eece8c8653348a717446ac41e93633784/src/runtime-deps/6.0/jammy-chiseled/arm64v8/Dockerfile#L29-L36

非 root图像

我们已经使用非 root 用户配置了所有新的 .NET Chiseled Ubuntu 容器。这些图像不包含 root 用户或包含提升 root 权限的命令,例如 sudo 或 su。这意味着无法执行需要 root 的功能和操作。

除了删除像 bash 这样的 shell 之外,非 root 图像也是一种额外的安全缓解措施。非 root 图像在逻辑上是独立的,并且补充了没有 root 运行的守护程序。特权的每一次减少都会有所帮助。

如果您需要访问特权资源,可以在 Dockerfile 中添加 root 用户。你不会被阻止,但这是您要做出的特定安全决定。

Chiseled图像类似于设备,不是通用的。我们觉得他们为我们提供了最终交付非 root图像的机会。这为我们未来的政策提供了依据。类似设备的图像将作为非 root 用户交付,而通用图像将根据基本图像的策略(可能使用 root 用户配置)进行交付。然而,Canonical 的这个项目启发了我们寻找一个中间选项,即提供不支持 root 的图像。

  • 非 root :

    https://stackoverflow.com/questions/59840450/rootless-docker-image

  • 配置了所有新的 .NET Chiseled Ubuntu 容器:

    https://github.com/dotnet/dotnet-docker/blob/fd39ea3eece8c8653348a717446ac41e93633784/src/runtime-deps/6.0/jammy-chiseled/arm64v8/Dockerfile#L13-L26

  • 没有 root 运行的守护程序:

    https://docs.docker.com/engine/security/rootless/

  • 特权的每一次减少都会有所帮助:

    https://seclists.org/oss-sec/2019/q1/119

  • 最终交付非 root图像:

    https://github.com/dotnet/dotnet-docker/issues/2249

  • 提供不支持 root 的图像:

    https://github.com/dotnet/designs/pull/271

安全的供应链

Canonical 制定了一个安全流程,可将 Ubuntu 虚拟机图像直接交付到 Azure 以供客户使用。我们突然想到,Canonical 可以对我们用来构建基于 Ubuntu 的 .NET 图像(常规和 Chiseled)的 Ubuntu 容器基础图像做同样的事情。这就是我们现在使用的,而不是从 Docker Hub 中提取。我们现在为所有具有已知保管/出处的 Canonical 资产建立了有效的零距离供应链。

我们正在做与共享 CVE 修复类似的事情。我们有一个共享的私有虚拟单声道存储库,用于共享每月补丁。它也与 Red Hat 共享。这意味着我们可以共同努力,以协调的方式在正确的时间进行正确的修复。

.NET 容器图像尚未签名,但即将推出。我们会定期努力提高我们以安全为中心的能力。

  • CVE:

    https://www.cve.org/

  • 虚拟单声道存储库:

    https://github.com/dotnet/source-build/issues/2956

支持

Canonical 和 Microsoft 一直在合作,为您提供更好的体验。这包括支持。您可以在熟悉的 .NET 存储库中报告问题,例如 dotnet/core 和 dotnet/runtime。如果您想要商业支持,您应该从 Canonical 支持开始。Canonical 是支持 Ubuntu 软件包的最佳场所。Canonical 可能会根据需要联系 Microsoft 以协助解决问题。

在 Canonical 提供的 .NET 包中发现漏洞的安全研究人员仍然有资格参加 Microsoft .NET Bounty Program。

Microsoft 继续在其 packages.microsoft.com 源代码中维护 Ubuntu 的 .NET 包,我们打算在未来继续这样做。对于大多数用户,我们建议使用 Ubuntu Jammy+ 附带的 dotnet6 包。这就是我所做的。这与我们为 Red Hat 用户提供的指南相同。

注意:现在 .NET 6 已包含在 Ubuntu 中,请查看我们关于在 Ubuntu 22.04 上使用 packages.microsoft.com 的建议。

继续使用 Microsoft 软件包有两个主要原因:

  • 您希望使用来自 Microsoft 的 .NET 版本,而不是任何其他供应商。

  • Microsoft 软件包针对更高版本的 .NET SDK 功能频段(如 6.0.4xx),而源代码构建跟踪 6.0.1xx。这对 Windows 用户更相关,但对某些 Linux 用户可能很重要。

新软件包可用于 .NET 6+ 和 Ubuntu 22.04+。不支持以前的 .NET 和 Ubuntu 版本(使用新软件包)。您必须使用现有的 packages.microsoft.com 提要才能在早期 Ubuntu 版本上使用 .NET。此外,Ubuntu 22.04 不支持早期的 .NET 版本,因为它们不支持 OpenSSL v3。

  • dotnet/core:

    https://github.com/dotnet/core/issues/7699

  • dotnet/runtime:

    https://github.com/dotnet/runtime/issues

  • Canonical 支持开始:

    https://ubuntu.com/security/docker-images

  • Microsoft .NET Bounty Program:

    https://www.microsoft.com/msrc/bounty-dot-net-core?ocid=AID3045631

  • packages.microsoft.com:

    https://docs.microsoft.com/dotnet/core/install/linux?ocid=AID3045631

  • 关于在 Ubuntu 22.04 上使用 packages.microsoft.com 的建议:

    https://github.com/dotnet/core/issues/7699

下一步计划

我们已经发现了许多使 Canonical 更容易使用 .NET 源代码的机会。我们将在短期内专注于这些。这些改进还将使其他从源代码构建和分发 .NET 的用户受益。

我们最近为 .NET 设置了一个发行版维护组。Canonical 是该组的成员。我们已经开始在该论坛中讨论潜在的源代码构建改进。欢迎其他发行版(从源代码构建 .NET)加入。有关详细信息,请联系 dotnet@microsoft.com。

Canonical 开始支持 x64 并将很快为 Arm64 添加 .NET 包。对于需要支持多种主线芯片架构的行业来说,这是一个激动人心的时刻。Ubuntu 和 .NET 在支持多种架构方面有着悠久的历史。

  • Canonical 更容易使用 .NET 源代码的机会:

    https://github.com/dotnet/source-build/issues/2911

  • 潜在的源代码构建改进:

    https://github.com/dotnet/source-build/issues/2911

.NET 已经开源 5 年多了。我们与 Canonical 的合作在我们 GitHub 项目的早期阶段感觉是遥不可及。我们已经学到了很多关于如何构建 OSS 项目以便它成为 Linux 发行版候选者的知识。这要感谢教给我们很多东西的其他合作伙伴,尤其是 Fedora 和 Red Hat。回顾过去,很容易看出,现在开源、信任和行业关系比我们刚开始时更为重要。我们很高兴也很荣幸能与 Canonical 合作。

  • 其他合作伙伴:

    https://docs.microsoft.com/dotnet/core/install/linux#official-package-archives?ocid=AID3045631

  • Fedora :

    https://packages.fedoraproject.org/search?query=dotnet

  • Red Hat:

    https://access.redhat.com/documentation/en-us/net/6.0

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值