華文網

selenium結合docker構建分散式測試環境

selenium是目前web和app自動化測試的主要框架。對於web自動化測試而言,由於selenium2.0以後socker伺服器由本地流覽器自己啟動且直接通過流覽器原生API動作頁面,故越來越多的人不再使用selenium RC了。大家使用的大多數是selenium-client,

python版本的selenium-client最新版本是3.3.3(2017-04-04發佈),卻忽略了selenium server!事實上在大型的Grid分散式佈局中必須要使用selenium server,我也會對這個佈局的使用做一些必要的解釋。在開始這個話題之前我說明兩點內容:

第一、寫selenium結合docker的使用只是個縮影,其實我想讓大家瞭解使用docker,你可以不精通但是你得會用!!!

第二、我不太想寫一些關於selenium的一些基礎操作,如:browser.get(×××),browser.find_element_by_id(×××)....這些大家都會,不會可以查一些文檔都會有相應的解釋,

對我自己而言我想記錄的是一些關於比較高級點的話題,或者在自動化過程中遇到的難題(比如上篇操作flash),又或者selenium中大家忽略的一些方法的使用。

廢話說了不少,開始我們的話題selenium結合docker構建分散式測試環境。

1.瞭解Selenium Standalone Server的使用

上圖中的selenium hub類似於一個中央處理器,

selenium node是遠端需要執行測試的節點,selenium Test case是運行在hub上的測試用例。

如何啟動一個selenium hub?

首先需要java的運行環境,在終端中輸入java -jar selenium-server-standalone-x.xx.x.jar -role hub -參數。

關於這個啟動的參數其實是需要我們來關注的。我們輸入java -jar selenium-server-standalone-2.52.0.jar -role hub -help下面列出來很多啟動參數,我相信你應該能看得懂,在下面的介紹中我也會提到一些參數。

如何向selenium hub中註冊資訊?

在終端中輸入java -jar selenium-server-standalone-x.xx.x.jar -role node -參數。

同理,我們輸入java -jar selenium-server-standalone-2.52.0.jar -role node -help獲取一些啟動node的參數說明。

2.瞭解docker

說完了Grid的一些原理,

我們來看看docker關於它的說明自行百度。我對它的簡單理解如下:

docker就像個貨船,貨船是幹嘛的?裝集裝箱的! 那麼這些集裝箱是什麼?集裝箱是一個個小的容器! 容器是什麼? 容器就是一個個搭建有簡易linux系統的特定應用,比如這個容器只搭建了java環境或者只搭建了apache環境! 容器如何啟動它? 通過鏡像來啟動! 鏡像怎麼來的? 通過從鏡像源pull或者自己構建鏡像!

自言自語一會,不知道你是否明白我說什麼了,

不明白也沒關係,我們結合搭建分散式環境這個應用,你應該會明白!

說完了docker是什麼,我們著手使用!

1.如何安裝docker?

如何安裝docker百度上有很多它的說明,由於我的是windows系統,關於它的安裝使用推薦文章如下:

http://www.jianshu.com/p/4052926bc12c這篇文章講述了用docker搭建spalsh伺服器,裡面有詳細的關於docker的安裝使用

2.如何獲取鏡像?

我們用xshell或者CRT連接docker後,執行如下命令:

3.如何啟動這2個鏡像?

上文提到了我們先啟動一個hub,

docker啟動命令如下:

Sikilu$ docker run -p 5555:4444 -d --name 'selenium_hub' selenium/hub做一些簡單的說明:

run:通過鏡像啟動一個容器

-p:埠映射,5555是容器宿主機的埠就是我們docker這個輪船的埠,4444是我們容器的埠就是我們集裝箱的埠。這說明了我們把容器的4444埠開放給docker主機的5555埠,那麼我們就可以通過docker主機的5555埠來訪問容器了,有點囉嗦~~~

-d:docker後臺運行這個容器,我們知道運行server-standalone-2.52.0.jar這個包實際上是啟動一個socket程式的,是在一個while迴圈中的。如果不啟用後臺運行的話,在xshell當前視窗是不能進行其他的操作的,當然你要再開一個視窗連接docker也可以。

