老旧Linux系统借助Docker运行新版GUI应用

前言

在工作中,我们有时会遇到这样的困境:所用的 Linux 系统版本较老,许多新的软件包无法安装和使用,但受限于公司的统一管理要求,又不能升级或更换系统。

面对这种情况,Docker 就是一个很好的解决方案——在容器中运行一个较新的 Linux 发行版(如 Ubuntu 24.04),在其中安装所需的软件,然后通过 X11 转发将 GUI 界面显示到宿主机的桌面上,实现「无缝使用」的效果。

有人可能会问:这不就是 Distrobox 干的事吗?没错,Distrobox 封装了 Docker 的各种复杂操作,专门用于在容器中运行本地 GUI 应用。但遗憾的是,在一些过于老旧的系统上,Distrobox 本身也无法正常工作(对 Docker 版本和内核特性有一定要求),所以我们只能手动搭建这套环境。

本文将从零开始,记录完整的搭建过程。

环境说明

项目 版本
宿主机系统 Deepin / UOS(基于 Debian)
Docker 18.09.1
docker-compose 1.21.0
容器系统 Ubuntu 24.04

一、安装 Docker

首先安装 Docker 和 docker-compose:

sudo apt install docker.io docker-compose

安装完成后确认版本:

docker --version
# Docker version 18.09.1, build 4c52b90

docker-compose --version
# docker-compose version 1.21.0, build unknown

可以看到版本确实比较老,这也是 Distrobox 无法使用的原因之一。

接下来创建 docker 用户组,避免每次都需要 sudo

# 创建 docker 用户组(已存在则忽略)
sudo groupadd docker 2>/dev/null || true

# 将当前用户加入 docker 组
sudo usermod -aG docker $USER

注意:添加用户组后需要注销并重新登录才能生效。

二、编写 docker-compose.yml

选择一个合适的位置,创建项目目录和配置文件:

mkdir -p ~/docker/ubuntu-24.04
cd ~/docker/ubuntu-24.04
touch docker-compose.yml

在编写配置之前,需要先获取当前用户的 UID家目录路径,后续配置中会多次用到:

id -u
# 例如输出:24035

echo $HOME
# 例如输出:/home/magicdmer

请将下面配置中所有出现 24035/home/magicdmer 的地方替换为你的实际值。

docker-compose.yml 内容如下:

version: '2.3'
services:
  dev:
    image: ubuntu:24.04
    container_name: dev
    network_mode: host       # 与宿主机共享网络栈
    privileged: true          # 授予完整权限(GUI 应用需要)
    restart: unless-stopped

    # ⚠️ 首次启动时请保持注释状态!
    # 原因:全新的 Ubuntu 容器中没有 sudo,而安装 sudo 又需要 root 权限,
    # 所以第一次需要以 root 身份进入容器完成初始化。
    # 初始化完成后,取消下面这行注释即可以普通用户身份运行。
    # user: "24035:24035"

	# 下面两个比较关键,init是给docker环境提供进程回收能力,不然出现一堆僵尸进程。
	# 这两个保证gui程序一直运行不会突然闪退
    init: true
    shm_size: '2gb'

    tty: true
    stdin_open: true

    environment:
      # ---- X11 显示 ----
      - DISPLAY=${DISPLAY}

      # ---- 输入法(fcitx)----
      - GTK_IM_MODULE=fcitx
      - QT_IM_MODULE=fcitx
      - XMODIFIERS=@im=fcitx

      # ---- 音频(PulseAudio)----
      - PULSE_SERVER=unix:/run/user/24035/pulse/native

      # ---- 语言 ----
      - LANG=zh_CN.UTF-8

      # ---- D-Bus 会话总线 ----
      - DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/24035/bus

      # ---- 代理(可选,按需配置)----
      # 如果宿主机运行了代理工具(如 ***),可以通过以下配置让容器也走代理
      - http_proxy=http://127.0.0.1:10800
      - https_proxy=http://127.0.0.1:10800
      - all_proxy=http://127.0.0.1:10800
      - no_proxy=localhost,127.0.0.1,::1

      # ---- 用户家目录 ----
      - HOME=/home/magicdmer

    volumes:
      # 挂载家目录 —— 容器内的应用可以直接访问宿主机的文件
      - /home/magicdmer:/home/magicdmer

      # X11 socket —— 精准挂载,避免整个 /tmp 冲突
      - /tmp/.X11-unix:/tmp/.X11-unix

      # 音频 + D-Bus 运行时目录
      - /run/user/24035:/run/user/24035

      # 用户/用户组信息(只读)—— 让容器内的 UID/GID 与宿主机一致,如果是域用户建议注释
      - /etc/passwd:/etc/passwd:ro
      - /etc/group:/etc/group:ro

      # 时区同步(只读)
      - /etc/localtime:/etc/localtime:ro

    # 保持容器常驻运行
    entrypoint: ["tail", "-f", "/dev/null"]

