自定义开发容器特性(Features)
2022年9月15日,作者:Brigit Murtaugh,@BrigitMurtaugh
我们都曾有过这样的经历:在设置开发环境时突然意识到——“哦,我还需要一样东西!”——而这个“东西”可能是为了项目工作而需要的一种(或者几种😊)语言或工具集。
开发容器(Development containers)是简化环境设置的绝佳方式——它们提供了一个完整的编码环境,其中包含您的项目所需的所有工具。它们通过镜像、Dockerfile 或 Docker Compose 文件以及 devcontainer.json
进行配置,后者是一种元数据格式,用于通过开发特定的内容和设置来丰富容器。
在创建开发容器时,您可能会反复遇到同样的“我还需要一样东西!”的反应——也许您在 Dockerfile 中使用了 Node.js 镜像,但还需要添加 Git。或者,您可能需要添加更复杂的东西,比如在您的开发容器中处理 Docker 或 Kubernetes。开发容器的优点在于,任何访问您的代码的人都将获得与您添加的所有工具一致的体验——但是,添加这些工具的最佳方式是什么呢?
如果有一种简单的方法,只需提及工具的名称和版本,就能在您的开发容器中安装额外的工具,那该怎么办?或者,如果您作为工具用户或作者,可以为他人创建一种简单的方式来安装它,那该怎么办?共享手动脚本有助于重复使用,但引用脚本时,您可能会忘记引用容器或工具设置,例如为 Go、Rust 或 C++ 调试启用 ptrace 支持,在容器启动时添加特定的入口点,或者确保包含正确的 VS Code 扩展。
功能
我们很高兴地宣布,开发容器的特性(Features)可以帮助您顺利地在开发容器中获取所需的工具!
特性是自包含的安装代码、容器配置和/或设置及扩展单元,旨在为您的开发容器提供新的开发能力。它们可以构建为与各种基础容器镜像配合使用。作为我们开放开发容器规范工作的一部分,我们对预创建的特性(Features)的获取方式以及如何编写和分发您自己的特性(Features)进行了一些改进。
让我们看看有什么新功能,以及如何从任何支持开发容器的工具或服务(例如 VS Code 开发容器(Dev Containers)扩展或 GitHub Codespaces)开始使用特性!
将特性添加到您的开发容器
开发容器特性提供了一种将开发容器元数据与一些安装步骤关联起来的快速方法。您可以通过简单的引用将它们添加到您的开发容器中。
这些特性现在可以作为 OCI 工件存储在任何支持的容器注册表中,这意味着您可以使用与引用容器镜像相同的标识符类型来引用它们。我们已将 vscode-dev-containers 存储库中的一些早期特性移到一个新的 devcontainers/features 存储库中,并使用这种新方法发布它们。
引用 devcontainers/features 存储库中的不同特性就像在您的 devcontainer.json
中添加一个 features
属性一样简单。每个特性都有一个 README.md
,其中显示了如何引用该特性以及可用的选项。
下面的示例安装了 go 和 docker-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 开发容器扩展中可用的体验)添加公开发布的特性。
您甚至可以使用 dev container CLI、GitHub Actions 或 Azure DevOps 任务,从您最喜欢的 CI 系统中使用带有特性的开发容器。我们在 devcontainers/ci 存储库中提供了 GitHub Actions 和 Azure DevOps 任务。dev container CLI、GitHub Actions 或 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.json
、install.sh
和目录中的任何其他文件。
开放容器倡议 (OCI) 定义了容器和容器资源的行业标准。我们将特性视为 OCI 工件,并使用 OCI 注册表的概念来分发特性。
上面提到的 特性模板 存储库包含一个 GitHub Actions 工作流,用于自动化发布过程。它将特性打包成 tarball,并将资产作为 OCI 工件发布到 GHCR。通过在 GitHub 存储库的 Actions 选项卡左侧选择 release.yaml
工作流,可以触发模板存储库中的此工作流。GitHub Actions 会将特性发布到 <owner>/<repo>
命名空间下的 GHCR。只有当其 devcontainer-feature.json
中的版本属性更新时,特性才会被重新发布。
注意:GHCR 有一个手动步骤,就是将 OCI 包标记为“public”。这对于每个特性只需要做一次。私有特性不需要此步骤,只要您使用注册表凭据登录了 Docker CLI,就可以访问它们。
与社区共享您的特性
如果您希望您的贡献出现在 VS Code 开发容器或 GitHub Codespaces UI 中进行开发容器创建,您可以执行以下步骤:
- 前往 devcontainers.github.io(支持 containers.dev 的 GitHub 仓库)
- 打开一个 PR 以修改
collection-index.yml
文件
合并后,您的更改将出现在 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
中提供了以下任何属性,则会遵循这些属性指示的顺序(按优先级递减)。
- 用户
devcontainer.json
中的overrideFeatureInstallOrder
属性。允许用户控制其特性的执行顺序。 - 作为特性
devcontainer-feature.json
的一部分定义的installsAfter
属性。
您可以在规范中阅读有关特性执行和安装顺序的更多信息。
还有什么新功能?
除了新的特性存储库,我们最近还开源了一个新的 devcontainers/images 存储库,其中托管了以前在 vscode-dev-containers 存储库中的特定镜像集。
我们正在为开发容器模板(我们在 vscode-dev-containers 中称之为“定义”)制定社区分发计划,我们预计它将类似于特性。我们将确保在 vscode-dev-containers 存储库中发布更新,就像我们宣布新的特性和镜像存储库时所做的那样。
我如何了解更多信息?
这篇文章只触及了特性功能的皮毛,我们很高兴您能尝试它们!
正如上文内容中链接的那样,了解特性构成以及如何分发的最佳位置是开发容器规范的特性和特性分发页面。
我们期待您在使用、创建和发布特性时的反馈——我们很乐意在 特性和特性分发问题提案中听到它们对您的工作有何帮助。
如果您有兴趣参与整个规范或连接其他工具以利用它,请查看开发容器的规范和CLI存储库。
祝您开发容器创建愉快,编码愉快!
Brigit Murtaugh, @BrigitMurtaugh