--name:指定容器運行的別名,如果不指定會隨機生成一個。

selenium/hub:就是我們要運行的鏡像檔。

啟動完hub後,我們啟動一個node,啟動node命令如下:

docker run -P -d --link selenium_hub:hub selenium/node-firefox做一些簡單的說明:

run:和上文相同

-P:隨機生成映射埠號,上文中的-p是指定特定的埠號,這裡面是node我們並不需要知道容器內部的埠號,當然你要指定也可以,埠號不要衝突即可。

-d:後臺運行與上文相同。

--link:說明我們這個容器是依賴上文中我們生成的容器selenium_hub,後面我們會提到link的使用。

selenium_hub:hub:前面的selenium_hub是我們上文中通過selenium/hub鏡像啟動容器的別名;後面的hub一定要寫成hub或者HUB,寫成其他啟動失敗,為什麼這樣我們後面會和--link一起說明。

selenium/node-firefox:node的鏡像。

啟動了selenium/hub與selenium/node後,我們運行docker ps有如下資訊:

我們看出來相應的一些啟動資訊。

CONTAINER ID:容器的id號,隨機生成,我們可以對他進行docker stop +id號、docker start +id號,或者docker rm+id號(刪除該容器)

IMAGE:我們利用到的鏡像檔。

CMMAND:容器啟動時執行的命令,有Dockerfile檔指定,後面提到!

PORTS:容器的一些埠資訊。

NAMES:注意到,在啟動node時我們沒有指定--name屬性,所以他隨機命名了sleepy_bhabha,而啟動hub我們指定了--name屬性,hub容器的name為我們指定的selenium-hub

由於我們是在後臺啟動這2個鏡像檔的,我們想要看容器啟動的log怎麼辦,以selenium_hub為例子,我們輸入docker logs selenium_hub有如下資訊:

這些資訊與我們在本地PC機上使用selenium-server-standalone-×××.jar無異。同理我們可以用docker logs sleepy_bhabha查看node的啟動資訊。

做完這一切我們在流覽器中輸入http://192.168.99.100:5555/grid/console,有如下資訊:

可以看出來,我們的hub中有個新註冊的裝有firefox流覽器且版本號為50.0的node節點,我們本地寫個簡單的腳本來測試下這個簡單的grid佈局代碼如下:

#coding=utf-8 from selenium import webdriver firefox_capabilities ={ "browserName": "firefox", "version": "50.0",#注意版本號一定要寫對 "platform": "ANY", "javascriptEnabled": True, "marionette": True, } browser=webdriver.Remote("http://192.168.99.100:5555/wd/hub",desired_capabilities=firefox_capabilities)#注意埠號5555是我們上文中映射的宿主機埠號 browser.get("http://www.baidu.com") browser.get_screenshot_as_file("D:/baidu.png") browser.close

代碼比較簡單,就是打開node端的firefox流覽器,輸入百度後截圖,一切看起來都是那麼順利,但是細心的同事可能發現至少有以前2個問題:

第一、我們對百度的截圖中文是亂碼的,這個不能忍啊!!!

第二、我們再次在IDE運行下這個腳本,發現一直處於阻塞狀態也不報錯,得不到hub遠端的執行資訊~~

對於問題一,因為我們要涉及到關於docker的鏡像製作等操作我們放在後面介紹,先來看看第二個問題,為什麼我們再次運行這個腳本無法正常執行?

首先,這是和docker無關的,你在真實的PC機上也是同樣的結果!既然和docker無關那就是selenium-server-standalone-3.3.1.jar這個包的bug了?答案是:也不是!!那到底是什麼我們來看看是什麼原因。我們打開hub的log(docker logs selenium_hub)。截圖如下:

看出來,第一次我們得到了一個包含有Capabilties請求的request後成功的建立了一個session,這個對應於我們第一次在IDE運行上文的腳本;我們第二次再次運行這個腳本,雖然hub得到了這個請求,但是沒有成功的建立了一個新的session。那麼問題可能出在node端它不容許建立新的session,所以我們一直處於阻塞狀態(阻塞的時間由node的啟動參數newSessionWaitTimeout決定),除非我們的第一個session被人為的或者由於超時被自動切斷後,才能重新建立!

