[Docker]GUI最佳实践
通过Docker
运行GUI
,能够实现compile once, run everywhere
的效果,也有助于理清不同软件之间的依赖问题
运行GUI
软件的困难在于如何利用主机的各种硬件,以及如何显示图形界面。主要包含以下几个方面
- 图形界面
- 存储
- 音频/视频
- 网络
- 中文支持
图形界面
参考:
Docker
官方提供的Ubuntu
镜像都是没有图形界面服务的。需要在容器中安装X11(X Window System),然后将主机DISPLAY
环境变量传入容器,即可实现容器GUI
软件的显示
分为两种情况支持,
- 一是将本地容器中运行
- 二是在远程服务器容器中运行
本地运行
其实现方式如下:
[应用程序]->[X11客户端]->[X11服务端]->[显示屏幕]
其中容器是客户端,主机是服务端。通过主机和容器共享套接字unix:0
,实现容器GUI
软件显示在本地
实现如下:
$ docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=unix$DISPLAY \
...
X11
服务默认只允许来自本地用户
启动的图形程序将图形显示在当前屏幕上,所以在启动之前还需安装xhost
命令,允许所有用户访问
$ sudo apt-get install x11-xserver-utils
$ xhost +
access control disabled, clients can connect from any host
远程运行
。。。
存储
通常GUI
软件会应用到本地文件,所以还需要实现主机和容器共享文件。可以通过绑定挂载
方式,将主机目录挂载到容器中,主机和容器均可对文件进行操作
需要注意的地方是文件权限
,默认容器按root
用户登录,在容器中创建的文件均是root
属性,不易于主机普通用户操作
可以创建一个普通用户user
,在容器启动时切换到用户user
执行,同时传入主机当前用户的UID
和GID
,修改容器user
的属性,保证挂载后不改变
挂载点的文件属性(很重要)
在Dockerfile
文件中
# 创建用户user
RUN useradd -s /bin/bash -m user
# 指定启动项docker-entrypoint.sh
COPY docker-entrypoint.sh ./
RUN chmod a+x docker-entrypoint.sh && \
chown user:user docker-entrypoint.sh
ENTRYPOINT ["/app/docker-entrypoint.sh"]
启动容器时指定运行docker-entrypoing.sh
#!/bin/bash
# 判断当前用户是否是`root`
if [ "$(id -u)" -eq '0' ]
then
# 获取用户传入的UID/GID
UID=${UID:-9001}
GID=${GID:-9001}
# 修改user属性音频
usermod -u ${UID} -g ${GID} -a -G root user > /dev/null 2>&1
export HOME=/home/user
chown -R ${UID}:${GID} ${HOME} > /dev/null 2>&1
# 使用工具gosu切换当前用户为user,并重新执行docker-entrypoint.sh
exec gosu user "$0" "$@"
fi
# 以user身份执行
exec "$@"
通过用户的创建和属性的修改,能够保证挂载点的文件属性不发生改变
音频/视频
容器默认无法使用主机硬件,所以对于某些软件需要使用音频/视频等设备需要额外添加参数
可以在启动时指定容器要访问的设备,传入相应硬件组ID
,比如
# 查询主机组ID
$ cat /etc/group | grep audio
audio:x:29:pulse
$ cat /etc/group | grep video
video:x:44:
# 访问音频
$ docker run --device /dev/snd:/dev/snd -e AUDIO_ID=`getent group audio | cut -d: -f3` ...
# 访问视频
$ docker run --device /dev/video0:/dev/video0 -e VIDEO_GID=`getent group video | cut -d: -f3` ...
如果出现以下错误信息,很有可能容器还是无法正确使用硬件
libGL error: MESA-LOADER: failed to retrieve device information
libGL error: Version 4 or later of flush extension not found
libGL error: failed to load driver: i915
libGL error: failed to open drm device: No such file or directory
libGL error: failed to load driver: i965
参数--privileged
表示容器可以使用主机所有硬件设备
$ docker run --privileged ...
所以加入--privileged
就可以了
网络
。。。
中文支持
中文支持包括4
个方面,
- 中文字符集
- 中文字体
- 时区
- 中文输入法
参考[Linux][locale]字符集设置设置zh_CN.UTF-8
出现中文乱码时,参考[Ubuntu 18.04]中文乱码安装中文字体;
sudo apt-get install ttf-wqy-microhei #文泉驿-微米黑
中国处于东八区,和默认时区相差8
个小时,参考[Ubuntu 18.04][localtime]设置时区进行设置
关于中文输入法使用,在容器启动时设置环境变量即可
docker run \
-e XMODIFIERS="@im=fcitx" \
-e QT_IM_MODULE="fcitx" \
-e GTK_IM_MODULE="fcitx" \
小结
参考wszqkzqk/deepin-wine-ubuntu和Peter Wu实现了Docker Deepin-Wine
的Windows
软件运行
jessfraz/dockerfiles也提供了许多软件实现的参考
Docker Hub
地址:zjzstu
当前实现: