惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
Help Net Security
Help Net Security
P
Privacy International News Feed
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
AWS News Blog
AWS News Blog
K
Kaspersky official blog
A
Arctic Wolf
Latest news
Latest news
T
Threat Research - Cisco Blogs
L
LINUX DO - 最新话题
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
月光博客
月光博客
N
News and Events Feed by Topic
Jina AI
Jina AI
博客园 - 司徒正美
WordPress大学
WordPress大学
罗磊的独立博客
雷峰网
雷峰网
AI
AI
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Security @ Cisco Blogs
博客园 - 三生石上(FineUI控件)
H
Heimdal Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cisco Blogs
博客园 - 【当耐特】
The Hacker News
The Hacker News
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Schneier on Security
Schneier on Security
博客园 - Franky
S
SegmentFault 最新的问题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cloudbric
Cloudbric
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Last Week in AI
Last Week in AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Google DeepMind News
Google DeepMind News

陈陈菌博客

如何在 podman 容器内使用 systemd 管理 podman 容器与镜像的导入或导出 用 xdg-dbus-proxy 解决容器的文件选择器的问题 解决 VSCodium 或 Code-Server 无法安装 GitHub Copilot 问题 不可变发行版 Fedora Silverblue 的体验记录 解决 apt 或 dnf 无法 tab 补全的问题 对 (MPA) 多页面切换实现丝滑动画的探索 让服务在非 Root 权限下使用 80 或 443 端口 AppImage 应用打包快速上手 Flatpak 使用和应用打包快速上手 如何用 webSocket 实现一个实时聊天应用 Linux 内核编译 | 快速上手 | deb 使用 debootstrap 构建 Debian 系根文件系统 高度可定制的 KDE 窗口装饰器 klassy 有关 docker、podman、nspawn、bwrap 的 Linux 容器图形性能测试 创建任意 Linux 容器并支持 GUI 程序 (Docker) 创建任意 Linux 容器并支持 GUI 程序 (nspawn) 文件同步工具 rsync 的使用 玲珑 (Linyaps) 应用打包 RPM 打包指南 | 精简版 PBR 材质的各种贴图类型入门 APU | Stable-Diffusion 使用记录 如何在 Electron 上启用 WebGPU Grub 主题安装与配置 Fcitx5 主题安装与自定义 不使用 Nginx 的网站开发指南 如何自制一个简易的资源监控程序 SQL 常用 CRUD 语法记录 Debian 打包入门,与需要注意的问题 在 fedora 建立一个 Arch 容器 (bwrap) 在 fedora 上建立一个 debian 容器 (bwrap) i3wm | 自制一个极简的屏幕亮度调节器 在 Linux 下启用内存压缩技术 zram 搭建一个本地轻量级聊天 Ai 我又又又重新上线了博客 如何通过命令行管理 wine 容器 (包括 proton) Btrfs 文件系统创建 swap 文件的方法 如何创建适用于 Linux 桌面的程序启动文件 在 Linux 控制 intel CPU 调度的方法 Arch Linux 的基本安装
在 podman 运行 GUI 应用的经验总结
GlumiStudio@ · 2026-06-02 · via 陈陈菌博客

toolbox 和 Distrobox 不好定制?那就自己来吧。

2026-06-02 16:13:11

分类: Linux 标签: 容器


尝试过了很多容器方案,如 toolbox、bwrap、systemd-nspawn、docker、以及 Distrobox,发现都各有优势和缺点,像 toolbox 和 distrobox 是比较好上手的一种,但他们因为过于开箱即用默认挂载宿主很多东西(如 home/user ),有时不太好定制,此时我就得从更基础的 podman 开始定制。

先上完整脚本:

create_box.sh

#!/bin/bash
xhost +local:

PROXY_SOCKET="$XDG_RUNTIME_DIR/podman-bus-proxy"

