Docker——使測試更美好

第一次嘗試使用docker是在去年六月。

當(dāng)時(shí)基于一些原因,筆者想把UI自動化用例放到docker里執(zhí)行。但發(fā)現(xiàn)在docker中執(zhí)行UI測試不是那么靠譜,于是就老老實(shí)實(shí)地用windows測試機(jī),搞了個(gè)jenkins slave來執(zhí)行用例。前不久,有一鍵部署測試環(huán)境的需求,就想到用docker完成這個(gè)工作?,F(xiàn)在這個(gè)story已經(jīng)算是比較完整了,分享給大家。

基于docker的測試環(huán)境一鍵部署

無論是開發(fā)自測環(huán)境的搭建還是測試環(huán)境的部署,一套環(huán)境從無到有的過程往往意味著各種下載與配置。這就好比你去一個(gè)地方,要先坐地鐵,再轉(zhuǎn)公交,非但要轉(zhuǎn)公交,從公交車上下來,還需要走15分鐘的路。而一鍵部署就好比出門打了一輛車,你在車上聽歌,微信,搖一搖。你只需等司機(jī)告訴你到了,然后開開心心下車就好。

基本思路:

圖里的頭像分別代表:git,docker,jenkins以及需要部署的機(jī)器。

基本的思路是:先按照需求build 基礎(chǔ)鏡像。封裝與復(fù)用的概念想必大家都聽過,build 基礎(chǔ)鏡像其實(shí)也是如此。把一些依賴的,不變的組件build 進(jìn)基礎(chǔ)鏡像,比如tomcat,比如jdk。再把變化的那部分用git 以及jenkins 來管理,比如war 包,比如配置文件。之后把不變的那部分與變的那部分組合起來,build成一個(gè)全新的鏡像(—個(gè)全新的,能被復(fù)用的,不需要配置的,run起來就是一個(gè)服務(wù)的鏡像)。最后只需在部署的機(jī)器上把這個(gè)鏡像run起來即可。

一個(gè)應(yīng)用一般包含不止一個(gè)服務(wù),服務(wù)之間注冊與發(fā)現(xiàn)的機(jī)制各有不同。在用docker完成一鍵部署的時(shí)候,服務(wù)之間的注冊與發(fā)現(xiàn)問題已經(jīng)轉(zhuǎn)換為docker間的通信問題。

實(shí)現(xiàn)docker間通信的基礎(chǔ)方法有兩個(gè):

使用docker的端口映射,以宿主機(jī)為媒介完成docker間通信;

使用docker link。

兵無常勢,水無常形。這兩種方式各有利弊,只要靈活運(yùn)用就好。

具體實(shí)現(xiàn):

照著上面的思路,筆者會先說如何構(gòu)建一個(gè)單獨(dú)的服務(wù)鏡像,然后說如何讓服務(wù)間相互發(fā)現(xiàn),直至成為一個(gè)完整的應(yīng)用。

以構(gòu)建一個(gè)webApplication的鏡像為例:

1、build一個(gè)基礎(chǔ)鏡像,這里需求各不相同,不細(xì)說。

2、在jenkins新建一個(gè)job,代碼用git管理

分支是一個(gè)變量,用參數(shù)化構(gòu)建來管理。類似的,所有可能會發(fā)生的變化都用參數(shù)化構(gòu)建來管理,不一一列舉。

3、在jenkins里新建Excute Shell,大部分你想實(shí)現(xiàn)的功能都可以用腳本來實(shí)現(xiàn)。比如編譯代碼打war包,比如你想自定義tomcat啟動時(shí)的JAVA_OPTS。

4、當(dāng)然最不可缺少的就是Dockerfile。

5、然后就是構(gòu)建鏡像,并push到私人倉庫,清理空間。

此時(shí),一個(gè)webApplication的鏡像已經(jīng)在你的私人倉庫里。但鏡像是不能提供服務(wù)的,鏡像需要run成容器,docker run有很多門道。只需在你的docker client輸入docker run --help,你就會明白我所言非虛。

上面提到過,docker間通信有兩種基本的方法,采用哪種方式?jīng)Q定了如何run。下面會分別說一說:

1)使用端口映射實(shí)現(xiàn)docker間通信

端口映射使用的是docker run的 -p 參數(shù)。如 -p 8081:8080,代表了宿主機(jī)的8081端口映射了容器內(nèi)的8080端口。你訪問宿主機(jī)的8081端口,實(shí)際訪問的是容器內(nèi)的8080端口提供的服務(wù)。假如此時(shí)容器內(nèi)的8080端口監(jiān)聽的是tomcat服務(wù),你就能在瀏覽器里看到那只可愛的貓了。

