现已发布!阅读关于 11 月的新功能和修复的信息。

自定义开发容器功能

2022 年 9 月 15 日,作者:Brigit Murtaugh,@BrigitMurtaugh

我们都经历过设置开发环境时的那个时刻——“哦,我只需要再添加一个东西!”——这个“东西”就是再添加一种语言或工具集(或者可能更多😊)才能在你的项目上工作。

开发容器是简化环境设置的绝佳方式 - 它们提供了一个完整的编码环境,其中包含项目所需的工具。它们使用镜像、Dockerfile 或 Docker Compose 文件以及 devcontainer.json 进行配置,devcontainer.json 是一种元数据格式,用于使用特定于开发的内容和设置来丰富容器。

在创建开发容器时,您可能会反复出现相同的“我只需要再添加一个东西!”的反应——也许您在 Dockerfile 中使用 Node.js 镜像,只需要添加 Git。或者,您可能需要添加更复杂的东西,例如在开发容器中处理 Docker 或 Kubernetes。开发容器非常棒,因为任何访问您代码的人都将拥有相同的、一致的体验,包括您添加的所有工具——但添加它们的最佳方法是什么?

如果有一种简单的方法可以在您的开发容器中安装额外的工具,只需提及该工具的名称和版本即可,那会怎么样?或者,如果作为工具用户或作者,您可以创建一个简单的方法供其他人安装,那会怎么样?共享手动脚本可以帮助重用,但在引用脚本时,您可能会忘记引用容器或工具设置,例如为 Go、Rust 或 C++ 调试启用 ptrace 支持,添加在容器启动时触发的特定入口点,或确保包含正确的 VS Code 扩展。

功能

我们很高兴地分享,开发容器功能可以帮助您顺利地在开发容器中获得所需的工具!

功能是独立的安装代码单元、容器配置和/或设置和扩展,旨在在您的开发容器中启用新的开发功能。可以构建它们以与各种基本容器镜像一起工作。作为我们在 开放式开发容器规范方面工作的一部分,我们对从何处获取预先创建的功能以及如何创作和分发您自己的功能进行了一些改进。

让我们看看有哪些新内容,以及如何开始使用任何支持开发容器的工具或服务中的功能(例如 VS Code 开发容器扩展或 GitHub Codespaces)!

向您的开发容器添加功能

开发容器功能提供了一种将开发容器元数据与某些安装步骤关联起来的快速方法。您可以通过简单的引用将它们添加到您的开发容器中。

这些功能现在可以作为 OCI 工件存储在任何支持的容器注册表中,这意味着您可以使用与引用容器镜像相同的标识符来引用它们。我们已将 vscode-dev-containers 存储库中的一些早期功能移到了新的 devcontainers/features 存储库中,这些功能使用这种新方法发布。

从 devcontainers/features 存储库引用不同的功能就像在您的 devcontainer.json 中添加一个 features 属性一样简单。每个功能都有一个 README.md,其中显示了如何引用该功能以及该功能有哪些可用选项。

下面的示例安装了 godocker-in-docker 功能

"name": "my-project-devcontainer",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
    "ghcr.io/devcontainers/features/go:1": {
        "version": "1.18"
    },
    "ghcr.io/devcontainers/features/docker-in-docker:1": {
        "version": "latest",
        "moby": true
    }
}

您还可以在规范站点上浏览官方和公开贡献的功能。任何功能都可以通过编辑 devcontainer.json 来添加,而公开发布的功能可以通过现有的开发容器配置体验(例如 VS Code 开发容器扩展中提供的)来添加。

Specification site list of available Features

您甚至可以使用来自您最喜欢的 CI 系统的具有功能的开发容器,方法是使用 开发容器 CLI、GitHub Action 或 Azure DevOps 任务。我们在 devcontainers/ci 存储库中提供了一个 GitHub Action 和 Azure DevOps 任务。开发容器 CLI、GitHub Action 或 Azure DevOps 任务也可用于预构建包含功能内容的镜像,以加快启动时间。

如果您不仅想使用公开的功能,还想创建自己的私有或公共功能来共享,请继续阅读!

创作

创建自己的功能的一个好起点是新的 功能模板存储库。除了包含给定功能内容的良好模板之外,该模板还包含一个 GitHub Actions 工作流程,以便使用您帐户的 GitHub 容器注册表 (GHCR) 快速发布它们,使您能够尽快启动并运行。我们稍后会详细讨论发布。

功能的源代码有两个组成部分:安装脚本 (install.sh) 和配置文件 (devcontainer-feature.json)。

+-- feature
|    +-- devcontainer-feature.json
|    +-- install.sh
|    +-- (other files)

install.sh:安装入口点脚本——它在概念上作为镜像的 Dockerfile 的一层添加,并在构建时执行。此入口点脚本可以安装语言(例如 Ruby)和工具(GitHub CLI)等工具。

