Docker容器運行GUI程序的配置方法


https://www.cnblogs.com/lijinze-tsinghua/p/8686264.html

Docker容器運行GUI程序的配置方法

0.環境說明

Ubuntu 16.04 
docker 1.35

1.Docker的“可視化”

Docker本身的工作模式是命令行的,因為主要的使用場景可能是做服務器后端方面的比較多。 
但有時候我們會有在docker容器里運行一些圖形界面的軟件,或者要調用攝像頭,輸出圖像等等一些需求,這個時候需要解決這個Docker “可視化”的問題。 
(這里的“可視化”不是很容易搜到的可視化管理的方法)

2.解決方案1—啟動容器時添加配置選項

林帆:Docker運行GUI軟件的方法

這篇文章里介紹了Docker公司的程序員傑西·弗萊澤爾(Jessie Frazelle)展示的使用了圖形界面的鏡像的例子,Jessie也開源了她展示的docker 運行libreoffice軟件的代碼和使用方法。

2.1 原理簡介

原文中講的比較詳細,原理並不復雜,我按照自己理解很淺顯地講一下。 
原理上可以把docker鏡像看做一台沒配顯示器的電腦,程序可以運行,但是沒地方顯示。 
linux目前的主流圖像界面服務X11又支持 客戶端/服務端(Client/Server)的工作模式 
只要在容器啟動的時候,將 『unix:端口』或『主機名:端口』共享給docker,docker 就可以通過端口找到顯示輸出的地方和linux系統共用顯示

2.2 具體操作(顯示到本地顯示器)

1)首先,在主系統里運行

$ sudo apt-get install x11-xserver-utils  $ xhost +

這兩句的作用是開放權限,允許所有用戶,當然包括docker,訪問X11 的顯示接口

2)在啟動docker容器時,添加選項如下:

 -v /tmp/.X11-unix:/tmp/.X11-unix \ #共享本地unix端口 -e DISPLAY=unix$DISPLAY \ #修改環境變量DISPLAY -e GDK_SCALE \ #我覺得這兩個是與顯示效果相關的環境變量,沒有細究 -e GDK_DPI_SCALE \

最終的啟動命令就會長類似這樣

$ docker run -d \

  -v /etc/localtime:/etc/localtime:ro \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -e DISPLAY=unix$DISPLAY \ -e GDK_SCALE \ -e GDK_DPI_SCALE \ --name libreoffice \ jess/libreoffice

這樣啟動后的容器,運行有圖形界面的程序就可以自由顯示,和在本地顯示一樣了。

這樣操作已經十分方便了。需要注意的是,每次重新開機,需要在本機操作一次

xhost +

打開權限。應該有永久更改這個的辦法,不過我覺得不算麻煩。 
原文中還有在遠程顯示的配置方法,我沒有試,就不多說了。

3.解決方案2—已經啟動的容器修改系統參數

參考文章 
有的時候,我們在已經啟動的容器里做了一些事情,有了顯示圖像的需要,但從頭新啟動一個容器有點麻煩。 
這時候可以用上面博客里講的方法實現圖形界面顯示,也還算方便。 
思路上也是把主機和docker看做服務器和客戶端的關系,通過IP地址來映射顯示

3.1 具體操作

1)使用 ifconfig 查看主機和docker的IP地址 
例如:主機的IP為 xxx 
docker 的IP為YYY 
2)docker 中

export DISPLAY= XXX #把環境變量映射到主機IP

3.)主機中

sudo gedit /etc/lightdm/lightdm.conf #增加一行 xserver-allow-tcp=true sudo systemctl restart lightdm xhost + #注意加號前應有空格

這樣配置就完成了,這是第一次配置的操作. 
以后每次重新開機時,還是要在主機里運行一下 xhost +,在docker里運行一下export DISPLAY= XXX 。 
其實還是挺麻煩的。 
最關鍵的是,這種方式用的是IP地址,在系統沒聯網時,網卡就沒有分配的IP地址了,這種方法就行不通了。

4.怎樣測試能否顯示圖像界面

第二篇參考文章中用了一個顯示時鍾的小程序xclock 
不過我在Ubuntu16.04的環境里搜不到這個了,能安裝的叫xarclock,功能一樣 
在docker中運行

sudo apt-get install xarclock #安裝這個小程序 xarclock #運行,如果配置成功,會顯示出一個小鍾表動畫
 

 

【微信分享】林帆:Docker運行GUI軟件的方法

https://www.csdn.net/article/2015-07-30/2825340

簡介:

Docker通過namespace將容器與主機上的網絡和運行環境進行了隔離,默認情況下,在容器中運行帶界面的軟件在外部是看不到的。在這個分享中,將介紹通過共享X11套接字讓外部主機顯示容器中運行的程序界面的方法。並討論在『運行本地的GUI程序』和『運行遠程服務器上的GUI程序』兩種場景的下的實現原理。