舉個(gè)栗子,這個(gè)webApplication需要一個(gè)mongoDB服務(wù),這個(gè)mongoDB也運(yùn)行在容器內(nèi)。那么問題來了,如果我們能知道MongoDB所在容器的ip地址,只需使用類似docker run的--add-host參數(shù)就能指定被依賴服務(wù)的地址。但偏偏,docker run的容器ip是很難指定的。除非進(jìn)到運(yùn)行mongoDB的那個(gè)docker容器里查看ip地址,否則就不能告知webApplication,mongoDB服務(wù)的地址。但既然是一鍵部署,當(dāng)然不能用手工的方式去查看IP了!怎么辦?

很簡單,只需要在run mongo容器的時(shí)候把mongoDB的服務(wù)端口映射到宿主機(jī)上,如 -p 27017:27017。那么webApplication只需訪問宿主機(jī)的27017端口,就是在訪問docker中的mongoDB服務(wù)了。宿主機(jī)的ip可以是固定的,把被依賴者的服務(wù)端口映射給宿主機(jī),依賴者訪問宿主機(jī)的映射端口。一個(gè)應(yīng)用的各個(gè)服務(wù)就能用這種方式相互發(fā)現(xiàn)了。

但有個(gè)問題,假如宿主機(jī)的27017被占用了呢?

這個(gè)簡單,改成-p 27018:27017就好!

如果webApplication指定訪問的是27017端口呢?

讓開發(fā)工程師去改代碼?

不是不可以。但是——

幸好還有一種方法。

2)Docker link

用docker run的 --link參數(shù)能實(shí)現(xiàn)docker container之間的連接。

1、run一個(gè)mongoDB服務(wù),用 --name 參數(shù)指定container的名字為 mongo

2、查明在webApplication里依賴的mongoDB的hostName為my-mongo

3、用--link參數(shù),啟動webApplication的container

4、webApplication容器內(nèi)hosts文件下就有了下面這一行

目的已經(jīng)達(dá)到,webApplication已經(jīng)知道m(xù)ongo的ip地址。無論你有多少個(gè)服務(wù)。只要你理清楚服務(wù)之間的依賴關(guān)系,用--link參數(shù),按順序啟動容器。一個(gè)完整的應(yīng)用就起來了。

但是,用這種方式有個(gè)致命的問題,服務(wù)之間耦合太高。當(dāng)其中一個(gè)服務(wù)不可用,需要重新run container時(shí)。link它的容器也需要重新run,猶如多米諾骨牌。最壞的情況是整個(gè)應(yīng)用的服務(wù)全都需要重新run。如果應(yīng)用包含的服務(wù)很多,那簡直就是噩夢。

在實(shí)踐中,筆者創(chuàng)建了兩套job。給類似DEMO環(huán)境這種專屬機(jī)器部署的時(shí)候筆者用端口映射的方式,專屬機(jī)器上幾乎不可能會有不可避免的端口沖突。在給個(gè)人開發(fā)機(jī)提供部署服務(wù)的時(shí)候,筆者選擇用link的方式。因?yàn)榇藭r(shí)端口沖突的幾率非常大。也不用太擔(dān)心那個(gè)耦合度太高的問題,能在個(gè)人機(jī)器上部署的應(yīng)用,可想而知不會有太多服務(wù)。再者,假如有端口沖突,用戶是不太希望去修改配置的。就像沒有人希望打車的時(shí)候司機(jī)不停問路。

基于docker的jvm監(jiān)控一鍵部署

沒有性能監(jiān)控的性能測試,就像沒有沙拉的蔬菜沙拉。

監(jiān)控至關(guān)重要。

對java應(yīng)用而言,最重要的監(jiān)控是對jvm的監(jiān)控。通過監(jiān)控jvm,你可以了解虛擬機(jī)運(yùn)行時(shí)的狀態(tài),例如Heap、MemoryPool等。通過這些參數(shù)可以分析代碼的缺陷等。

說起jvm的監(jiān)控,大家首先想到的是jconsole,這個(gè)樸實(shí)無華卻又非常實(shí)用的工具。

jconsole

若是監(jiān)控本地java進(jìn)程,只需打開jconsole,選擇對應(yīng)的本地進(jìn)程即可。像這樣

若要監(jiān)控遠(yuǎn)程進(jìn)程,配置也不復(fù)雜,只需要在java進(jìn)程的啟動參數(shù)中加入如下幾個(gè)配置(這里有一些安全配置,不在本文討論范圍之內(nèi))

在jconsole客戶端中連接遠(yuǎn)程進(jìn)程

jconsole實(shí)在是一款很好用的工具

但是,jconsole有一些局限。

有時(shí)候你需要監(jiān)控的遠(yuǎn)程進(jìn)程運(yùn)行在一臺網(wǎng)絡(luò)策略比較復(fù)雜的遠(yuǎn)程機(jī)器上,這時(shí)候使用jconsole就會很頭疼。若是這個(gè)進(jìn)程還運(yùn)行在docker容器內(nèi),那簡直就能讓你的頭爆炸。

怎么解決?