devcontainer-feature.json:其中包含有关功能的元数据、一组可以在安装期间传递给功能安装脚本的选项,以及将合并到最终开发容器中的 devcontainer.json 的“片段”。例如,如果任何功能在其配置中指示 "privileged": true,则整个开发容器将以 --privileged 标志启动。

可以使用多种语言创作功能,最直接的是 shell 脚本。如果某个功能是用不同的语言编写的,则应在元数据中包含有关它的信息,以便用户可以做出明智的选择。

注意:虽然 install.sh 将以任何语言运行功能,但如果您用开发容器中不存在的解释型语言编写功能,则代码将无法执行。请务必获取您需要的语言作为 install.sh 的一部分。

您应该确保您公开发布的功能除了功能之外还会检查和安装依赖项。

此外,公共功能很可能在 arm64 或 x86_64 计算机上使用 - 因此请务必在可能的情况下适应这种情况。

您可以在规范中查看 devcontainer-feature.json 属性,以及 devcontainers/features 存储库中的公共示例。

现在我们已经了解了如何创建功能,如何将其分发给其他人?

分发

功能以 tarball 的形式分发。tarball 包含功能子目录的全部内容,包括 devcontainer-feature.jsoninstall.sh 和目录中的任何其他文件。

开放容器倡议 (OCI) 定义了容器和容器资源的行业标准。我们将功能视为 OCI 工件,并使用 OCI 注册表的概念来分发功能。

上面提到的 功能模板存储库包含一个 GitHub Actions 工作流程,用于自动化发布过程。它将功能打包成 tarball,并将资产作为 OCI 工件发布到 GHCR。通过在 GitHub 上存储库的 Actions 选项卡的左侧选择它,从模板存储库触发 release.yaml 工作流程。GitHub Action 会将功能发布到 GHCR,命名空间为 <owner>/<repo>。仅当其 devcontainer-feature.json 中的 version 属性更新时,才会重新发布功能。

注意:GHCR 的一个手动步骤是将 OCI 包标记为“公共”。这每个功能只需要执行一次。私有功能不需要此步骤,只要您使用注册表的凭据登录到 Docker CLI 即可访问。

与社区分享您的功能

如果您希望您的贡献出现在用于开发容器创建的 VS Code 开发容器GitHub Codespaces UI 中,您可以执行以下步骤

一旦合并,您的更改将出现在 containers.dev/collections 中。

功能安装顺序

如果我的 Feature 应该在另一个 Feature 之后安装怎么办?作为 Feature 的作者,您可能会发现您的 Feature 应该在其他 Feature 之前或之后安装。在您的 devcontainer-feature.json 中,您可以使用 installsAfter 属性来列出应该在其之前执行的 Feature。

作为最终用户,您可以使用 devcontainer.json 中的 overrideFeatureInstallOrder 属性进一步控制执行顺序。此数组中的任何 Feature ID 都将按照提供的顺序在所有其他 Feature 之前安装。例如:

"features": {
      "ghcr.io/devcontainers/features/java:1",
      "ghcr.io/devcontainers/features/node:1",
  },
  "overrideFeatureInstallOrder": [
    "ghcr.io/devcontainers/features/node"
  ]

默认情况下,Feature 会在基础镜像之上安装,其顺序由实现工具确定为最佳。

如果在 Feature 的 devcontainer-feature.json 或用户的 devcontainer.json 中提供了以下任何属性,则将遵循这些属性指示的顺序(优先级递减)。

  1. 用户 devcontainer.json 中的 overrideFeatureInstallOrder 属性。允许用户控制其 Feature 的执行顺序。
  2. 在 Feature 的 devcontainer-feature.json 中定义的 installsAfter 属性。

您可以在规范中阅读有关 Feature 执行和安装顺序的更多信息。

还有什么新内容?

除了新的 Feature 仓库之外,我们最近还开源了一个新的 devcontainers/images 仓库,我们在其中托管了一组之前位于 vscode-dev-containers 仓库中的特定镜像。

我们正在为开发容器模板(在 vscode-dev-containers 中称为“定义”)开发一个社区分发计划,我们预计它会类似于 Feature。我们将确保在 vscode-dev-containers 仓库中发布更新,就像我们 宣布新的 Features 和 images 仓库时所做的那样。

如何了解更多?

这篇文章只是触及了您可以使用 Feature 完成的事情的表面,我们很高兴您能尝试它们!

如以上内容中链接的那样,了解 Feature 的构成以及如何分发它们的最佳地点是开发容器规范的 FeaturesFeatures 分发页面。

我们期待您在使用、创建和发布 Feature 时的反馈 – 我们很乐意在 FeaturesFeatures 分发问题提案中了解它们对您有何帮助。

如果您有兴趣参与整个规范或将另一个工具连接起来以利用它,请查看开发容器 specCLI 仓库。

祝您开发容器创建愉快,编码愉快!

Brigit Murtaugh, @BrigitMurtaugh