Docker比較常用的場景是『運行無界面的后台服務』或者『運行基於的Web服務』。不過有時出於個人的喜好或特定的需求,我們會希望在Docker中運行帶圖形界面的應用程序

比如,在今年的『Docker全球開發者大會』上,Docker自家的美女程序員『傑西·弗萊澤爾(Jessie Frazelle)』展示了一系列黑魔法一樣的鏡像。這些鏡像中的大多數都使用了圖形界面。

DaoCloud的孫宏亮在現場通過博客直播了她的演講。看到這張照片很多人應該已經認出她了。

Jessie在自己的博客里介紹這些鏡像時說,她十分欣賞蘋果的Mac電腦中每個應用程序使用獨立沙盒中運行的做法,這樣避免了應用程序將配置文件和運行過程中生成的臨時文件散亂的丟在系統各種目錄中。Jessie現在的工作環境主要是Debian系統,出於這種喜好,她將自己常用的各種軟件統統使用Docker容器化了

 

將容器中的圖形界面展示到外部的一般性思路。

目前Unix/Linux比較主流的圖形界面服務是X11,而X11服務的圖形顯示方式實際上是一種Client/Server模式,在服務端和客戶端之間,X11通過『DISPLAY』環境變量來指定將圖形顯示到何處。如下面的流程所示,請注意服務端與客戶端的位置,服務端是用於提供顯示信息的。

[應用程序]->[X11客戶端]->[X11服務端]->[顯示屏幕]

DISPLAY的格式是『unix:端口』或『主機名:端口』,前一種格式表示使用本地的unix套接字,后一種表示使用tcp套接字

默認情況下,X11的服務端會監聽本地的『unit:0』端口,而DISPLAY的默認值為『:0』,這實際上是『unit:0』的簡寫。因此如果在Linux的控制台啟動一個圖形程序,它就會出現在當前主機的顯示屏幕中。

基於這個原理,將Docker中的GUI程序顯示到外面,就是通過某種方式把X11的客戶端的內容從容器里面傳遞出來。基本的思路無非有兩種:

 

  1. 通過SSH連接或遠程控制軟件,最終通過tcp套接字將數據發送出來
  2. 讓容器和主機共享X11的unix套接字,直接將數據發送出來

 

從應用場景上划分,又可以分成兩類情況:『運行本地的GUI程序』和『運行遠程服務器上的GUI程序』。這兩類情況在操作上很相似,但前者可以使用unix套接字,而后者必然要使用tcp套接字轉發,原理上有很大差別。先說本地運行GUI程序的情況。

以Jessie在Docker開發者大會上做的第一個演示『LibreOffice』為例。這個鏡像的Dockerfile代碼和使用方法都已經開源在Github上了。

不知道有多少人實際測試過Jessie在博客或者Docker開發者大會上用過的例子,我相信其中應該有些人會發現,直接運行這些例子是行不通的。下面是我的運行環境:

 

$ 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

 

這是一個全新的Ubuntu系統,僅僅添加了Docker等基本的軟件。

在LibreOffice的Dockerfile注釋里提供了運行方法:

 

$ 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』參數就是將主機上X11的unix套接字共享到了容器里面。因為每個unix套接字實際上就是系統/tmp/.X11-unix目錄下面依據套接字編號命名的一個特殊文件。

命令執行完,LibreOffice並沒有啟動。

好在剛剛已經說過這茬,所以還不算太意外。看一下日志:

 

$ 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服務默認只允許『來自本地的用戶』啟動的圖形程序將圖形顯示在當前屏幕上。對於Jessie的運行環境,她應該的已經修改了這個設置,但並沒有在博客中提及。對於大多數的Linux用戶來說,直接運行博客中的命令,都應該會遇到這個問題。

解決的辦法很簡單,允許所有用戶訪問X11服務即可。這個事情可以用xhost命令完成。

 

$ sudo apt-get install x11-xserver-utils

$ xhost +

 

參數『+』表示允許任意來源的用戶。

現在再次運行前面的docker run命令,就會看到LibreOffice啟動起來了,速度相當快。由於是直接共享了X11的unix套接字,在效率上與運行安裝在主機上的程序基本沒有差異。

在遠程服務器上用Docker運行GUI程序的情況。

這種情況多出現在將Docker作為產品測試環境使用的場景。利用Docker用后既消除的特點,能夠快速的為每次測試提供干凈的上下文環境。有時為了在非Linux系統中使用Linux的圖形化軟件,也可以通過遠程Docker運行的方法實現

此時,整個數據連接實際就變成了這樣的:

[應用程序]->[X11客戶端]->[SSH服務端]->[SSH客戶端]->[X11服務端]->[顯示屏幕]

這種情況實際上已經演化成為了通過tcp套接字轉發的X11連接,只不過用戶並沒有直接使用SSH連接到容器里面的tcp端口上,而是連接到了遠程主機。相應的X11數據先從容器傳遞到了主機,再通過SSH通過傳遞到了用戶的電腦上