配置要点解析

  • network_mode: host:容器与宿主机共享网络,省去端口映射的麻烦,也让代理配置更简单。
  • privileged: true:GUI 应用通常需要访问一些特殊设备和资源,privileged 模式可以避免很多权限问题。
  • 挂载 /etc/passwd/etc/group:这是关键优化——直接复用宿主机的用户信息,避免了容器内外 UID 不一致导致的文件权限问题。
  • 挂载 /tmp/.X11-unix:这是 X11 显示服务的 Unix socket 所在目录,是 GUI 转发的基础。
  • initshm_size: 这两个用来保证 gui 程序在本地运行的稳定性,不会运行一段时间后闪退

三、启动容器

# 拉取 Ubuntu 24.04 镜像
docker-compose pull

# 后台启动容器
docker-compose up -d

在宿主机上授权 Docker 容器访问 X11 显示服务:

xhost +local:docker

提示xhost +local:docker 在每次重启宿主机后需要重新执行。可以将其加入 ~/.bashrc 或设置为开机自启。

四、初始化容器环境

以 root 身份进入容器:

docker exec -it dev bash

在容器内依次执行以下操作:

4.1 基础配置

apt update

# 安装 sudo
apt install sudo -y

# 如果没有挂载宿主机的用户信息,需要我们手动添加用户
useradd -u 24035 -d /home/magicdmer -s /bin/bash magicdmer

# 为宿主机用户配置免密 sudo(替换为你的用户名)
echo "magicdmer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/magicdmer

# 切换到普通用户
su magicdmer

# 确认 DISPLAY 变量(没有值则手动设置)
echo $DISPLAY
export DISPLAY=:0  # 如果上一行为空则执行这行

4.2 中文环境

# 安装并生成中文 locale
sudo apt install -y locales
sudo locale-gen zh_CN.UTF-8
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=zh_CN.UTF-8

# 安装中文字体(解决中文显示为方块的问题)
sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei

4.3 D-Bus 与主题

# 安装 D-Bus 相关组件,使容器内应用能与宿主机桌面环境联动
sudo apt install -y dbus-x11 dconf-cli adwaita-icon-theme gnome-themes-extra

4.4 输入法支持

# 安装 fcitx 输入法前端,使容器内应用能调用宿主机的中文输入法
sudo apt install -y fcitx-frontend-gtk3 fcitx-frontend-gtk2 fcitx-frontend-qt5

4.5 验证测试

# 安装一个 GUI 应用进行测试
sudo apt install -y gedit

# 启动测试 —— 宿主机桌面上应该弹出 gedit 窗口
gedit

如果一切正常,你应该能在宿主机桌面上看到 gedit 的窗口,并且可以正常使用中文输入法。

五、创建桌面快捷方式

每次通过命令行启动容器中的应用比较麻烦,我们可以在宿主机上创建 .desktop 快捷方式,实现双击即打开:

[Desktop Entry]
Name=Gedit (Docker)
Comment=文本编辑器(运行在 Docker 容器中)
GenericName=Text Editor
Exec=docker exec -u magicdmer dev gedit
Icon=/usr/share/pixmaps/gedit.png
Type=Application
Categories=Editor;IDE;
Terminal=false

将以上内容保存为 ~/.local/share/applications/docker-gedit.desktop,即可在应用菜单中找到它。

注意Exec不要使用 -it 参数,否则 .desktop 文件无法正常启动应用(-it 是交互式终端参数,桌面启动时没有终端可分配)。

总结

通过以上步骤,我们实现了在老旧 Linux 系统上通过 Docker 运行新版 Ubuntu 24.04 GUI 应用的完整方案。核心原理是:

  1. Docker 容器提供新版本的软件运行环境
  2. X11 socket 挂载实现 GUI 界面转发到宿主机
  3. PulseAudio / D-Bus 挂载实现音频和桌面服务的联动
  4. fcitx 前端实现中文输入法的支持
  5. passwd/group 挂载解决文件权限一致性问题

这套方案虽然不如 Distrobox 那样开箱即用,但胜在兼容性强——只要系统能跑 Docker,就能用这种方式突破系统版本的限制。

posted @ 2026-04-13 18:10  magicdmer  阅读(63)  评论(0)    收藏  举报