View on GitHub

富乎 · 地问


avatar
辗转探寻为富乎?《天问》无解向地问!

<<< 返回主页

一齐来笠飞鼠

1、背景

2、自制一个“鼠”笼——支持图形化(GUI)程序的docker容器

2.1 适用环境

2.2 原理简介

2.3 容器的制法

$ export BAT_IMAGE=ubuntu:22.04 # 或其他版本
$
$ export BAT_CONTAINER=fuck_bat # 或其他名称
$
$ export SHARED_DIR=${HOME}/${BAT_CONTAINER} # 或其他目录
$
$ docker run --name=${BAT_CONTAINER} -ti \
    --cap-add CAP_SYS_ADMIN \
    -v $(realpath ${SHARED_DIR}):$(realpath ${SHARED_DIR}) \
    -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
    -v /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:ro \
    -v /run/user/${UID}:/run/user/${UID}:ro \
    -e DISPLAY=unix${DISPLAY} \
    -e DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS} \
    ${BAT_IMAGE} \
    bash

需要解释几点:

最后,若不想敲一大堆命令,可下载“懒编程秘笈”项目的 scripts/docker_trapbat.sh脚本来执行。

2.4 容器参数的修改(有需要时才使用)

正如前一小节所说,在后续的调试中有可能要根据报错的内容来挂载更多的目录或文件。 若先删除容器,再用前述的命令加上新的挂载目录或文件的选项重新创建容器,还要安装必要的依赖项, 显然费时费力,不值得提倡。更好的做法是修改已有容器的参数,直接增加待挂载的目录或文件, 操作如下:

$ # 获取目标容器的ID
$ export BAT_CONTAINER_ID=$(docker ps -a --no-trunc --filter name="^/${BAT_CONTAINER}$" --format ' ' | awk '{ print $1 }')
$
$ # 关闭docker服务
$ sudo systemctl stop docker.*
$
$ # 打开参数文件并修改,修改前最好先备份一下。
$ # 若要添加挂载目录,可在MountPoints字典增加一个子项;
$ # 若要添加环境变量,可在Env数组增加一个子项。
$ sudo vim /var/lib/docker/containers/${BAT_CONTAINER_ID}/config.v2.json
$
$ # 重新启动docker服务
$ sudo systemctl start docker.service
$
$ # 肉眼检查参数是否修改成功
$ docker inspect ${BAT_CONTAINER}

2.5 宿主系统的配置

$ # 安装X11的访问控制程序
$ sudo apt install x11-xserver-utils
$
$ # 先查看一下允许访问的客户端列表(即白名单)
$ xhost
$
$ # 再将前文创建的docker容器账户加入白名单。
$ # 注意:由于容器是本地网络(即--network=host),所以第二个字段用localuser,
$ #      而第三个字段则是容器的用户名(通常是root),
$ #      其余字段可查阅xhost的使用手册(执行命令:man xhost)。
$ xhost +SI:localuser:root
$
$ # 2024-04-27更新:不推荐使用--network=host(原因见前文),则白名单配置要使用IP。
$ # 注意:以下IP仅作举例,具体以容器内分配到的值为准。
$ xhost +172.17.0.2
$
$ # 检查一下白名单是否已包含刚才所加的账户
$ xhost
$
$ # 最后开启仅白名单可访问的模式
$ xhost -

3、进一步完善“鼠”笼的环境

以下操作均在容器内进行。由于是root用户,命令行提示符也由美元符号$)变成井号#), 但为了与注释前导符(也是#)区分开,还是继续使用$

3.1 换软件源以获取更快的软件包下载速度

$ # 先备份软件源配置文件
$ cp /etc/apt/sources.list /etc/apt/sources.list.original
$
$ # 再换成清华源,读者也可使用阿里云或其他的源
$ sed -i "s/http:\/\/[a-zA-Z0-9.]*ubuntu\.com/https:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list
$
$ # 更新包管理器缓存
$ apt update -y

3.2 配置中文环境

$ # 安装语言包
$ apt install -y language-pack-zh-hans language-pack-zh-hant
$
$ # 设置环境变量
$ export LANG=zh_CN.UTF-8
$ echo "export LANG=zh_CN.UTF-8" >> $HOME/.bashrc
$
$ # 安装常用的中文字体
$ apt install -y fonts-wqy-microhei fonts-wqy-zenhei fonts-arphic-ukai fonts-arphic-uming

