跳至主要内容

在 DevContainer 中构建和运行 Podman Desktop

·阅读时长 8 分钟
Florent Benoit
首席软件工程师

GitHub 上周宣布,Codespaces 现已向所有人开放,并提供免费分钟数。

让我们看看如何使用一个 开发容器 来构建和运行 Podman Desktop,该容器包含构建和运行 Podman Desktop 的所有工具。开发容器在本地使用 Visual Studio Code 运行,但在本博文中,我们将看到它如何通过 GitHub 的简单点击直接运行。

挑战在于运行一个桌面工具(Podman Desktop)和一个容器引擎(Podman),而不会占用太多内存!

定义容器的映像

首先是选择容器的映像。可以选取一个默认映像并添加一些功能,但 https://github.com/devcontainers/features/tree/main/src 上没有现有的 Podman 功能,并且大多数功能都希望在 Debian/Ubuntu 之上运行。

如果您对如何设置映像不感兴趣,请跳到 下一节

Podman 二进制文件在 Fedora 发布后很快就会可用。因此,我决定使用 `Fedora 37` 作为基础映像。

让我们使用以下内容开始 Containerfile:

FROM quay.io/fedora/fedora:37

然后我从官方的 nodejs.org 存储库安装 Node.js 16。这样可以更容易地切换到我们需要的版本。

# install Node.js + yarn
ENV NODE_VERSION 16.18.1
RUN curl -SLO "https://node.org.cn/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" && \
tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 && \
rm "node-v$NODE_VERSION-linux-x64.tar.gz" && \
npm install -g yarn

现在,需要安装所有运行 Electron 应用程序所需的系统依赖项。

Podman 也已安装,因此我们可以在这个容器中运行一些容器。

当然,我们还需要安装 VNC(我选择 tigervnc)和一个轻量级的窗口管理器(fluxbox)。

为了连接到容器的显示器,我们需要使用 noVNC 通过 HTML/websocket 公开 VNC。

安装 xterm 以从 VNC 端启动终端。

RUN dnf -y update && \
yum -y reinstall shadow-utils && \
yum install -y git \
# dependencies for Podman Desktop
nss \
atk \
at-spi2-atk \
cups-libs \
gtk3 \
# for remote Display
fluxbox \
tigervnc-server \
xorg-x11-fonts-Type1 \
novnc \
supervisor \
xdpyinfo \
# for podman
podman \
fuse-overlayfs --exclude container-selinux \
xterm && \
rm -rf /var/cache /var/log/dnf* /var/log/yum.*

Supervisord 设置 VNC 服务器和窗口管理器的启动。

COPY supervisord.conf /etc/supervisord.conf

fluxbox 的自定义主题

COPY fluxbox /usr/share/fluxbox/init

然后我们需要一个特殊的配置,以允许 Podman 在容器中运行。

我们在运行容器时使用正确的 subuid 和 subgid 范围添加了 `podman-desktop` 用户。我使用了 教程

RUN useradd -u 1000 podman-desktop && echo podman-desktop:10000:5000 > /etc/subuid && echo podman-desktop:10000:5000 > /etc/subgid

然后使用一些默认的配置文件

# initialize conf files
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman-desktop/.config/containers/containers.conf

并确保所有权限都正确,请遵循以下指南 https://www.redhat.com/sysadmin/podman-inside-container

# set permissions
RUN chown podman-desktop:podman-desktop -R /home/podman-desktop && chmod 644 /etc/containers/containers.conf && \
mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock && \
mkdir -p /run/user/1000 && chown podman-desktop:podman-desktop /run/user/1000

以及定义一个空的用户命名空间。

ENV _CONTAINERS_USERNS_CONFIGURED=""

确保 Podman 将套接字创建在预期的目录中。

# socket path for podman
ENV XDG_RUNTIME_DIR=/run/user/1000

好的!我们有一个自定义的 Containerfile,它提供了构建和运行 Podman Desktop(使用 VNC 进行显示)、运行 Podman 和运行 Electron 的所有工具。

当前文件位于 https://github.com/containers/podman-desktop/blob/main/.devcontainer/.parent/Containerfile

让我们配置 DevContainer。

使用 devcontainer.json 配置 DevContainer

DevContainer 定义存储在 `devcontainer/devcontainer.json` 文件中。

我们需要重用上一步中的映像。为此,让我们使用 `devcontainer.json` 文件的构建部分。

"build": {
"dockerfile": "Containerfile"
},

为了避免每次使用此开发容器打开工作区时都重新执行所有构建步骤,我们将映像发布到 quay.io,地址为 quay.io/podman-desktop/devcontainer-parent:next 。此父映像变化不大,因此最好将其用作父映像。

在 `devcontainer` 目录中有一个 `.parent` 目录,其中包含与父映像相关的所有内容。

而在 `devcontainer/Containerfile` 文件中,我们引用了此映像。