Jconsole是基于JMX的工具。JMX有一套API,稱為MBean。也許我們可以利用MBean寫一套框架,像特洛伊木馬一樣讓它在遠(yuǎn)程機(jī)器上執(zhí)行。這套框架的工作很簡單:收集需要監(jiān)控進(jìn)程的運(yùn)行時(shí)數(shù)據(jù),發(fā)給一個(gè)數(shù)據(jù)狀態(tài)收集工具,比如graphite。這個(gè)數(shù)據(jù)收集工具就像一個(gè)管家,你關(guān)心的所有數(shù)據(jù)它都能告訴你。客戶端只需要保證和這個(gè)數(shù)據(jù)工具的網(wǎng)絡(luò)互通即可。

但無論對誰來說,從零開始寫一套可靠的框架都不是一件太容易的事。維護(hù)和優(yōu)化需要很多的時(shí)間。

幸好,已經(jīng)有了一套現(xiàn)成的方案

JmxTrans

這不僅是一套現(xiàn)成的框架,甚至有現(xiàn)成的鏡像。你要做的就是把鏡像run成容器,照著官方文檔修改一下配置就能使用。如下:

1、啟動容器

2、查看Dockerfile,找到配置文件所在目錄,在筆者的實(shí)踐中,配置文件在 /opt/jmxtrans/conf目錄下

3、新建自己的配置文件

大多數(shù)你可能需要使用的配置,都可以在jmxtrans的官網(wǎng)上找到,但不排除有一些奇特的坑。踩踩更健康。

4、重啟容器,查看jmxtrans的日志是否有報(bào)錯(cuò)信息,我的日志在/opt/jmxtrans/log目錄下。如果你的配置沒有問題,log看起來是這樣的

Graphite

jmxtrans獲取到j(luò)ava進(jìn)程的運(yùn)行時(shí)數(shù)據(jù)后,需要一個(gè)收集并展示的組件。對于jmxtrans而言,這個(gè)組件是一個(gè)"writer"。jmxtrans可以配合很多種"writer"使用。筆者用的是graphite,當(dāng)然也是跑在docker里的。

graphite的api服務(wù)監(jiān)聽在80端口??梢钥吹?,docker run時(shí)映射了宿主機(jī)的80端口,如何處理端口沖突在上篇中已經(jīng)說過。現(xiàn)在只需在瀏覽器中訪問http://${宿主機(jī)ip}:${宿主機(jī)映射端口}

dashbord長這樣:

實(shí)現(xiàn)一鍵部署

現(xiàn)在我們已經(jīng)能用jmxtrans和graphite完成遠(yuǎn)程jvm的監(jiān)控,但配置的過程略顯繁瑣。尤其是每個(gè)jmxtrans都要加入新的配置文件,非常麻煩。所以,筆者也對這套環(huán)境監(jiān)控做了一鍵部署,如下:

1、把jmxtrans的配置文件用git來管理,不同環(huán)境的配置文件用不同的分支。

2、用jenkins job做一鍵部署的載體,在job中拉取git倉庫里的jmxtrans配置文件。

3、把配置文件Add進(jìn)jmxtrans鏡像,build成一個(gè)包含指定配置文件、即插即用的鏡像。

4、啟動graphite容器,上文提過。

5、啟動jmxtrans容器,這時(shí)采用link的方式是極好的.因?yàn)樵趈mxtrans配置文件中聲明的地址,需要在jmxtrans所在docker容器的hosts文件中定義其真實(shí)ip。docker的真實(shí)ip在一鍵部署中是動態(tài)變化的,沒法預(yù)先知道。

然后只需把jenkins的job串聯(lián)起來,監(jiān)控的一鍵部署就完成了。但是,graphite的dashbord實(shí)在是丑。為了心情好,我們需要一個(gè)顏值高的圖表

grafana

依然使用docker

然后在瀏覽器中打開grafana,創(chuàng)建DataSource

配置graphite data source

創(chuàng)建graph

創(chuàng)建所有你想看到的監(jiān)控圖表

比較graphite的圖表,心情豈非好上許多?

本文作者:施凱(點(diǎn)融黑幫),目前就職于點(diǎn)融網(wǎng)infra部門,擅長質(zhì)量保證體系的搭建和開發(fā)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Docker — 云時(shí)代的程序分發(fā)方式 要說最近一年云計(jì)算業(yè)界有什么大事件?Google Compute Engi...
    ahohoho閱讀 15,850評論 15 147
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • 0. 前言 docker是什么?docker是用GO語言開發(fā)的應(yīng)用容器引擎,基于容器化,沙箱機(jī)制的應(yīng)用部署技術(shù)。可...
    sessionboy閱讀 4,008評論 2 49
  • 轉(zhuǎn)載自 http://blog.opskumu.com/docker.html 一、Docker 簡介 Docke...
    極客圈閱讀 10,755評論 0 120
  • 特別特別簡單的一道菜,但是味道很贊哦,中午做了一頓大受好評,晚上又如法炮制了一盤,依然被吃光光了。 材料...
    小狗子他娘閱讀 660評論 0 0

友情鏈接更多精彩內(nèi)容