,

macOS 和 Windows 上的 Dev Containers 功能支持

上个月,我们改进了 Podman 对 Windows 上 Dev Containers 的支持。Dev Containers 是一种流行的容器化开发规范,正在成为一种标准。在这篇博文中,我们将回顾 Dev Containers 中“功能”的概念,以及 Podman 当前如何在不同的操作系统上支持它。

开发容器

开发容器 https://containers.dev/,也称为 Dev Containers,是**一种用于指定容器化开发环境的文件格式**。使用 devcontainer.json 文件,团队可以声明构建和运行项目的工具和配置。它可以在项目的 git 仓库中进行版本控制,因此任何人都可以在几秒钟内启动一个开发环境。唯一的要求是容器引擎,如 Docker 或 Podman。

微软创建了这个标准。Visual Studio Code、JetBrains IDEs、以及许多其他工具都支持它

Dev Containers 镜像

微软维护着一个预构建的 dev 容器镜像列表。每个镜像都附带针对特定编程语言或技术栈的开发工具。微软预构建镜像的列表可以在 https://github.com/devcontainers/images 中找到。例如,用于 Go 开发的镜像是 ghcr.io/devcontainers/templates/go。

{
    "image": "mcr.microsoft.com/devcontainers/go"
}

这些镜像针对特定语言预定义了一组工具。然而,现实世界的项目需要更多东西。可以使用自定义镜像来代替微软预构建的镜像,但**Dev Containers 功能是一种流行的自定义 Dev Containers 的方式。**

Dev Containers 功能

功能是可以包含在镜像之上的额外工具,可用功能的列表(官方和社区支持)发布在这里:https://containers.dev/features。在以下示例中,batspandocpre-commitshellcheckmodern-shell-utilsskopeo 等工具被添加到微软 Go 镜像的工具中

{
   "image": "mcr.microsoft.com/devcontainers/go",
   "features": {
       "ghcr.io/edouard-lopez/devcontainer-features/bats:0": {},
       "ghcr.io/rocker-org/devcontainer-features/pandoc:1": {},
       "ghcr.io/prulloac/devcontainer-features/pre-commit:1": {},
       "ghcr.io/marcozac/devcontainer-features/shellcheck:1": {},
       "ghcr.io/mikaello/devcontainer-features/modern-shell-utils:2": {},
       "ghcr.io/jsburckhardt/devcontainer-features/skopeo:1": {}
    }
}

功能也是基于容器的,并且与镜像不同,它们在开发环境启动时构建。

功能内部结构和额外构建上下文的用法

功能的安装方式很特别;我们将在下面详细说明。这将有助于澄清 Podman 如何支持它们。 
功能以 OCI 工件的形式分发,类型为“application/vnd.devcontainers”。当 Devcontainer 启动时,例如使用 VisualStudio Code,OCI 工件会被拉取,并且安装脚本会被提取到一个本地文件夹中(这是 skopeo 功能的安装脚本的外观)。

$ skopeo inspect --raw docker://ghcr.io/jsburckhardt/devcontainer-features/skopeo:1 | jq
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.devcontainers",
    "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "size": 0
  },
...
}

Dev Container 启动的下一步是构建自定义镜像。这是根据 devcontainer.json 镜像动态完成的(在上面的示例中是 `mcr.microsoft.com/devcontainers/go`),并执行功能安装脚本。以下是一个(简化)的构建 Dev Container 自定义镜像的 Dockerfile 示例

FROM mcr.microsoft.com/devcontainers/go

COPY --from=features-context /tmp/build-features/ /tmp/dev-container-features

RUN cd /tmp/dev-container-features/skopeo_3 \
 && chmod +x ./devcontainer-features-install.sh \
 && ./devcontainer-features-install.sh

这里有趣的部分是 COPY –from 指令。它使用额外的构建上下文 feature-context,而不是默认上下文。文件夹 tmp/build-features/ 存在于构建上下文 feature-context 中。这是一种巧妙的方式,可以隔离 Dev Container 镜像的构建上下文和功能文件夹,以避免冲突问题(例如,构建上下文子文件夹和功能文件夹可能具有相同的名称)。

