现已推出!阅读 10 月份的新功能和修复。

自定义开发容器功能

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 Container Registry(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 上存储库的“操作”选项卡左侧选择它,触发模板存储库中的 release.yaml 工作流。GitHub Action 将在 <owner>/<repo> 命名空间下将功能发布到 GHCR。只有当 devcontainer-feature.json 中的版本属性更新时,功能才会重新发布。

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

与社区共享您的功能

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

合并后,您的更改将出现在containers.dev/collections 上。

功能安装顺序

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

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

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

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

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

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

您可以阅读有关功能执行和安装顺序的更多信息 规范

还有什么新功能?

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

我们正在开发一个针对开发容器模板的社区分发计划(我们在 vscode-dev-containers 中将其称为“定义”),预计将类似于功能。我们将确保在 vscode-dev-containers 存储库中发布更新,就像我们在 宣布新的功能和镜像存储库 时所做的那样。

我该如何了解更多信息?

这篇文章只是触及了您可以使用功能进行的操作的表面,我们很高兴您尝试使用它们!

如上文内容中链接所示,了解有关功能及其分发方式的最佳位置是 功能功能分发 页面。开发容器规范。

我们期待您在使用、创建和发布功能时提供反馈——我们很乐意听到您在 功能功能分发 问题提案中如何使用它们。

如果您有兴趣参与规范本身或连接另一个工具以利用它,请查看开发容器 规范CLI 存储库。

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

Brigit Murtaugh,@BrigitMurtaugh