需要区分一下:

3.3 安装其他工具程序(可选,但推荐)

$ # Linux下非常流行的编辑器
$ apt install -y vim
$
$ # 常用的网络小工具
$ apt install -y net-tools iputils-ping curl wget
$
$ # 编译套件,含make和gcc
$ apt install -y build-essential

3.4 创建一个普通用户用于运行飞鼠软件(2024-04-27更新)

$ # 安装sudo命令供普通用户使用
$ apt install -y sudo
$
$ # 新增用户,注意需要将其加入sudo组
$ useradd -m -s /bin/bash -U -G sudo -p $(openssl passwd -1 fuck_bat) fuck_bat
$
$ # 配置中文环境
$ echo "export LANG=zh_CN.UTF-8" >> /home/fuck_bat/.bashrc
$
$ # 将图形显示设置同步到该用户
$ echo "export DISPLAY=${DISPLAY}" >> /home/fuck_bat/.bashrc
$ echo "export DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS}" >> /home/fuck_bat/.bashrc
$
$ # 启动容器后自动切换到该用户以便运行飞鼠软件
$ echo 'su - fuck_bat' >> /root/.bashrc
$
$ # 退出容器,稍后可使用“docker start -i”启动该窗口,进行后续操作
$ exit

4、“调教”飞鼠

:以下操作若使用普通用户则需要加上sudo

假设有只飞鼠叫xx,其安装包叫xx.deb,那么可将其放入前文的共享目录,然后安装:

$ dpkg -i ${SHARED_DIR}/xx.deb # 2024-04-27更新:推荐将“dpkg -i”换成“apt install”,可自动解决程序依赖关系

毫无悬念会报错,因为复杂的软件会有很多依赖项,而这些依赖项在原始的Ubuntu系统中肯定没有安装。 挑选其中一个看看,例如libgtk-3-0,上网查一下,或者在宿主系统利用水平制表符Tab)补全机制看一看, 其对应的软件包也叫libgtk-3-0,于是安装一下:

$ apt install libgtk-3-0

出现更多的报错,皆因依赖项还有自己的依赖项。不过这次也出现了更有用的提示, 按提示来修复一下:

$ apt --fix-broken install

下载安装了一大堆依赖项,再继续安装飞鼠软件,就能成功安装了。 安装后的程序通常位于/opt/xx目录下,快捷启动方式则位于/usr/share/applications。 假设其主程序仍叫xx,运行一下看看会发生什么:

$ /opt/xx/xx

出现以下报错:

/opt/xx/xx: error while loading shared libraries: libgbm.so.1: cannot open shared object file: No such file or directory

按照前面安装缺失依赖项的思路,安装gdm库:

$ apt install libgbm1

还没完,又报告缺失另一个库:

/opt/xx/xx: error while loading shared libraries: libasound.so.2: cannot open shared object file: No such file or directory

继续安装asound库:

$ apt install libasound2

若还有缺失,继续如法炮制。一番操作过后,有了新进展——报错内容变了:

Running as root without --no-sandbox is not supported. See https://crbug.com/638180.

看上去“熟口熟面”,一查果然是Electron框架所导致的错误,大致原因与沙盒机制有关。 由于docker容器已经作了资源隔离,与沙盒类似,所以在容器内即使禁用沙盒也没什么问题, 按其要求加上相应的选项,再运行一次就行了:

$ /opt/xx/xx --no-sandbox

至此,飞鼠应该已经“调教”好,能正常玩耍了。如果有一只以上的飞鼠,可以让以上命令后台运行, 甚至忽略大部分程序日志,例如:

$ /opt/xx/xx --no-sandbox > /dev/null &

完事之后可以按Ctrl+p、再按一下q来退出容器。再次进入则为docker attach ${BAT_CONTAINER}

2024-04-27更新:以上的权限报错可通过在创建容器时指定--cap-add=CAP_SYS_ADMIN来解决。同时, 切换成普通用户(非root)来运行应用程序则不再需要指定--no-sandbox

5、参考链接