这意味着要支持 Dev Containers 功能,容器引擎需要支持额外的构建上下文。

Podman 对额外构建上下文的支持

额外的构建上下文 是一个比较新的功能。它们在 Podman v4.2 和 Buildah v1.26 中引入。

podman build \
     --build-context context=./alt-ctx \
     ./main-ctx

当 podman 在本地运行时,额外构建上下文的当前实现效果很好。但当 podman 在远程机器上运行时就不是这样了。实际上,与主构建上下文不同,额外的上下文不会发送到远程机器,并且构建会失败,因为额外构建上下文的本地路径在远程机器上不存在。

这是一个令人讨厌的限制,希望很快能得到解决。但目前,Podman Machine 可以通过一些默认约定来支持额外的构建上下文(和 Dev Containers 功能)。

Podman Machine 支持额外构建上下文的默认约定

首先,Podman Machine 将一些默认文件夹挂载到访客操作系统中。

LinuxmacOSWindows
主机路径访客路径主机路径访客路径主机路径访客路径
$HOME$HOME/Users/UsersC:\/mnt/C
/private/private
这意味着如果额外的构建上下文在挂载的主机路径中,它也存在于 Podman Machine 中 🎉。

其次,Windows 主机路径(例如 `C:/Users/user1`)会自动转换为 Linux 访客路径(例如 `/mnt/c/Users/user1`)。Windows 的 Podman 客户端在挂载卷时也会使用这种技巧(例如 `podman run -v C:/Users/user1`)。

📝 这些约定在 Podman 5.3.0 开始支持 Windows WSL(对于 Hyper-V 有一个单独的问题)。

下表总结了当前不同操作系统上对 Dev Containers 功能(和额外构建上下文)的支持。

Linux 本地Linux 远程macOS (vfkit)macOS (libkrun)Windows (WSLv2)Windows (Hyper-V)
🟢🟠🟠🟠
Dev Containers 功能支持

🟢 可用

🟠 使用 Podman 机器默认配置可用

尚不可用

嵌套:使用 Podman 支持的 Dev Container 构建 Podman

现在 Podman 对 Dev Containers 功能有了不错的支持,让我们充分利用它。让我们从源代码构建 Podman 本身!唯一的要求是本地安装

  • Podman
  • devcontainer CLI(带有 Dev Containers 扩展的 VisualStudio Code 也可行)。

安装完这两个要求后,这个简单的 `devcontainer.json` 和 `Dockerfile` 就足够构建 Podman 了。

{
	"name": "podman-devcontainer",
	"build": {
		"dockerfile": "Dockerfile",
		"context": ".."
	},
	"features": {
		"ghcr.io/devcontainers/features/go:1": {}
	},

	"containerEnv": {
		"HOME": "/home/vscode"
	}
}
FROM quay.io/podman/stable
COPY /rpm/podman.spec /rpm/podman.spec
RUN dnf update -y && dnf -y install 'dnf-command(builddep)'
RUN dnf -y \
    builddep /rpm/podman.spec

这两个文件应该复制到 Podman 仓库根目录下的一个名为 `.devcontainer` 的新文件夹中(或者签出我的 Podman 分支的 名为 inception 的分支)。 

在 Podman 仓库根目录的终端中运行以下命令,启动 Dev Container。

$ devcontainer up --docker-path podman --workspace-folder .

然后,可以在 Dev Container 中执行命令 make podman。

$ devcontainer exec --workspace-folder . --docker-path podman \
    make podman

或者,可以使用 VisualStudio Code 启动相同的 Dev Container。

截图

📝 运行 Podman Makefile 的其他 make 目标可能会失败。这可能与 Dev Container 中缺少一些工具或 Podman Machine 资源不足(RAM 和 CPU)有关。无论哪种方式,这个 `devcontainer.json` 都应该很容易改进。

发表评论

订阅

使用您的电子邮件地址注册,以接收来自此网站的电子邮件更新。


分类


搜索