在 DevContainer 中构建并运行 Podman Desktop
GitHub 上周宣布 Codespaces 已对所有人开放,并提供免费时长。
让我们看看如何使用一个 开发容器,其中包含构建和运行 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://#/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
再加上定义一个空的 user namespace。
ENV _CONTAINERS_USERNS_CONFIGURED=""
确保 Podman 会在预期目录中创建 socket。
# 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 部分。
"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
两条指令:
- 获取所有 Node.js 依赖项。
- 使用
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 完全可用时,我们希望有一种快速打开 Website rendering URL
和 noVNC
的方法。
让我们通过添加 portsAttributes
部分来调整 devcontainer.json
文件。
"portsAttributes": {
"9000": {
"label": "vnc",
"onAutoForward": "openPreview"
},
"3000": {
"label": "website"
}
}
完成所有创建后步骤后,VS Code 编辑器中的“预览”浏览器将打开一个 VNC 窗口。另一个端口 (3000
) 被标记为网站端口。
在 Github Codespace 上使用 DevContainer.json
作为用户,只需单击一下即可打开我们配置的所有工作区。
前往 https://github.com/containers/podman-desktop,然后点击 < > Code
下拉菜单,再点击 Create codespace on main
按钮。
单击按钮后,codespace 正在设置中。
几分钟后,由于还没有 预构建的 codespaces,codespace 就会打开。
简单的浏览器显示 noVNC 窗口:
点击连接按钮。然后在终端中输入 podman run quay.io/podman/hello
,容器就会在 Podman Desktop 中被检测到。
也可以使用端口小部件,通过点击世界图标在另一个标签页中预览端口 3000
的网站。更改网站源代码将刷新窗口内容。
根据用例,也可以在预览浏览器中打开文档。
结论
Podman Desktop 的 DevContainer 镜像很新,所以它可能会随着时间的推移而不断发展,增加新的功能,但它允许您轻松地构建/运行/实验并**贡献**到该工具或网站。