podman run -it \
--dns "8.8.8.8" \
--env DISPLAY="$DISPLAY" \
--env XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
--env PULSE_SERVER="unix:$XDG_RUNTIME_DIR/pulse/native" \
--env DBUS_SESSION_BUS_ADDRESS="unix:path=$PROXY_SOCKET" \
--env XMODIFIERS="@im=fcitx" \
--env QT_IM_MODULE="fcitx" \
--env GTK_IM_MODULE="fcitx" \
--env WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
--volume /tmp/.X11-unix:/tmp/.X11-unix:ro \
--volume /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:ro \
--volume $XDG_RUNTIME_DIR:$XDG_RUNTIME_DIR:z \
--device /dev/kfd:/dev/kfd \
--device /dev/dri:/dev/dri \
--volume /run/udev:/run/udev:ro \
--volume /dev/shm:/dev/shm \
--volume /dev/input:/dev/input:ro \
--volume /etc/resolv.conf:/etc/resolv.conf:ro \
--network host \
--hostname $1 \
--name $1 \
--user root \
--group-add render \
--group-add video \
--group-add input \
--privileged \
--security-opt seccomp=unconfined \
--security-opt label=disable \
--userns=keep-id \
$2 \
/bin/bash

create_proxy.sh

xhost +local:

# 1. 在 XDG_RUNTIME_DIR 下生成一个代理 socket 路径
PROXY_SOCKET="$XDG_RUNTIME_DIR/podman-bus-proxy"

if [ -e "$PROXY_SOCKET" ]; then
    echo '已经存在'
else
    # 2. 启动 xdg-dbus-proxy,开启过滤:只放行 fcitx xdg-open 相关的通信,拦截其他所有服务(如 Portal)
    xdg-dbus-proxy "unix:path=$XDG_RUNTIME_DIR/bus" "$PROXY_SOCKET" \
        --filter \
        --own=org.fcitx.* \
        --talk=org.fcitx.* \
        --talk="org.freedesktop.Notifications" \
        --call="org.freedesktop.portal.Desktop=org.freedesktop.portal.OpenURI.*@/org/freedesktop/portal/desktop" &
    PROXY_PID=$!
fi

一般我会通过 create_box.sh <容器名> <镜像名> 来创建一个 podman 容器,

再通过 create_proxy.sh 建立一个 $XDG_RUNTIME_DIR/bus 的代理(为什么要这样呢?因为可以自己过滤哪些需要的通信,通常每次进入系统只需要执行一次)

而基础发行版镜像可以随便选,如 ubuntu、fedora、Arch、Debian 随便你,我们都知道 podman 可以使用 docker hub 的镜像,所以你可以直接 podman pull docker.io/library/debian 之类的。

跑完 create_box.sh 后此时就会就可以用这个容器了。你可以在 podman ps -a 可以查看到。

以后管理容器也非常简单:

启动:podman start <容器>

停止:podman stop <容器>

执行程序:podman exec -it <容器> <命令行>

podman 一些基础命令就不细说了,可以自行了解。

下面我们聊以上脚本都干了什么。(其中有很多都是根据自己需求来决定的可选项,并不是必须)

create_box.sh 脚本

(1) 有关 xhost +local:


允许本地用户(UID 相同或者 root)访问 X server(显示图形界面)。这是 X11 的授权机制。

(2) PROXY_SOCKET="$XDG_RUNTIME_DIR/podman-bus-proxy"


$XDG_RUNTIME_DIR 通常是 /run/user/1000,是每个用户的运行时目录。 PROXY_SOCKET 我指向了一个自定义的 D-Bus 通信代理,防止容器直接访问宿主的 D-Bus(通常是 /run/user/1000/bus),增加安全性。这里会跟 create_proxy.sh 脚本有联动。

(3) 运行图形应用


通常需要加入 $DISPLAY$WAYLAND_DISPLAY 变量、透传 /tmp/.X11-unix、以及 $XDG_RUNTIME_DIR/dev/dri,主要是为了保证容器里的 x11/wayland GUI 能显示在宿主的屏幕上。

这里 /dev/dri 为了用于 GPU 加速

x11 应用通常走 /tmp/.X11-unix

wayland 应用通常是 $XDG_RUNTIME_DIR/wayland-0

这里我整个映射 $XDG_RUNTIME_DIR 主要是为了省事,因为后续还有很多通信需要走这里。

(4) 中文输入法


通常我们需要容器也拥有相关变量,并且在容器内也安装了 fcitx5 框架下,可以在容器内调用宿主的 fcitx5(前提是必须有透传 $XDG_RUNTIME_DIR 相关)

--env XMODIFIERS="@im=fcitx" \
--env QT_IM_MODULE="fcitx" \
--env GTK_IM_MODULE="fcitx" \

(5) 系统级 dbus /run/dbus/system_bus_socket


