自定义开发容器 Features
2022 年 9 月 15 日,作者 Brigit Murtaugh,@BrigitMurtaugh
我们都曾有过这样的时刻,在设置开发环境时,会说:“哦,我只需要再一件东西!”——这件“东西”就是再添加一种语言或一套工具(或可能再多一些😊)来处理您的项目。
开发容器是简化环境设置的好方法——它们提供了一个完整的编码环境,包含您的项目所需的工具。它们通过镜像、Dockerfile 或 Docker Compose 文件以及 devcontainer.json
进行配置,后者是一种元数据格式,用于通过开发特定内容和设置来丰富容器。
在创建开发容器时,您可能会反复出现“我只需要再一件东西!”的反应——也许您在 Dockerfile 中使用 Node.js 镜像,但只需要添加 Git。或者您可能需要添加更复杂的东西,比如在开发容器中处理 Docker 或 Kubernetes。开发容器非常棒,因为任何访问您的代码的人都将拥有相同、一致的工具体验——但添加这些工具的最佳方式是什么呢?
如果有一种简单的方法,只需提及工具的名称和版本,即可在您的开发容器中安装该额外工具,那会怎样?或者,如果您作为工具用户或作者,可以为他人创建一种简单的安装方式,那会怎样?共享手动脚本有助于重用,但在引用时,您可能会忘记引用容器或工具设置,例如为 Go、Rust 或 C++ 调试启用 ptrace 支持,在容器启动时添加特定的入口点,或确保包含正确的 VS Code 扩展。
Features
我们很高兴地分享,开发容器的 Features 帮助您顺畅地在开发容器中获得所需的工具!
Features 是自包含的安装代码、容器配置和/或设置及扩展单元,旨在为您的开发容器启用新的开发功能。它们可以构建为与各种基础容器镜像配合使用。作为我们开发开放开发容器规范工作的一部分,我们对获取预创建 Features 的位置以及如何创作和分发您自己的 Features 进行了一些改进。
让我们看看有什么新功能,以及如何开始使用支持开发容器的任何工具或服务(例如 VS Code 开发容器 扩展或 GitHub Codespaces)中的 Features!
将 Features 添加到您的开发容器
开发容器 Features 提供了一种将开发容器元数据与某些安装步骤关联起来的快捷方式。您可以通过简单的引用将它们添加到您的开发容器中。
这些 Features 现在可以作为 OCI 工件存储在任何支持的容器注册表中,这意味着您可以使用与引用容器镜像相同的标识符类型来引用它们。我们已将 vscode-dev-containers 存储库中的一些早期 Features 移至新的 devcontainers/features 存储库,并在其中使用这种新方法发布它们。
从 devcontainers/features 存储库引用不同的 Features 就像向您的 devcontainer.json
添加 features
属性一样简单。每个 Feature 都有一个 README.md
,其中显示了如何引用该 Feature 以及有哪些可用选项。
以下示例安装了 go 和 docker-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 开发容器 扩展中可用的功能)添加。
您甚至可以使用 dev container CLI、GitHub Action 或 Azure DevOps 任务,从您最喜欢的 CI 系统中使用带 Features 的开发容器。我们在 devcontainers/ci 存储库中提供了 GitHub Action 和 Azure DevOps 任务。dev container CLI、GitHub Action 或 Azure DevOps 任务也可以用于预构建包含 Feature 内容的镜像,以加快启动时间。
如果您不仅想使用公开可用的 Features,还想创建自己的私有或公共 Features 进行共享,请继续阅读!
创作
开始创建自己的 Features 的一个好地方是新的 Features 模板 存储库。除了包含给定 Feature 内容的良好模板之外,该模板还包含一个 GitHub Actions 工作流程,可使用 GitHub Container Registry (GHCR) 快速发布它们到您的账户,以便您尽快启动并运行。我们稍后会详细讨论发布。
Feature 的源代码包含两个组件:安装脚本(install.sh
)和配置文件(devcontainer-feature.json
)。
+-- feature
| +-- devcontainer-feature.json
| +-- install.sh
| +-- (other files)
install.sh
:安装入口点脚本——它在概念上被添加为镜像 Dockerfile 的一层,并在构建时执行。此入口点脚本可以安装工具,例如语言(例如 Ruby)和工具(GitHub CLI)。
devcontainer-feature.json
:此文件包含有关 Feature 的元数据、在安装期间可以传递给 Feature 安装脚本的一组选项,以及将合并到最终开发容器中的 devcontainer.json
的“片段”。例如,如果任何 Feature 在其配置中指示 "privileged": true
,则整个开发容器将使用 --privileged
标志启动。
Features 可以用多种语言编写,最直接的是 Shell 脚本。如果 Feature 用不同的语言编写,则应将相关信息包含在元数据中,以便用户可以做出明智的选择。
注意: 虽然 install.sh 将运行任何语言的 Features,但如果您编写的 Feature 采用的解释型语言未在开发容器中,则代码将无法执行。请确保在 install.sh 中获取您需要的语言。
您应该确保公开发布的 Features 除了 Feature 本身之外,还会检查并安装依赖项。
此外,公共 Features 很可能在 arm64 或 x86_64 机器上使用——因此请务必尽可能适应这一点。
您可以在规范中查看 devcontainer-feature.json
属性,以及在 devcontainers/features 存储库中的公共示例。
现在我们已经了解了如何创建 Feature,那么如何将其分发给其他人呢?
分发
Features 以 tarball 形式分发。tarball 包含 Feature 子目录的全部内容,包括 devcontainer-feature.json
、install.sh
和目录中的任何其他文件。
Open Container Initiative (OCI) 定义了容器和容器资源的行业标准。我们将 Features 视为 OCI 工件,并使用 OCI Registry 的概念来分发 Features。
上述 Features 模板 存储库包含一个 GitHub Actions 工作流,用于自动化发布过程。它将 Feature 打包成一个 tarball,并将资产作为 OCI 工件发布到 GHCR。在 GitHub 上的存储库 Actions 选项卡左侧选择 release.yaml
工作流,从模板存储库触发它。GitHub Action 将 Feature 发布到 GHCR 的 <owner>/<repo>
命名空间下。只有当 devcontainer-feature.json
中的版本属性更新时,Feature 才会重新发布。
注意: GHCR 的一个手动步骤是将 OCI 包标记为“public”。这对于每个 Feature 只需执行一次。私有 Features 不需要此步骤,只要您使用注册表的凭据登录到 Docker CLI,即可访问它们。
与社区共享您的 Features
如果您希望您的贡献出现在 VS Code 开发容器 或 GitHub Codespaces UI 中,以便进行开发容器创建,您可以执行以下步骤:
- 前往 devcontainers.github.io(支持 containers.dev 的 GitHub 仓库)
- 打开一个 PR 以修改
collection-index.yml
文件
合并后,您的更改将出现在 containers.dev/collections。
Feature 安装顺序
如果我的 Feature 应该在另一个 Feature 之后安装怎么办?作为 Feature 作者,您可能会发现您的 Feature 应该在其他 Feature 之前或之后安装。在您的 devcontainer-feature.json
中,您可以使用 installsAfter
属性列出应该在其之前执行的 Features。
作为最终用户,您可以使用 devcontainer.json
中的 overrideFeatureInstallOrder
属性进一步控制执行顺序。此数组中的任何 Feature ID 都将以提供的顺序在所有其他 Features 之前安装。例如:
"features": {
"ghcr.io/devcontainers/features/java:1",
"ghcr.io/devcontainers/features/node:1",
},
"overrideFeatureInstallOrder": [
"ghcr.io/devcontainers/features/node"
]
默认情况下,Features 将以实现工具确定的最佳顺序安装在基础镜像之上。
如果 Feature 的 devcontainer-feature.json
或用户的 devcontainer.json
中提供了以下任何属性,则会遵循这些属性指示的顺序(优先级递减)。
- 用户
devcontainer.json
中的overrideFeatureInstallOrder
属性。允许用户控制其 Features 的执行顺序。 - 定义为 Feature
devcontainer-feature.json
一部分的installsAfter
属性。
您可以在规范中阅读有关 Feature 执行和安装顺序的更多信息。
还有什么新功能?
除了新的 Features 存储库,我们最近还开源了一个新的 devcontainers/images 存储库,我们在此托管了先前在 vscode-dev-containers 存储库中的一组特定镜像。
我们正在制定开发容器模板(我们在 vscode-dev-containers 中将其称为“定义”)的社区分发计划,我们预计它将类似于 Features。我们将在 vscode-dev-containers 存储库中发布更新,就像我们宣布新的 Features 和镜像存储库时所做的那样。
我如何了解更多信息?
这篇博文只是触及了 Features 强大功能的皮毛,我们很高兴您能尝试一下!
如上文内容中链接所示,了解 Features 的构成以及如何分发它们的最佳位置是开发容器规范中的 Features 和 Features 分发 页面。
我们期待您在使用、创建和发布 Features 时的反馈——我们很乐意在 Features 和 Features 分发 的问题提案中听到它们如何为您服务。
如果您有兴趣参与整个规范或连接其他工具以利用它,请查看开发容器的 规范 和 CLI 存储库。
祝您开发容器创建愉快,编码愉快!
Brigit Murtaugh, @BrigitMurtaugh