FROM quay.io/podman-desktop/devcontainer-parent:next

默认情况下,我们将在容器中是 `root` 用户,这可能不是我们所期望的。让我们更改一下。

"containerUser": "podman-desktop"

一些 Visual Studio Code 扩展使用起来很方便,我们可以添加它们。

  "extensions": ["svelte.svelte-vscode", "bradlc.vscode-tailwindcss"]

然后是棘手的部分,如何运行我们的容器,允许在容器中再次使用 podman 运行一些容器。

我们指定了使之成为可能的参数。可以使用 `--privileged` 标志,但我更喜欢列出权限的子集。使用 `--privileged` 我们并不知道需要哪些权限,而指定了所有权限,人们就会知道授予/拒绝了哪些权限。

"runArgs": [
"--cap-add=sys_admin",
"--security-opt",
"seccomp=unconfined",
"--device",
"/dev/fuse",
"--security-opt",
"label=disable",
"--security-opt",
"apparmor=unconfined"
],

Podman Desktop 的源代码需要在 DevContainer 中可编辑,因此需要将其挂载。

"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
"workspaceFolder": "/workspace",

然后我们需要一个命令来构建 Podman Desktop。

为此,我们使用 `onCreateCommand` 钩子,并使用一个自定义命令

"onCreateCommand": "${containerWorkspaceFolder}/.devcontainer/onCreateCommand.sh",

而在 `devcontainer` 文件夹中,`onCreateCommand.sh` 脚本如下所示:

#!/bin/sh
yarn

MODE=production yarn run build && yarn run electron-builder build --linux --dir --config .electron-builder.config.cjs

两个指令:

  1. 获取所有 Node.js 依赖项。
  2. 使用 `Linux` 作为目标操作系统,在 `dist` 文件夹中构建 Podman Desktop。

容器启动后,如何启动 Podman Desktop、网站和 VNC 等?

只需使用 `postStartCommand` 钩子即可。

"postStartCommand": "${containerWorkspaceFolder}/.devcontainer/postStartCommand.sh",

而在 `devcontainer` 文件夹中,`postStartCommand.sh` 脚本如下所示:

#!/bin/sh

# Start all services
/usr/bin/supervisord -c /etc/supervisord.conf &

# wait X server to be ready or after 2mn exit
echo "Waiting for X server to be ready"
timeout 120 bash -c 'until xdpyinfo -display :0 &> /dev/null; do printf "."; sleep 1; done'

# launch podman desktop
echo "Launching Podman Desktop"
cd dist/linux-unpacked/&& ./podman-desktop &

# Launch the 9000 redirect after 20 seconds
sleep 20
websockify --web=/usr/share/novnc localhost:9000 localhost:5900 &

# launch the website rendering
echo "Launching Website"
cd website && yarn start

它启动 VNC 和 noVNC,启动预编译的 Podman Desktop 并启动文档渲染。

它不会启动 Podman Desktop 的监视模式/开发模式,因为它需要一个内存超过 8GB 的容器。

选择一个更大的实例,例如 16GB,可以使用开发模式。

当然,为了让 VNC 正常工作,我们需要指定 `DISPLAY` 环境变量。

"remoteEnv": {
"DISPLAY": ":0"
}

当 DevContainer 完全可用时,我们希望有一种方法可以快速打开 `网站渲染 URL` 和 `noVNC`。

让我们调整 `devcontainer.json` 文件,添加 `portsAttributes` 部分。

"portsAttributes": {
"9000": {
"label": "vnc",
"onAutoForward": "openPreview"
},
"3000": {
"label": "website"
}
}

在所有后创建步骤之后,VS Code 编辑器中的 `预览` 浏览器将打开一个窗口以显示 VNC。另一个端口(`3000`)将被标记为网站。

在 Github Codespace 中使用 DevContainer.json

作为用户,使用我们配置的所有内容打开工作区只需单击一下。

转到 https://github.com/containers/podman-desktop,然后单击 `< > 代码` 下拉菜单,再单击 `在 main 上创建 codespace` 按钮。

Open Codespace

单击该按钮后,codespace 将开始设置。

Preparing Codespace

几分钟后,由于还没有 预构建的 codespaces,codespace 将打开。

简单的浏览器将显示 noVNC 窗口:Opening Codespace

单击连接按钮。然后在终端中,您可以输入 `podman run quay.io/podman/hello`,Podman Desktop 中将检测到该容器。 Testing Codespace

还可以使用端口小部件通过单击地球图标在 `3000` 端口上获取另一个选项卡中网站的预览。更改网站的源代码将刷新窗口的内容。

根据用例的不同,还可以将文档打开在预览浏览器中。

Edit website Codespace

结论

Podman Desktop 的 DevContainer 映像是最近发布的,因此可能会随着时间的推移而不断发展,添加新的功能,但它可以让您轻松构建/运行/试验并贡献该工具或网站。