Linux 下 dbus 有两种通讯方式,一种是 /run/user/1000/bus(当前登录用户的通信), 还有就是这个 /run/dbus/system_bus_socket,它允许容器访问宿主整个系统范围的的服务通信,如果配合 --privileged 权限非常高。

在容器只需要这样就能控制宿主关机:

busctl --system call \
  org.freedesktop.login1 \
  /org/freedesktop/login1 \
  org.freedesktop.login1.Manager \
  PowerOff b true

(6) /dev/kfd


如果你是 amd 的硬件,并且可能需要用到 rocm 之类的东西,这个是必须要的,用于 GPU 计算。

(7) /run/udev


在某些情况下,我们需要读取宿主的设备信息,几乎是必须的。

(8) /dev/shm


用于共享内存,x11 或 浏览器缓存这块很有用。

(9) /dev/input


输入设备(键盘、鼠标、触摸板)等的访问

(10) --network host


使用宿主网络, /etc/resolv.conf :只是为了 DNS,保证容器可以正常解析域名

(11) PULSE_SERVER 相关


为了能听到声音,必须得把 unix:$XDG_RUNTIME_DIR/pulse/native 弄进容器。

(12) 用户和权限


--user root \
--group-add render \
--group-add video \
--group-add input \
--privileged \
--security-opt seccomp=unconfined \
--security-opt label=disable \
--userns=keep-id \

这里的权限取决于自己的需求。

  • --user root:容器内使用 root 用户。
  • --group-add ...:添加 GPU / 视频 / 输入设备访问权限。
  • --privileged:打开所有权限(几乎等于 root 宿主)。
  • --security-opt seccomp=unconfined:关闭 seccomp 限制,允许系统调用。
  • --security-opt label=disable:关闭 SELinux 标签限制。
  • --userns=keep-id:保持宿主 UID/GID 对应,防止权限错乱。

create_proxy.sh

这个脚本是我最初是为了 启动 D-Bus 代理,限制容器能访问的服务。使用 xdg-dbus-proxy 的方式来实现。

  • --filter:启用访问控制
  • --own=org.fcitx.*:允许容器注册和使用 fcitx
  • --talk=org.fcitx.*:允许容器访问 fcitx
  • --talk=org.freedesktop.Notifications:允许容器使用桌面通知功能
  • --call=org.freedesktop.portal.Desktop=org.freedesktop.portal.OpenURI.*@/org/freedesktop/portal/desktop:允许 xdg-open 调用,通常用于容器应用打开链接时让宿主的浏览器进行目标跳转

最后在每个容器中 /usr/local/bin/xdg-open 我用了自定义的 xdg-open :

#!/bin/bash

# 获取 URL 参数
URL="$1"

# 检查是否为空
if [ -z "$URL" ]; then
    echo "Usage: xdg-open <url>"
    exit 1
fi

# 补全协议(如果是 blog.glumi.cn 这种,补全为 http)
if [[ ! "$URL" =~ ^[a-zA-Z0-9]+:// ]]; then
    URL="http://$URL"
fi

# 核心:通过 D-Bus 调用宿主机的 Portal 接口
# 这里我们使用 busctl,它是 systemd 自带的,通常容器里都有
busctl --user call \
    org.freedesktop.portal.Desktop \
    /org/freedesktop/portal/desktop \
    org.freedesktop.portal.OpenURI \
    OpenURI "ssa{sv}" "" "$URL" 0

关于容器应用在宿主桌面上的快捷入口

总是通过命令行启动程序多少会有点麻烦,所以可以将一些容器应用的启动写成 .desktop 文件

通常写在 /usr/share/applications/~/.local/share/applications/

[Desktop Entry]
Version=1.0
Type=Application
StartupWMClass=hello
Terminal=false
Exec=podman exec .....
Name=Name of Application
Icon=/path/to/icon

其中 Exec 是所执行的程序地址(可以包含参数), Terminal 指明是否在执行一个终端程序, Name 也就是该应用程序的名称, version 版本号,Icon 应用程序图标,StartupWMClass 通常是窗口的类名(有时定位应用很有用,一些桌面环境dock栏识别图标会认这个)

关于 wayland / x11

上面我的脚本采用了两种混用方式,如果 wayland 应用跑不起来,也许你需要在启动程序加入 GDK_BACKEND=x11 变量来回退以 x11 方式启动。

在某些情况下,可能还需要将 $WAYLAND_DISPLAY 变量设置为空