問題知道了,我們如何改進呢?對的就是改變node的啟動參數。我們seleniu/node鏡像默認的關鍵參數如下:

"capabilities": [ { "maxInstances": $NODE_MAX_INSTANCES,#最大的流覽器實例 ...... } "maxSession": $NODE_MAX_SESSION #最大的Session數目

由於預設的maxSession為5而maxInstances為1,所以取最小的一個,node端只運行有一個session的存在,所以我們第二次運行處於阻塞狀態!!這些資訊我們會在後面對其鏡像的構建文件Dockerfile講解時提到。作者為什麼要將maxInstances設置為1?我的理解是:一般用到Grid佈局的都是一些比較大型的測試體系,一般環境搭建好了測試腳本寫好了保證一天有一個測試結果就好。我們默認的timeout時間是30000S,這個從上面我們hub的開機記錄可以看出來,也就是說如果hub在30000s內沒有執行任何操作就會自動切斷!這個timeout的時間是相當的長,關於這個timeout的時間長短我覺得與你的testcase有關,比如你在腳本中有個比較耗時的操作例如Sleep(100),睡眠100S再進行後續操作,如果你的timeout設置為30s,那麼在30S的時候hub會主動切斷這個連接,也就是說你後面的用例是不會再執行了....這個就是個仁者見仁,智者見智的事情了,但是我覺得把timeout搞長點好點。想要多次調試腳本,大不了我們把maxInstances與maxSession設置數目大點就了。實在不行你也可以先docker stop+node 容器的ID,再docker start +node 容器ID就好了!

說了第二個問題的一些看法,我們重點來看看如何解決第一個問題,在解決第一個問題的同時,我們修改一些配置,一併把第二個問題給解決了!!

Base是selenium鏡像的基礎,裡面的Dockerfile除了在Ubuntu鏡像的基礎上安裝了一些工具包,主要工作如下:

1.還有搭建了一個java運行環境,用來運行後來的selenium-server-standalone-3.3.1.jar

Hub資料夾裡面的Dockerfile就是用來build selenium/hub鏡像的,是基於上面的Base,主要工作如下:

1.定義了node啟動的一些參數,發現它把裡面的timeout參數改成30s了。我並沒有pull最新的selenium/hub,你們現在pull的可能timeout參數就是30s,我的是30000s。

2.定義了容器啟動的腳本entry_point.sh,並把他複製到容器的/opt/bin下

NodeBase是一切node鏡像的基礎,我們查看裡面的Dockerfile發現它是基於我們上面提到的Base的,主要工作如下:

1.定義了node容器的啟動腳本entry_point.sh並複製到容器的/opt/bin/下。

NodeFirefox是用來build我們pull下來的selenium/node-firefox它是基於我們上面提到的NodeBase。我們查看它的Dokcerfile檔,發現它的主要工作如下:

3.設置fire-node的一些啟動參數,我們清楚的看到NODE_MAX_INSTANCES 1與ENV NODE_MAX_SESSION 1的配置,所以如何要改變我們問題二的情況,在重新構建鏡像的時候,就要重新定義這些環境變數了。

對上面的解釋做個說明:

1.Dockerfile是用來build鏡像的。指令為docker build -t 鏡像名稱 Dockerfile路徑,例如:docker build -t selenium/my-firefxo-node . 用當前路徑下的Dockerfile檔來創建一個 selenium/my-firefxo-node鏡像檔。

2.Dockerfile一些基礎知識可以百度瞭解,無非就是一些shell指令集的大集合。

說完了這些,我們就來解決我們遇到的第一個和第二個問題,思路很簡單,對的,就是利用的selenium/firefox-node重新構建鏡像。

截圖中文亂碼的問題我的考慮如下:

2.僅僅做了1的操作後,我們重新運行build的鏡像,發現還是亂碼,查閱資料明白可能是firefox必須支援相應的中文字體才可以避免亂碼的情況,所以我們最終的Dockerfile內容如下:

FROM selenium/node-firefox #改變node的啟動參數 ENV NODE_MAX_INSTANCES 10 ENV NODE_MAX_SESSION 10 # 配置中文 RUN sudo locale-gen zh_CN.UTF-8 && sudo DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales RUN sudo locale-gen zh_CN.UTF-8 ENV LANG zh_CN.UTF-8 ENV LANGUAGE zh_CN:zh ENV LC_ALL zh_CN.UTF-8 #更新軟體包索引 RUN sudo apt-get update -qqy #安裝基本字體 RUN sudo apt-get -qqy --no-install-recommends install fonts-ipafont-gothic xfonts-100dpi xfonts-75dpi xfonts-cyrillic xfonts-scalable #安裝文泉驛微米黑字體 RUN sudo apt-get -qqy install ttf-wqy-microhei && sudo ln /etc/fonts/conf.d/65-wqy-microhei.conf /etc/fonts/conf.d/69-language-selector-zh-cn.conf

說到這遇到一個現實的問題是,我們建立了上面的Dokcerfile檔,但是是在windows平臺上的,例如我是放在D盤的Sikilu這個資料夾下的,我們docker主機如何訪問這個Sikilu資料夾呢?

首先,我們要明白個道理,docker是不能運行在windows平臺,我們能在windows平臺使用是因為它運行在Oracle VM VirtualBox裡面的!!所以在windows平臺搭建docker時給你安裝了個VirtualBox虛擬機器。這就好辦了,我們打開這個虛擬機器把D盤的Sikilu設置為共用資料夾就好了。具體截圖如下:

設置完後,我們重啟虛擬機器中名稱為default這個docker主機。

我們在Xshell中切換到根目錄cd /發現了共用的資料夾:

我們把上面的Dockerfile放到我們共用的這個資料夾下並切換進去。執行docker build -t selenium/my_node-firefox .

build的過程可能要點時間最終build成功!我們運行docker images

可以看到我們build的鏡像。我們先停掉上面用selenium/node-firefox啟動的容器:

我們運行如下指令:docker run -P -d --link selenium_hub:hub selenium/my_node-firefox

我們運行上面的測試腳本,發現問題能得到有效的解決,當然運行超過10次就又阻塞了,原因上面說的很清楚了我們的最大session設置了10!

還有一個問題:我們如何建立其他版本號的node-firefox?上面說了我們pull下來的是50.0的,比如我要構建集群測試每台機器上不同版本的firefox,那麼我們就要創建不同版本的鏡像!

這邊有2中思路,第一種思路想法也簡單

2.運行我們上面build的selenium/my_node-firefox這個鏡像把這個共用的資料夾掛載進去。(-v參數)

docker run -P -v /Sikilu/:/Sikilu --link selenium_hub:hub selenium/my_node-firefox

3.我們刪除該容器/opt下的firefox-50.0這個流覽器,同時解壓掛載的宿主機Sikilu中的特定版本的firefox到/opt目錄

4.運行rm -rf /usr/bin/firefox

5.ln -fs /opt/firefox-$FIREFOX_VERSION/firefox /usr/bin/firefox

6.exit這個容器運行docker commit -m "firefox-47.0.2" 當前容器的ID 鏡像名稱,例如docker commit -m "firefox-47.0.2" 2d96630b4f07(我們進入的容器id號) selenium/node-firefox47.0.2(新的鏡像名稱)

上面的一系列操作,我們得到了一個特定版本的鏡像,下次啟動我們run這個鏡像就可以了。

第二種思路,在我們新build的selenium/my_node-firefox這個基礎新建Dockerfile,重新構建鏡像(建議這種方式畢竟高端點...)內容如下:

同樣,我們切換到共用的Sikilu資料夾中運行:docker build -t selenium/node-firefox47.0.2 .

如果網路較慢是特別費時間的,這時候去聽音樂去吧,一段時間後建立一個firefox版本為47.0.2的鏡像,當我們run這個鏡像來啟動容器時,註冊進hub的就是這個版本的流覽器!!

最後一個問題收尾,就是我們最開始提到的run一個鏡像時的--link的參數。

docker通過link將source container中定義的環境變數全部導入到received container中。我們先來看看上面提到NodeBase檔下的entry_point.sh這個腳本,我們截取最關鍵的一部分:就是執行selenium-server-standalone.jar這個jar包的一段:

xvfb-run -n $SERVERNUM --server-args="-screen 0 $GEOMETRY -ac +extension RANDR" java ${JAVA_OPTS} -jar /opt/selenium/selenium-server-standalone.jar -role node -hub http://$HUB_PORT_4444_TCP_ADDR:$HUB_PORT_4444_TCP_PORT/grid/register -nodeConfig /opt/selenium/config.json ${SE_OPTS} & NODE_PID=$!

上面的$HUB_PORT_4444_TCP_PORT表示我們hub的埠號,$HUB_PORT_4444_TCP_ADDR這個代表hub的IP地址,這些是怎麼來的?其實這個是因為我們使用link參數,docker自動生成這些參數。我們 進入到由鏡像selenium/my_node-firefox啟動的容器(sudo docker exec -it 24c5fb9a649a /bin/bash),輸入env

發現了這2個欄位,其實這個容器的環境變數被分成5個部分,一個部分就是ALIASDB_PORT開頭的一系列變數,這些變數會有很組,每組變數的命名格式如下:

其中是我們source container的別名;是在Dockerfile中使用EXPOSE匯出的埠,還有docker run 的時候使用-p匯出的埠;則是這些埠對應的協議。

現在明白上文中為什麼--link selenium/hub冒號後面為什麼要跟hub或者HUB了吧,只有寫成這樣才會找到HUB_PORT_4444_TCP_PORT與$HUB_PORT_4444_TCP_ADDR這2個變數,免得容器是啟動不起來的!!

到這裡結束吧,本來還想多寫點關於docker的用法知識。但是打字打的想吐了,可能本文中一些東西說的不清不楚,但是我相信您通過查閱資料一定能得到相應的解決!!

在xshell當前視窗是不能進行其他的操作的,當然你要再開一個視窗連接docker也可以。

--name:指定容器運行的別名,如果不指定會隨機生成一個。

selenium/hub:就是我們要運行的鏡像檔。

啟動完hub後,我們啟動一個node,啟動node命令如下:

docker run -P -d --link selenium_hub:hub selenium/node-firefox做一些簡單的說明:

run:和上文相同

-P:隨機生成映射埠號,上文中的-p是指定特定的埠號,這裡面是node我們並不需要知道容器內部的埠號,當然你要指定也可以,埠號不要衝突即可。

-d:後臺運行與上文相同。

--link:說明我們這個容器是依賴上文中我們生成的容器selenium_hub,後面我們會提到link的使用。

selenium_hub:hub:前面的selenium_hub是我們上文中通過selenium/hub鏡像啟動容器的別名;後面的hub一定要寫成hub或者HUB,寫成其他啟動失敗,為什麼這樣我們後面會和--link一起說明。

selenium/node-firefox:node的鏡像。

啟動了selenium/hub與selenium/node後,我們運行docker ps有如下資訊:

我們看出來相應的一些啟動資訊。

CONTAINER ID:容器的id號,隨機生成,我們可以對他進行docker stop +id號、docker start +id號,或者docker rm+id號(刪除該容器)

IMAGE:我們利用到的鏡像檔。

CMMAND:容器啟動時執行的命令,有Dockerfile檔指定,後面提到!

PORTS:容器的一些埠資訊。

NAMES:注意到,在啟動node時我們沒有指定--name屬性,所以他隨機命名了sleepy_bhabha,而啟動hub我們指定了--name屬性,hub容器的name為我們指定的selenium-hub

由於我們是在後臺啟動這2個鏡像檔的,我們想要看容器啟動的log怎麼辦,以selenium_hub為例子,我們輸入docker logs selenium_hub有如下資訊:

這些資訊與我們在本地PC機上使用selenium-server-standalone-×××.jar無異。同理我們可以用docker logs sleepy_bhabha查看node的啟動資訊。

做完這一切我們在流覽器中輸入http://192.168.99.100:5555/grid/console,有如下資訊:

可以看出來,我們的hub中有個新註冊的裝有firefox流覽器且版本號為50.0的node節點,我們本地寫個簡單的腳本來測試下這個簡單的grid佈局代碼如下:

#coding=utf-8 from selenium import webdriver firefox_capabilities ={ "browserName": "firefox", "version": "50.0",#注意版本號一定要寫對 "platform": "ANY", "javascriptEnabled": True, "marionette": True, } browser=webdriver.Remote("http://192.168.99.100:5555/wd/hub",desired_capabilities=firefox_capabilities)#注意埠號5555是我們上文中映射的宿主機埠號 browser.get("http://www.baidu.com") browser.get_screenshot_as_file("D:/baidu.png") browser.close

代碼比較簡單,就是打開node端的firefox流覽器,輸入百度後截圖,一切看起來都是那麼順利,但是細心的同事可能發現至少有以前2個問題:

第一、我們對百度的截圖中文是亂碼的,這個不能忍啊!!!

第二、我們再次在IDE運行下這個腳本,發現一直處於阻塞狀態也不報錯,得不到hub遠端的執行資訊~~

對於問題一,因為我們要涉及到關於docker的鏡像製作等操作我們放在後面介紹,先來看看第二個問題,為什麼我們再次運行這個腳本無法正常執行?

首先,這是和docker無關的,你在真實的PC機上也是同樣的結果!既然和docker無關那就是selenium-server-standalone-3.3.1.jar這個包的bug了?答案是:也不是!!那到底是什麼我們來看看是什麼原因。我們打開hub的log(docker logs selenium_hub)。截圖如下:

看出來,第一次我們得到了一個包含有Capabilties請求的request後成功的建立了一個session,這個對應於我們第一次在IDE運行上文的腳本;我們第二次再次運行這個腳本,雖然hub得到了這個請求,但是沒有成功的建立了一個新的session。那麼問題可能出在node端它不容許建立新的session,所以我們一直處於阻塞狀態(阻塞的時間由node的啟動參數newSessionWaitTimeout決定),除非我們的第一個session被人為的或者由於超時被自動切斷後,才能重新建立!

問題知道了,我們如何改進呢?對的就是改變node的啟動參數。我們seleniu/node鏡像默認的關鍵參數如下:

"capabilities": [ { "maxInstances": $NODE_MAX_INSTANCES,#最大的流覽器實例 ...... } "maxSession": $NODE_MAX_SESSION #最大的Session數目

由於預設的maxSession為5而maxInstances為1,所以取最小的一個,node端只運行有一個session的存在,所以我們第二次運行處於阻塞狀態!!這些資訊我們會在後面對其鏡像的構建文件Dockerfile講解時提到。作者為什麼要將maxInstances設置為1?我的理解是:一般用到Grid佈局的都是一些比較大型的測試體系,一般環境搭建好了測試腳本寫好了保證一天有一個測試結果就好。我們默認的timeout時間是30000S,這個從上面我們hub的開機記錄可以看出來,也就是說如果hub在30000s內沒有執行任何操作就會自動切斷!這個timeout的時間是相當的長,關於這個timeout的時間長短我覺得與你的testcase有關,比如你在腳本中有個比較耗時的操作例如Sleep(100),睡眠100S再進行後續操作,如果你的timeout設置為30s,那麼在30S的時候hub會主動切斷這個連接,也就是說你後面的用例是不會再執行了....這個就是個仁者見仁,智者見智的事情了,但是我覺得把timeout搞長點好點。想要多次調試腳本,大不了我們把maxInstances與maxSession設置數目大點就了。實在不行你也可以先docker stop+node 容器的ID,再docker start +node 容器ID就好了!

說了第二個問題的一些看法,我們重點來看看如何解決第一個問題,在解決第一個問題的同時,我們修改一些配置,一併把第二個問題給解決了!!

Base是selenium鏡像的基礎,裡面的Dockerfile除了在Ubuntu鏡像的基礎上安裝了一些工具包,主要工作如下:

1.還有搭建了一個java運行環境,用來運行後來的selenium-server-standalone-3.3.1.jar

Hub資料夾裡面的Dockerfile就是用來build selenium/hub鏡像的,是基於上面的Base,主要工作如下:

1.定義了node啟動的一些參數,發現它把裡面的timeout參數改成30s了。我並沒有pull最新的selenium/hub,你們現在pull的可能timeout參數就是30s,我的是30000s。

2.定義了容器啟動的腳本entry_point.sh,並把他複製到容器的/opt/bin下

NodeBase是一切node鏡像的基礎,我們查看裡面的Dockerfile發現它是基於我們上面提到的Base的,主要工作如下:

1.定義了node容器的啟動腳本entry_point.sh並複製到容器的/opt/bin/下。

NodeFirefox是用來build我們pull下來的selenium/node-firefox它是基於我們上面提到的NodeBase。我們查看它的Dokcerfile檔,發現它的主要工作如下:

3.設置fire-node的一些啟動參數,我們清楚的看到NODE_MAX_INSTANCES 1與ENV NODE_MAX_SESSION 1的配置,所以如何要改變我們問題二的情況,在重新構建鏡像的時候,就要重新定義這些環境變數了。

對上面的解釋做個說明:

1.Dockerfile是用來build鏡像的。指令為docker build -t 鏡像名稱 Dockerfile路徑,例如:docker build -t selenium/my-firefxo-node . 用當前路徑下的Dockerfile檔來創建一個 selenium/my-firefxo-node鏡像檔。

2.Dockerfile一些基礎知識可以百度瞭解,無非就是一些shell指令集的大集合。

說完了這些,我們就來解決我們遇到的第一個和第二個問題,思路很簡單,對的,就是利用的selenium/firefox-node重新構建鏡像。

截圖中文亂碼的問題我的考慮如下:

2.僅僅做了1的操作後,我們重新運行build的鏡像,發現還是亂碼,查閱資料明白可能是firefox必須支援相應的中文字體才可以避免亂碼的情況,所以我們最終的Dockerfile內容如下:

FROM selenium/node-firefox #改變node的啟動參數 ENV NODE_MAX_INSTANCES 10 ENV NODE_MAX_SESSION 10 # 配置中文 RUN sudo locale-gen zh_CN.UTF-8 && sudo DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales RUN sudo locale-gen zh_CN.UTF-8 ENV LANG zh_CN.UTF-8 ENV LANGUAGE zh_CN:zh ENV LC_ALL zh_CN.UTF-8 #更新軟體包索引 RUN sudo apt-get update -qqy #安裝基本字體 RUN sudo apt-get -qqy --no-install-recommends install fonts-ipafont-gothic xfonts-100dpi xfonts-75dpi xfonts-cyrillic xfonts-scalable #安裝文泉驛微米黑字體 RUN sudo apt-get -qqy install ttf-wqy-microhei && sudo ln /etc/fonts/conf.d/65-wqy-microhei.conf /etc/fonts/conf.d/69-language-selector-zh-cn.conf

說到這遇到一個現實的問題是,我們建立了上面的Dokcerfile檔,但是是在windows平臺上的,例如我是放在D盤的Sikilu這個資料夾下的,我們docker主機如何訪問這個Sikilu資料夾呢?

首先,我們要明白個道理,docker是不能運行在windows平臺,我們能在windows平臺使用是因為它運行在Oracle VM VirtualBox裡面的!!所以在windows平臺搭建docker時給你安裝了個VirtualBox虛擬機器。這就好辦了,我們打開這個虛擬機器把D盤的Sikilu設置為共用資料夾就好了。具體截圖如下:

設置完後,我們重啟虛擬機器中名稱為default這個docker主機。

我們在Xshell中切換到根目錄cd /發現了共用的資料夾:

我們把上面的Dockerfile放到我們共用的這個資料夾下並切換進去。執行docker build -t selenium/my_node-firefox .

build的過程可能要點時間最終build成功!我們運行docker images

可以看到我們build的鏡像。我們先停掉上面用selenium/node-firefox啟動的容器:

我們運行如下指令:docker run -P -d --link selenium_hub:hub selenium/my_node-firefox

我們運行上面的測試腳本,發現問題能得到有效的解決,當然運行超過10次就又阻塞了,原因上面說的很清楚了我們的最大session設置了10!

還有一個問題:我們如何建立其他版本號的node-firefox?上面說了我們pull下來的是50.0的,比如我要構建集群測試每台機器上不同版本的firefox,那麼我們就要創建不同版本的鏡像!

這邊有2中思路,第一種思路想法也簡單

2.運行我們上面build的selenium/my_node-firefox這個鏡像把這個共用的資料夾掛載進去。(-v參數)

docker run -P -v /Sikilu/:/Sikilu --link selenium_hub:hub selenium/my_node-firefox

3.我們刪除該容器/opt下的firefox-50.0這個流覽器,同時解壓掛載的宿主機Sikilu中的特定版本的firefox到/opt目錄

4.運行rm -rf /usr/bin/firefox

5.ln -fs /opt/firefox-$FIREFOX_VERSION/firefox /usr/bin/firefox

6.exit這個容器運行docker commit -m "firefox-47.0.2" 當前容器的ID 鏡像名稱,例如docker commit -m "firefox-47.0.2" 2d96630b4f07(我們進入的容器id號) selenium/node-firefox47.0.2(新的鏡像名稱)

上面的一系列操作,我們得到了一個特定版本的鏡像,下次啟動我們run這個鏡像就可以了。

第二種思路,在我們新build的selenium/my_node-firefox這個基礎新建Dockerfile,重新構建鏡像(建議這種方式畢竟高端點...)內容如下:

同樣,我們切換到共用的Sikilu資料夾中運行:docker build -t selenium/node-firefox47.0.2 .

如果網路較慢是特別費時間的,這時候去聽音樂去吧,一段時間後建立一個firefox版本為47.0.2的鏡像,當我們run這個鏡像來啟動容器時,註冊進hub的就是這個版本的流覽器!!

最後一個問題收尾,就是我們最開始提到的run一個鏡像時的--link的參數。

docker通過link將source container中定義的環境變數全部導入到received container中。我們先來看看上面提到NodeBase檔下的entry_point.sh這個腳本,我們截取最關鍵的一部分:就是執行selenium-server-standalone.jar這個jar包的一段:

xvfb-run -n $SERVERNUM --server-args="-screen 0 $GEOMETRY -ac +extension RANDR" java ${JAVA_OPTS} -jar /opt/selenium/selenium-server-standalone.jar -role node -hub http://$HUB_PORT_4444_TCP_ADDR:$HUB_PORT_4444_TCP_PORT/grid/register -nodeConfig /opt/selenium/config.json ${SE_OPTS} & NODE_PID=$!

上面的$HUB_PORT_4444_TCP_PORT表示我們hub的埠號,$HUB_PORT_4444_TCP_ADDR這個代表hub的IP地址,這些是怎麼來的?其實這個是因為我們使用link參數,docker自動生成這些參數。我們 進入到由鏡像selenium/my_node-firefox啟動的容器(sudo docker exec -it 24c5fb9a649a /bin/bash),輸入env

發現了這2個欄位,其實這個容器的環境變數被分成5個部分,一個部分就是ALIASDB_PORT開頭的一系列變數,這些變數會有很組,每組變數的命名格式如下:

其中是我們source container的別名;是在Dockerfile中使用EXPOSE匯出的埠,還有docker run 的時候使用-p匯出的埠;則是這些埠對應的協議。

現在明白上文中為什麼--link selenium/hub冒號後面為什麼要跟hub或者HUB了吧,只有寫成這樣才會找到HUB_PORT_4444_TCP_PORT與$HUB_PORT_4444_TCP_ADDR這2個變數,免得容器是啟動不起來的!!

到這裡結束吧,本來還想多寫點關於docker的用法知識。但是打字打的想吐了,可能本文中一些東西說的不清不楚,但是我相信您通過查閱資料一定能得到相應的解決!!