這就必須有要求用於展示的用后電腦安裝有X11服務,大多數的Linux系統默認就具備了,Mac系統可以安裝XQuartz軟件,Windows則可以使用Xming等第三方X11服務端實現。首先將本地的X11服務運行起來

其次,當用戶使用SSH連接運行程序的服務器時,應該開啟SSH的『X11-Forwarding』功能。具體來說,有兩個注意點。

1)檢測服務器上的/etc/ssh/sshd_config文件,是否已經有『X11Forwarding yes』這樣的配置,如果沒有則需要加上。

2)當連接到服務器時,應該在ssh命令后面加上-X參數,表示使用X11-Forwarding特性。

 

$ ssh -X <user>@<ip-addr>

 

登陸上去后運行剛才的docker run命令,並不能看到LibreOffice運行起來的跡象。通過log發現錯誤還是『Failed to open display』。在前面已經說過,對於遠程連接運行GUI的情況,必然要換成tcp套接字的X11轉發方式。而命令中的『-v /tmp/.X11-unix:/tmp/.X11-unix』參數僅僅是共享了unix套接字。那么怎樣才能換成tcp套接字呢?需要修改兩個地方:

1)首先為容器里面設置的環境變量『DISPLAY』,不能是『unix$DISPLAY』了

2)其次共享unix套接字可以不必了,而是要用『--net=host』讓容器內的網絡環境與主機共享

DISPLAY改成什么呢?首先要看SSH登陸后得到的系統DISPLAY變量值,我這里看到的是『localhost:10.0』,主機的localhost:10.0到了容器里面就要變成0.0.0.0:10.0。原因不解釋了,這個是Docker默認添加的映射。

因此DISPLAY的值應該賦予『0.0.0.0:10.0』。可以簡寫為『:10.0』,X11會先去找unix:10.0,發現沒有那個套接字文件,然后就會去試0.0.0.0:10.0。結果是一樣的。修改過后的啟動命令變成了:

 

  $ 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

 

再次運行這個鏡像,然而,依舊沒有看到LibreOffice。查看Docker logs,這次的錯誤信息是:

『X11 connection rejected because of wrong authentication』。

這是因為在使用SSH通道轉發X11時,會生成一個隨機的授權cookie,存放在服務器的Xauthority文件中。這個cookie會在每次X11客戶端發送數據時被用到。我們使用了『--net=host』參數后,容器中的X11客戶端將直接通過tcp套接字與外部通信,然而容器里面並沒有這個授權文件。因此我需要加上參數『-v $HOME/.Xauthority:/root/.Xauthority』把授權文件也放到容器里面。此外,啟動命令中的兩個GDK開頭的環境變量在服務器端的Ubuntu上是不存在的,因此也可以刪掉

現在我們得到了最終的啟動命令:

 

  $ 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

 

執行這個命令后,就看到LibreOffice已經在本地電腦的顯示器上運行起來啦!

這個在Mac上看到的LibreOffice,程序本身運行在遠程服務器的Docker里面。同樣的方法也可以適應於Jessie的其他鏡像。

 

Q&A:

問題1. X11是什么,與KDE有什么區別?

林帆:X11是Linux下面的界面顯示服務KDE是一種窗口管理軟件,是具體的界面,X11是在更下面一層的協議層。

問題2. 在服務端運行GUI鏡像時會收到網絡的影響畫面卡頓嗎?

林帆:這個和網速關系比較大

問題3. 通過這種gui方式,是不是可以做docker桌面雲了?

林帆:不算是,因為這種做法需要SSH登錄,其實有點不安全.

問題4. 可以多用戶連接同一docker image不?就像remote desktop service一樣?

林帆:用這種方式不能,SSH的X-Forwarding是單點的

問題5. 可以考慮用xvfb嗎?

林帆:原理上是可以的,不過這樣就看不到運行的界面了

問題6. 理論上講,只要配置合理正確並且GUI支持X11,這種方式可以運行大部分linux下的gui應用?

林帆:是的,對於應用程序本身感覺不到圖像是被現實到了本地還是遠程的屏幕上

問題7. 請問在docker上運行的gui應用,應用間的互操作性如何保障?x11協議應該只能轉發顯示數據,無法轉發實際數據(如電子表格中的數據,用以粘貼到其他打開的文檔文件中),是否有其他協議可以保證互操作性?

林帆:目前看來互操作的話只能用其他協議代替X11了,比如VNC或者FreeNX。X11協議中,剪貼板的數據都是保存在X的客戶端,兩個遠程窗口之間不能共享

 

 

Docker: Ubuntu使用VNC運行基於Docker容器里的桌面系統

https://blog.csdn.net/chengly0129/article/details/70215018

https://github.com/fcwu/docker-ubuntu-vnc-desktop


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM