尝试以扩展 VS Code 中的代理模式!

自定义开发容器特性

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 扩展。

功能

我们很高兴地宣布,开发容器**特性 (Features)** 能帮助你在开发容器中顺利获得所需的工具!

特性 (Features) 是独立的安装代码、容器配置和/或设置和扩展单元,旨在为你的开发容器启用新的开发功能。它们可以构建为与各种基础容器镜像配合使用。作为我们开发 开放开发容器规范 工作的一部分,我们改进了你可以获取预创建特性 (Features) 的位置以及如何创作和分发你自己的特性 (Features)。

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

向开发容器添加特性

开发容器特性 (Dev Container Features) 提供了一种将开发容器元数据与安装步骤关联起来的快速方法。你可以通过简单的引用将它们添加到你的开发容器中。

这些特性 (Features) 现在可以作为 OCI Artifacts 存储在任何支持的容器注册表中,这意味着你可以使用与引用容器镜像相同类型的标识符来引用它们。我们已将一些早期位于 vscode-dev-containers 仓库中的特性 (Features) 迁移到一个新的 devcontainers/features 仓库中,并使用这种新方法进行发布。

从 devcontainers/features 仓库引用不同的特性 (Features) 就像向你的 `devcontainer.json` 添加 `features` 属性一样简单。每个特性 (Feature) 都有一个 `README.md`,其中显示了如何引用该特性以及可用的选项。

下面的例子安装了 godocker-in-docker 特性 (Features)。

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

你也可以在 规范网站 上探索官方和公开贡献的特性 (Features)。任何特性 (Feature) 都可以通过编辑 `devcontainer.json` 来添加,公开发布的特性 (Features) 可以通过现有的开发容器配置体验来添加(例如 VS Code 开发容器 扩展中提供的)。

Specification site list of available Features

你甚至可以使用你最喜欢的 CI 系统,通过 dev container CLI、GitHub Action 或 Azure DevOps 任务来使用带有特性 (Features) 的开发容器。我们在 devcontainers/ci 仓库中提供了 GitHub Action 和 Azure DevOps 任务。dev container CLI、GitHub Action 或 Azure DevOps 任务还可以用于预构建包含特性 (Feature) 内容的镜像,以加快启动时间。

如果你不仅想使用公开可用的特性 (Features),还想创建自己的私有或公开特性 (Features) 并分享,请继续阅读!

创作

开始创建你自己的特性 (Features) 的一个好地方是新的 特性 (Features) 模板 仓库。除了为给定特性 (Feature) 的内容提供一个好的模板外,该模板还包含一个 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.json`、`install.sh` 以及目录中的任何其他文件。

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

上述提到的 特性 (Features) 模板 仓库包含一个 GitHub Actions 工作流,用于自动化发布过程。它将特性打包成 tarball,并将资产作为 OCI artifact 发布到 GHCR。通过在 GitHub 上仓库的 Actions 选项卡左侧选择 `release.yaml` 工作流来触发模板仓库中的该工作流。GitHub Action 会将特性发布到 GHCR 的 `/` 命名空间下。只有当特性 `devcontainer-feature.json` 中的版本属性更新时,特性才会被重新发布。

**注意:** 使用 GHCR 的一个手动步骤是将 OCI 包标记为“public”。这对于每个特性只需要执行一次。私有特性不需要此步骤,只要你使用注册表的凭据登录到 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` 属性。

你可以在规范中阅读更多关于特性执行和安装顺序的信息。

还有哪些新功能?

除了新的特性 (Features) 仓库,我们最近还开源了一个新的 devcontainers/images 仓库,其中托管了一组以前在 vscode-dev-containers 仓库中的特定镜像。

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

如何了解更多?

这篇文章只是介绍了特性的冰山一角,我们很高兴你尝试它们!

如上述内容中链接所示,了解特性 (Features) 及其分发方式的最佳位置是开发容器规范中的特性 (Features)特性分发 (Features distribution) 页面。

我们期待你在使用、创建和发布特性 (Features) 时提供反馈——我们很乐意在特性 (Features)特性分发 (Features distribution) 议题提案中听取它们的运作情况。

如果你有兴趣参与到整个规范中,或者连接另一个工具来利用它,请查看开发容器 规范CLI 仓库。

祝你创建开发容器愉快,编程愉快!

Brigit Murtaugh, @BrigitMurtaugh