Docker运行GUI软件的方法
轉(zhuǎn)自 https://www.csdn.net/article/2015-07-30/2825340
簡(jiǎn)介:
Docker通過namespace將容器與主機(jī)上的網(wǎng)絡(luò)和運(yùn)行環(huán)境進(jìn)行了隔離,默認(rèn)情況下,在容器中運(yùn)行帶界面的軟件在外部是看不到的。在這個(gè)分享中,將介紹通過共享X11套接字讓外部主機(jī)顯示容器中運(yùn)行的程序界面的方法。并討論在『運(yùn)行本地的GUI程序』和『運(yùn)行遠(yuǎn)程服務(wù)器上的GUI程序』兩種場(chǎng)景的下的實(shí)現(xiàn)原理。
下文是本次的分享整理:
Docker比較常用的場(chǎng)景是『運(yùn)行無(wú)界面的后臺(tái)服務(wù)』或者『運(yùn)行基于的Web服務(wù)』。不過有時(shí)出于個(gè)人的喜好或特定的需求,我們會(huì)希望在Docker中運(yùn)行帶圖形界面的應(yīng)用程序。
比如,在今年的『Docker全球開發(fā)者大會(huì)』上,Docker自家的美女程序員『杰西·弗萊澤爾(Jessie Frazelle)』展示了一系列黑魔法一樣的鏡像。這些鏡像中的大多數(shù)都使用了圖形界面。
DaoCloud的孫宏亮在現(xiàn)場(chǎng)通過博客直播了她的演講。看到這張照片很多人應(yīng)該已經(jīng)認(rèn)出她了。
Jessie在自己的博客里介紹這些鏡像時(shí)說,她十分欣賞蘋果的Mac電腦中每個(gè)應(yīng)用程序使用獨(dú)立沙盒中運(yùn)行的做法,這樣避免了應(yīng)用程序?qū)⑴渲梦募瓦\(yùn)行過程中生成的臨時(shí)文件散亂的丟在系統(tǒng)各種目錄中。Jessie現(xiàn)在的工作環(huán)境主要是Debian系統(tǒng),出于這種喜好,她將自己常用的各種軟件統(tǒng)統(tǒng)使用Docker容器化了。
將容器中的圖形界面展示到外部的一般性思路。
目前Unix/Linux比較主流的圖形界面服務(wù)是X11,而X11服務(wù)的圖形顯示方式實(shí)際上是一種Client/Server模式,在服務(wù)端和客戶端之間,X11通過『DISPLAY』環(huán)境變量來指定將圖形顯示到何處。如下面的流程所示,請(qǐng)注意服務(wù)端與客戶端的位置,服務(wù)端是用于提供顯示信息的。
[應(yīng)用程序]->[X11客戶端]->[X11服務(wù)端]->[顯示屏幕]
DISPLAY的格式是『unix:端口』或『主機(jī)名:端口』,前一種格式表示使用本地的unix套接字,后一種表示使用tcp套接字。
默認(rèn)情況下,X11的服務(wù)端會(huì)監(jiān)聽本地的『unit:0』端口,而DISPLAY的默認(rèn)值為『:0』,這實(shí)際上是『unit:0』的簡(jiǎn)寫。因此如果在Linux的控制臺(tái)啟動(dòng)一個(gè)圖形程序,它就會(huì)出現(xiàn)在當(dāng)前主機(jī)的顯示屏幕中。
基于這個(gè)原理,將Docker中的GUI程序顯示到外面,就是通過某種方式把X11的客戶端的內(nèi)容從容器里面?zhèn)鬟f出來。基本的思路無(wú)非有兩種:
通過SSH連接或遠(yuǎn)程控制軟件,最終通過tcp套接字將數(shù)據(jù)發(fā)送出來
讓容器和主機(jī)共享X11的unix套接字,直接將數(shù)據(jù)發(fā)送出來
從應(yīng)用場(chǎng)景上劃分,又可以分成兩類情況:『運(yùn)行本地的GUI程序』和『運(yùn)行遠(yuǎn)程服務(wù)器上的GUI程序』。這兩類情況在操作上很相似,但前者可以使用unix套接字,而后者必然要使用tcp套接字轉(zhuǎn)發(fā),原理上有很大差別。先說本地運(yùn)行GUI程序的情況。
以Jessie在Docker開發(fā)者大會(huì)上做的第一個(gè)演示『LibreOffice』為例。這個(gè)鏡像的Dockerfile代碼和使用方法都已經(jīng)開源在Github上了。
不知道有多少人實(shí)際測(cè)試過Jessie在博客或者Docker開發(fā)者大會(huì)上用過的例子,我相信其中應(yīng)該有些人會(huì)發(fā)現(xiàn),直接運(yùn)行這些例子是行不通的。下面是我的運(yùn)行環(huán)境:
$ cat lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"
$ docker --version
Docker version 1.7.1, build 786b29d
這是一個(gè)全新的Ubuntu系統(tǒng),僅僅添加了Docker等基本的軟件。
在LibreOffice的Dockerfile注釋里提供了運(yùn)行方法:
$ docker run -d
-v /etc/localtime:/etc/localtime:ro
-v /tmp/.X11-unix:/tmp/.X11-unix
-e DISPLAY=unix$DISPLAY
-v $HOME/slides:/root/slides
-e GDK_SCALE
-e GDK_DPI_SCALE
--name libreoffice
jess/libreoffice
其中的『-v /tmp/.X11-unix:/tmp/.X11-unix』參數(shù)就是將主機(jī)上X11的unix套接字共享到了容器里面。因?yàn)槊總€(gè)unix套接字實(shí)際上就是系統(tǒng)/tmp/.X11-unix目錄下面依據(jù)套接字編號(hào)命名的一個(gè)特殊文件。
命令執(zhí)行完,LibreOffice并沒有啟動(dòng)。
好在剛剛已經(jīng)說過這茬,所以還不算太意外。看一下日志:
$ docker logs libreoffice
No protocol specified
Failed to open display
javaldx: Could not find a Java Runtime Environment!
Warning: failed to read path from javaldx
No protocol specified
No protocol specified
No protocol specified
No protocol specified
這是由于X11服務(wù)默認(rèn)只允許『來自本地的用戶』啟動(dòng)的圖形程序?qū)D形顯示在當(dāng)前屏幕上。對(duì)于Jessie的運(yùn)行環(huán)境,她應(yīng)該的已經(jīng)修改了這個(gè)設(shè)置,但并沒有在博客中提及。對(duì)于大多數(shù)的Linux用戶來說,直接運(yùn)行博客中的命令,都應(yīng)該會(huì)遇到這個(gè)問題。
解決的辦法很簡(jiǎn)單,允許所有用戶訪問X11服務(wù)即可。這個(gè)事情可以用xhost命令完成。
$ sudo apt-get install x11-xserver-utils
$ xhost +
參數(shù)『+』表示允許任意來源的用戶。
現(xiàn)在再次運(yùn)行前面的docker run命令,就會(huì)看到LibreOffice啟動(dòng)起來了,速度相當(dāng)快。由于是直接共享了X11的unix套接字,在效率上與運(yùn)行安裝在主機(jī)上的程序基本沒有差異。
在遠(yuǎn)程服務(wù)器上用Docker運(yùn)行GUI程序的情況。
這種情況多出現(xiàn)在將Docker作為產(chǎn)品測(cè)試環(huán)境使用的場(chǎng)景。利用Docker用后既消除的特點(diǎn),能夠快速的為每次測(cè)試提供干凈的上下文環(huán)境。有時(shí)為了在非Linux系統(tǒng)中使用Linux的圖形化軟件,也可以通過遠(yuǎn)程Docker運(yùn)行的方法實(shí)現(xiàn)。
此時(shí),整個(gè)數(shù)據(jù)連接實(shí)際就變成了這樣的:
[應(yīng)用程序]->[X11客戶端]->[SSH服務(wù)端]->[SSH客戶端]->[X11服務(wù)端]->[顯示屏幕]
這種情況實(shí)際上已經(jīng)演化成為了通過tcp套接字轉(zhuǎn)發(fā)的X11連接,只不過用戶并沒有直接使用SSH連接到容器里面的tcp端口上,而是連接到了遠(yuǎn)程主機(jī)。相應(yīng)的X11數(shù)據(jù)先從容器傳遞到了主機(jī),再通過SSH通過傳遞到了用戶的電腦上。
這就必須有要求用于展示的用后電腦安裝有X11服務(wù),大多數(shù)的Linux系統(tǒng)默認(rèn)就具備了,Mac系統(tǒng)可以安裝XQuartz軟件,Windows則可以使用Xming等第三方X11服務(wù)端實(shí)現(xiàn)。首先將本地的X11服務(wù)運(yùn)行起來。
其次,當(dāng)用戶使用SSH連接運(yùn)行程序的服務(wù)器時(shí),應(yīng)該開啟SSH的『X11-Forwarding』功能。具體來說,有兩個(gè)注意點(diǎn)。
1)檢測(cè)服務(wù)器上的/etc/ssh/sshd_config文件,是否已經(jīng)有『X11Forwarding yes』這樣的配置,如果沒有則需要加上。
2)當(dāng)連接到服務(wù)器時(shí),應(yīng)該在ssh命令后面加上-X參數(shù),表示使用X11-Forwarding特性。
$ ssh -X @
登陸上去后運(yùn)行剛才的docker run命令,并不能看到LibreOffice運(yùn)行起來的跡象。通過log發(fā)現(xiàn)錯(cuò)誤還是『Failed to open display』。在前面已經(jīng)說過,對(duì)于遠(yuǎn)程連接運(yùn)行GUI的情況,必然要換成tcp套接字的X11轉(zhuǎn)發(fā)方式。而命令中的『-v /tmp/.X11-unix:/tmp/.X11-unix』參數(shù)僅僅是共享了unix套接字。那么怎樣才能換成tcp套接字呢?需要修改兩個(gè)地方:
1)首先為容器里面設(shè)置的環(huán)境變量『DISPLAY』,不能是『unix$DISPLAY』了
2)其次共享unix套接字可以不必了,而是要用『--net=host』讓容器內(nèi)的網(wǎng)絡(luò)環(huán)境與主機(jī)共享
DISPLAY改成什么呢?首先要看SSH登陸后得到的系統(tǒng)DISPLAY變量值,我這里看到的是『localhost:10.0』,主機(jī)的localhost:10.0到了容器里面就要變成0.0.0.0:10.0。原因不解釋了,這個(gè)是Docker默認(rèn)添加的映射。
因此DISPLAY的值應(yīng)該賦予『0.0.0.0:10.0』。可以簡(jiǎn)寫為『:10.0』,X11會(huì)先去找unix:10.0,發(fā)現(xiàn)沒有那個(gè)套接字文件,然后就會(huì)去試0.0.0.0:10.0。結(jié)果是一樣的。修改過后的啟動(dòng)命令變成了:
$ docker run -d
-v /etc/localtime:/etc/localtime:ro
--net=host
-e DISPLAY=:10.0
-v $HOME/slides:/root/slides
-e GDK_SCALE
-e GDK_DPI_SCALE
--name libreoffice
jess/libreoffice
再次運(yùn)行這個(gè)鏡像,然而,依舊沒有看到LibreOffice。查看Docker logs,這次的錯(cuò)誤信息是:
『X11 connection rejected because of wrong authentication』。
這是因?yàn)樵谑褂肧SH通道轉(zhuǎn)發(fā)X11時(shí),會(huì)生成一個(gè)隨機(jī)的授權(quán)cookie,存放在服務(wù)器的Xauthority文件中。這個(gè)cookie會(huì)在每次X11客戶端發(fā)送數(shù)據(jù)時(shí)被用到。我們使用了『--net=host』參數(shù)后,容器中的X11客戶端將直接通過tcp套接字與外部通信,然而容器里面并沒有這個(gè)授權(quán)文件。因此我需要加上參數(shù)『-v $HOME/.Xauthority:/root/.Xauthority』把授權(quán)文件也放到容器里面。此外,啟動(dòng)命令中的兩個(gè)GDK開頭的環(huán)境變量在服務(wù)器端的Ubuntu上是不存在的,因此也可以刪掉。
現(xiàn)在我們得到了最終的啟動(dòng)命令:
$ docker run -d
-v /etc/localtime:/etc/localtime:ro
--net=host
-e DISPLAY=:10.0
-v $HOME/slides:/root/slides
-v $HOME/.Xauthority:/root/.Xauthority
--name libreoffice
jess/libreoffice
執(zhí)行這個(gè)命令后,就看到LibreOffice已經(jīng)在本地電腦的顯示器上運(yùn)行起來啦!
這個(gè)在Mac上看到的LibreOffice,程序本身運(yùn)行在遠(yuǎn)程服務(wù)器的Docker里面。同樣的方法也可以適應(yīng)于Jessie的其他鏡像。
Q&A:
問題1. X11是什么,與KDE有什么區(qū)別?
林帆:X11是Linux下面的界面顯示服務(wù)。KDE是一種窗口管理軟件,是具體的界面,X11是在更下面一層的協(xié)議層。
問題2. 在服務(wù)端運(yùn)行GUI鏡像時(shí)會(huì)收到網(wǎng)絡(luò)的影響畫面卡頓嗎?
林帆:這個(gè)和網(wǎng)速關(guān)系比較大。
問題3. 通過這種gui方式,是不是可以做docker桌面云了?
林帆:不算是,因?yàn)檫@種做法需要SSH登錄,其實(shí)有點(diǎn)不安全.
問題4. 可以多用戶連接同一docker image不?就像remote desktop service一樣?
林帆:用這種方式不能,SSH的X-Forwarding是單點(diǎn)的。
問題5. 可以考慮用xvfb嗎?
林帆:原理上是可以的,不過這樣就看不到運(yùn)行的界面了。
問題6. 理論上講,只要配置合理正確并且GUI支持X11,這種方式可以運(yùn)行大部分linux下的gui應(yīng)用?
林帆:是的,對(duì)于應(yīng)用程序本身感覺不到圖像是被現(xiàn)實(shí)到了本地還是遠(yuǎn)程的屏幕上
問題7. 請(qǐng)問在docker上運(yùn)行的gui應(yīng)用,應(yīng)用間的互操作性如何保障?x11協(xié)議應(yīng)該只能轉(zhuǎn)發(fā)顯示數(shù)據(jù),無(wú)法轉(zhuǎn)發(fā)實(shí)際數(shù)據(jù)(如電子表格中的數(shù)據(jù),用以粘貼到其他打開的文檔文件中),是否有其他協(xié)議可以保證互操作性?
林帆:目前看來互操作的話只能用其他協(xié)議代替X11了,比如VNC或者FreeNX。X11協(xié)議中,剪貼板的數(shù)據(jù)都是保存在X的客戶端,兩個(gè)遠(yuǎn)程窗口之間不能共享。
轉(zhuǎn)載于:https://www.cnblogs.com/jcchen1987/p/10553930.html
總結(jié)
以上是生活随笔為你收集整理的Docker运行GUI软件的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入解析CNN pooling 池化层原
- 下一篇: COCI 2020/2021 Svjet