.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 团队合作使我们能够超越。
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 工作负载。
.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 包:
让我们来看看规模性获胜。以下所有大小都是未压缩的(在磁盘上,不是注册表/线路大小)。
首先,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容器图像
对于大多数应用程序来说,使用这些新的容器图像不会对 Dockerfile 的外观产生任何显着影响。我们更新了我们的示例以使用这些新的容器图像:
我将向您展示使用 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 容器目前处于预览阶段。当它们稳定并在生产中得到支持时,我们将另行发布公告。
非 root图像
我们已经使用非 root 用户配置了所有新的 .NET Chiseled Ubuntu 容器。这些图像不包含 root
用户或包含提升 root 权限的命令,例如 sudo
或 su
。这意味着无法执行需要 root
的功能和操作。
除了删除像 bash
这样的 shell 之外,非 root 图像也是一种额外的安全缓解措施。非 root 图像在逻辑上是独立的,并且补充了没有 root 运行的守护程序。特权的每一次减少都会有所帮助。
如果您需要访问特权资源,可以在 Dockerfile
中添加 root
用户。你不会被阻止,但这是您要做出的特定安全决定。
Chiseled图像类似于设备,不是通用的。我们觉得他们为我们提供了最终交付非 root图像的机会。这为我们未来的政策提供了依据。类似设备的图像将作为非 root 用户交付,而通用图像将根据基本图像的策略(可能使用 root
用户配置)进行交付。然而,Canonical 的这个项目启发了我们寻找一个中间选项,即提供不支持 root 的图像。
安全的供应链
Canonical 制定了一个安全流程,可将 Ubuntu 虚拟机图像直接交付到 Azure 以供客户使用。我们突然想到,Canonical 可以对我们用来构建基于 Ubuntu 的 .NET 图像(常规和 Chiseled)的 Ubuntu 容器基础图像做同样的事情。这就是我们现在使用的,而不是从 Docker Hub 中提取。我们现在为所有具有已知保管/出处的 Canonical 资产建立了有效的零距离供应链。
我们正在做与共享 CVE 修复类似的事情。我们有一个共享的私有虚拟单声道存储库,用于共享每月补丁。它也与 Red Hat 共享。这意味着我们可以共同努力,以协调的方式在正确的时间进行正确的修复。
.NET 容器图像尚未签名,但即将推出。我们会定期努力提高我们以安全为中心的能力。
支持
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。
下一步计划
我们已经发现了许多使 Canonical 更容易使用 .NET 源代码的机会。我们将在短期内专注于这些。这些改进还将使其他从源代码构建和分发 .NET 的用户受益。
我们最近为 .NET 设置了一个发行版维护组。Canonical 是该组的成员。我们已经开始在该论坛中讨论潜在的源代码构建改进。欢迎其他发行版(从源代码构建 .NET)加入。有关详细信息,请联系 [email protected]。
Canonical 开始支持 x64 并将很快为 Arm64 添加 .NET 包。对于需要支持多种主线芯片架构的行业来说,这是一个激动人心的时刻。Ubuntu 和 .NET 在支持多种架构方面有着悠久的历史。
.NET 已经开源 5 年多了。我们与 Canonical 的合作在我们 GitHub 项目的早期阶段感觉是遥不可及。我们已经学到了很多关于如何构建 OSS 项目以便它成为 Linux 发行版候选者的知识。这要感谢教给我们很多东西的其他合作伙伴,尤其是 Fedora 和 Red Hat。回顾过去,很容易看出,现在开源、信任和行业关系比我们刚开始时更为重要。我们很高兴也很荣幸能与 Canonical 合作。