关于Docker使用X11来运行Gui程序,网上的东西只能说是千篇一律的复制粘贴,以至于产生了一种错觉-> 使用Dockerfile就可以达到目的
实际上单纯使用Dockerfile无法达到运行Gui程序的目的,应该说远远不够,因为Dockerfile本身是用于自定义镜像的,也就是说,是用来自定义一个集成了你需要的软件包的原始镜像
但是本着尝试的态度我也去学习了下Dockerfile,并且尝试写了一个,那就记录下来算了
编写Dockerfile
在一个可写入的位置新建一个文件 名为Dockerfile 不需要加后缀,也不要改名,内容如下
#!/bin/bash #这里以ubuntu:16.04为基础镜像 FROM ubuntu:16.04 # 用你自己的 uid /gid 替换下面的0 查看命令 id $USER # RUN export uid=501 gid=20 #添加自己需要的内容 ADD ./Acc /home/app # 添加具有免密码sudo权限的普通用用户 用户目录为/home/acc 名为lckiss #PS:以下所有命令都不要包含sudo 如果需要,请取消下面这行的注释 去掉#即可 # RUN apt-get update && apt-get install -y sudo && rm -rf /var/lib/apt/lists/* RUN mkdir -p /home/acc RUN echo "lckiss:x:${uid}:${gid}:lckiss,,,:/home/acc:/bin/bash" >> /etc/passwd RUN echo "lckiss:x:${uid}:" >> /etc/group RUN echo "lckiss ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers RUN chmod 0440 /etc/sudoers RUN chown ${uid}:${gid} -R /home/acc #解决无法找到add-apt-repository问题 RUN apt-get update && apt-get install -y python-software-properties && apt-get install -y software-properties-common #添加mono的源 RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF RUN echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | tee /etc/apt/sources.list.d/mono-official.list #安装mono环境 RUN apt update RUN apt-get install -y mono-devel #指定用户 USER lckiss #设置环境变量 HOME为/home/acc ENV HOME /home/acc #启动容器时的运行命令 CMD /usr/bin/mono /home/acc/Acc.exe
构建原始镜像
打开终端,切换到Dockerfile所在文件夹运行下面的命令来构建你的基础镜像(我上面的是一些基础的用法,比如添加了mono(.net环境)支持,并且添加了一些东西期望其能运行Gui)
docker build --rm -t my-mono .
这里的my-mono是取的镜像名称,构建成功后会生成一个名为my-mono的原始镜像,很多人都会问为什么要加–rm,都知道–rm是容器运行后就销毁的意思,起始Dockerfile就是这样运作的,先按你选择的最基础的镜像,比如我上面写的是ubuntu 16.04,生成一个容器,在容器中执行你的那些命令,完成后保存为镜像。那么这里就有个问题,无论是失败成功都会有一个容器,并且运行过后再无用处,所以加–rm,不信你可以用这个命令查看你生成了多少个容器
docker container ls -a
然后你可以按你的需求去运行这个镜像的实例了,比如:
docker run -it --privileged --mount type=bind,source=/Users/lckiss/Downloads/,target=/my-data --name baidu -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix my-mono
起始这个启动命令的有些参数是可以写到Dockerfile中的,但是我就懒得去改了,本来想着这样我就可以使用mono运行Gui的程序,后来发现不行,因为我的是Mac而不是linux。
具体linux运行Gui的方法可以看这篇文章,因为看上去更符合环境:http://blog.csdn.net/ericcchen/article/details/79253416
过渡段
mono这个工程实际上mac也有,但是很抱歉,这玩意儿在mac上不是那么的尽如人意,linux是友好的,软件本身是一方面,环境也是一方面
如何在mac上跑起来
起初我在看这篇文章的时候就觉得,这不是一般的麻烦:http://www.infoq.com/cn/articles/talk-about-docker-running-the-chinese-gui-software
应该说这是2018年,不是2015年,这中间的3年足矣让我怀疑这篇文章的做法
但是网上的文章,少之又少,并且由于平台的差异性,难以找到一定吻合的解决方案,这里就需要自己慢慢Google加上慢慢尝试
网上有一些解决办法,其中最常见的就是:https://coderwall.com/p/vwbpcg/run-gui-apps-in-containier-in-osx-docker-for-mac
中文版:http://shaoguangleo.github.io/2018/01/21/docker-run-gui-on-macosx/
不要问我为什么不尝试,实际上这种是有局限性的,而我要运行的是一个下载器,运行时错误为:
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.ArgumentNullException: Could not open display (X-Server required. Check your DISPLAY environment variable) Parameter name: Display at System.Windows.Forms.XplatUIX11.SetDisplay (System.IntPtr display_handle) [0x00408] in <8254e6010dae4d09ac0767af6dcc75af>:0 at System.Windows.Forms.XplatUIX11..ctor () [0x00077] in <8254e6010dae4d09ac0767af6dcc75af>:0 at System.Windows.Forms.XplatUIX11.GetInstance () [0x00019] in <8254e6010dae4d09ac0767af6dcc75af>:0 at System.Windows.Forms.XplatUI..cctor () [0x00066] in <8254e6010dae4d09ac0767af6dcc75af>:0
这种错误网上也有,但是因为不通用,而且比较新,谷歌上的结果基本上在2018年1月,所以无法解决,这种问题要么找开发者,要么尝试给docker装个桌面,然后通过远程连接的方式,这实在有点曲线救国,并且感觉不到这和虚拟机有什么区别。
更新
经过再一次的尝试,证明上面教程确实可行,原因是看到了这个文章:https://stackoverflow.com/questions/48335431/osx-x11-error-cannot-open-display
执行xhost +来确保是可以从网络连接的而不是”access control disabled, clients can connect from any host”,解决办法是执行:export DISPLAY=192.168.1.X:0 (X改成你的主机Ip)
并且执行该命令(socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\”$SPLAY\”)的终端不要中断,请后台运行,具体如下:
DockerFile
#!/bin/bash #docker run # --rm -it # --privileged # --mount type=bind,source=/Users/lckiss/Downloads/,target=/my-data # --name baidu # -e DISPLAY=192.168.1.104:0 # -v /tmp/.X11-unix:/tmp/.X11-unix # my-mono #这里以mono:latest为基础镜像 FROM mono:latest #添加自己需要的内容 RUN mkdir /home/app ADD ./Acc /home/app RUN cp /home/app/Config.json / #解决中文乱码问题 RUN apt-get update && apt-get install -y xfonts-wqy ttf-wqy-zenhei #缓存等清理 RUN apt-get clean && apt-get autoclean && apt-get autoremove && rm -rf /var/lib/apt/lists/* #指定用户 USER root #设置环境变量 HOME为/root ENV HOME /root ENV LANG zh-CN.UTF-8 ENV LANGUAGE zh-CN.UTF-8 ENV LC_ALL zh-CN.UTF-8 #启动容器时的运行命令 CMD /usr/bin/mono /home/app/Acc.exe
监听命令 (安装:brew install socat)
socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
X11:
brew install Caskroom/cask/xquartz
打开Xquartz软件,偏好设置->安全性->勾选允许从网络客户端连接
编译dockerfile命令
docker build --rm -t my-mono .
启动命令 其中IP地址为本机的IP地址,注意修改
docker run --rm -it \ --privileged \ --mount type=bind,source=/Users/lckiss/Downloads/,target=/my-data \ --name baidu -e DISPLAY=192.168.43.196:0 \ -v /tmp/.X11-unix:/tmp/.X11-unix \ my-mono
更新优化好的Dockerfile
用于打包rom的,将工具包放在同一目录下
#!/bin/bash #docker run # -it # --privileged # --name rom # --mount type=bind,source=/Users/lckiss/Downloads/,target=/my-data # ubuntu:16.04 bash #这里以java:8为基础镜像 FROM java:8 #添加自己需要的内容 RUN mkdir /mnt/rom ADD ./util /home/util #链接权限 RUN chmod +x -R /home/util/ && ln -s /home/util/* /bin RUN apt-get update && apt-get install -y file lib32c-dev lib32stdc++6 #缓存等清理 RUN apt-get clean && apt-get autoclean && apt-get autoremove && rm -rf /var/lib/apt/lists/* #设置环境变量 HOME为/root ENV HOME /root #启动容器时的运行命令 CMD /bin/bash
编译dockerfile命令
docker build --rm -t my-rom .
启动命令
docker run -it --privileged --name linux --mount type=bind,source=/Users/lckiss/Downloads/,target=/my-data my-rom
总结:
踩完坑了确实要比虚拟机强悍很多啊,不用等开机,告别了臃肿,只用来执行单一的任务,一条命令即可搞定。Nice!
Dockerfile的方式可以让你抛弃容器(用完就删除),个人觉得是Docker的一种高级用法,但是真正明白了,也是很简单的。
至于其他的实现,比如说ngnix等等环境,都有直接配置好的镜像,不满意可以在这个基础上进行修改即可。
至于直接安装一个桌面就不尝试了,完全没必要,但是对于美观的elementary,有必要留下一个脚印:Ubuntu1604安装Pantheon桌面环境
PS:你也可以不学习Dockerfile一样可以达到运行的效果,使用Dockerfile只是为了开箱即用
本站由以下主机服务商提供服务支持:
0条评论