張雷
(中國石油大學(華東)計算機與通信工程學院,山東青島266000)
傳統(tǒng)的Web應用大都部署在性能強的主機群、虛擬機群,亦或云服務商提供的云主機群上.伴隨著企業(yè)業(yè)務規(guī)模的擴大,用戶不斷增多,流量高峰時,曾經的服務器集群難免會遇到性能瓶頸,這時就需要擴展集群,以支撐更龐大的用戶訪問.基于主機方式的擴展較為繁瑣,需要手動進行各種配置,以適應現有集群環(huán)境,因而成本代價相對很高。同時,流量低峰時又會空閑大量服務器資源,造成資源浪費,利用率低等情況,集群的動態(tài)伸縮也是一個很大的挑戰(zhàn)。Docker的出現,使得應用的部署擴展方式得到很大程度的改變,很好的解決了上面的問題,在環(huán)境的搭建部署方面有著天然的優(yōu)勢,本文基于一個簡單Web應用,根據容器相關技術將其容器化,觀察在Docker環(huán)境中應用的運行情況。然后分別在單容器,容器集群中構建Web應用,研究分析其與傳統(tǒng)部署環(huán)境中服務的差異優(yōu)劣。最后對容器集群環(huán)境進行了資源動態(tài)伸縮測試,節(jié)點容錯測試。
Docker[1-2]是一個平臺,一系列技術的總稱,基于這個平臺在項目的開發(fā)、測試、部署各個環(huán)節(jié)中更加方便快捷,此外Docker還提供了許多額外的特性來保證軟件的穩(wěn)定安全。Contianer(容器)和Image(鏡像)是Docker中最重要的兩個基本概念。
Image是一個輕量級、獨立的可執(zhí)行包,其中包含運行一個軟件所需的一切,包括代碼、運行時庫、環(huán)境變量和配置文件。它是容器啟動的基礎,每一個容器都是從一個鏡像中產生的,實際上鏡像就是由多個不可變的layer構成的,容器則是在其上加了一個可讀寫的layer。容器與鏡像存儲結構如圖1所示。
圖1 鏡像與容器的存儲
Container是Image的運行時實例,實際運行時Image在內存中的內容.默認情況下,它與主機環(huán)境完全隔離,只能訪問主機文件和端口。容器化后的軟件將始終運行在一致的環(huán)境中,無論其部署在何種平臺之上。容器將軟件與其周圍環(huán)境隔離開來,因而有助于減少團隊之間在同一基礎設施上運行不同軟件的沖突。
Container基于主機內核,因而可以獲得本地原生的支持。它們具有比僅通過Hypervisor虛擬訪問主機資源的虛擬機更好的性能特征。容器是更輕量的虛擬機[3-4]。虛擬機是在操作系統(tǒng)上完整的模擬一臺真實機器,多臺虛擬機就需要完整虛擬出相應數量的操作系統(tǒng),耗費大量主機資源.相比Docker,由于鏡像的layer層的概念,相同的layer層在主機中只會保存一份,許多鏡像擁有相同layer層時,都會基于這一個layer,資源占用大大減少。這也是容器技術比虛擬機性能表現更好的原因之一。
Docker中所有的一切都是基于鏡像的。如何把應用Dockerize,也就是打包成鏡像呢?Docker提供了一個非常便捷的方式來將軟件應用及其所需的運行環(huán)境打包成一個鏡像,即Dockerfile。
Dockerfile是一個文本文檔,包含了用戶用以創(chuàng)建鏡像的所有命令.只需遵循Dockerfile命令格式,定義所需的應用環(huán)境,Docker就可以通過Dockerfile中的指令來自動完成鏡像的構建.Dockerfile中的每一條命令都會創(chuàng)建一個layer,出于鏡像的輕量,容器的效率等原因,盡量不要在一個鏡像中創(chuàng)建過多的layer。一些主要命令[5]:
FROM<image>:FROM指令初始化一個新的構建階段,并后續(xù)指令設置一個基本鏡像。有效的Dockerfile必須以FROM指令開始。鏡像可以是任何有效的鏡像:本地的,亦或是公共倉庫中的。
ADD <src>...<dest>:ADD 指令從 src復制新文件,目錄或遠程文件URL,并將它們添加到路徑為dest的鏡像文件系統(tǒng)中。
RUN<command>:RUN指令將在當前鏡像頂部的新層中執(zhí)行一些命令,并提交結果.生成的鏡像將用于Dockerfile中的下一步。
EXPOSE<port>:通知容器在運行時偵聽指定的網絡端口??梢灾付ǘ丝谑莻陕燭CP還是UDP,如果未指定,則默認為TCP。
CMD["param1","param2"]:容器啟動時默認執(zhí)行的命令,一個Dockerfile文件中只能有一個CMD命令,如果有多個,只有最后一個會起作用。
安裝運行著Docker的機器,它們之間相互獨立,單獨作為一臺Docker服務主機,Swarm[6]的作用就是將這些機器聯系起來,構成一個集群,使之對外看起來就像是一臺機器。搭建Swarm集群后,繼續(xù)運行使用Docker命令,Docker將會在管理的整個集群上執(zhí)行命令,而不僅僅是在當前的機器上運行。集群中的機器可以是物理的或虛擬的。加入集群后,它們被稱為節(jié)點。
Swarm管理節(jié)點是集群中唯一可以執(zhí)行命令的機器,或授權其他機器作為工作節(jié)點加入集群。工作節(jié)點只是提供處理資源,沒有權力告訴任何其他機器它可以做什么和不能做什么。
容器化[7-9]的主要工作就是Dockerfile的編寫,定義容器內的環(huán)境。并將訪問資源(如網絡接口和磁盤驅動器)在此環(huán)境中進行虛擬化,并具體說明要將哪些文件復制到此環(huán)境。
基于Docker官方基礎鏡像,預裝python2.7環(huán)境,官方鏡像經過了大量精簡優(yōu)化,體積非常小,保證開發(fā)環(huán)境正常的同時,占據更少的存儲空間,對搭建部署有極大的好處。構建鏡像的Dockerfile定義:
根據此Dockerfile文件,執(zhí)行docker build命令,構建出鏡像。還可以把構建好的鏡像放入私有庫中,協(xié)作開發(fā)人員就可以從中下載使用。鏡像包含了開發(fā)的必需環(huán)境,基于同一個鏡像開發(fā),也避免了開發(fā)環(huán)境不一致問題[10]。
在單節(jié)點部署容器:將構建好的鏡像pull至此節(jié)點上,執(zhí)行doker run命令完成容器的部署.因為是網絡應用,需要將容器暴露的80端口映射到主機的任意可用端口上.這樣通過訪問主機的指定端口就能夠訪問到容器內的應用。
集群環(huán)境:一個集群由多個節(jié)點組成,可以是物理機或虛擬機。這里僅以兩臺虛擬機組成集群。虛擬機是用VMware搭建的,基于Unbuntu17.04系統(tǒng).也可以使用Docker Machine工具來創(chuàng)建虛擬機,通過docker-machine create命令創(chuàng)建虛擬機,可以統(tǒng)一查看管理虛擬機,非常方便。
搭建容器集群[11-12]:執(zhí)行docker swarm init命令啟用swarm模式,使當前的機器成為集群管理節(jié)點,這步會得到一個Worker角色序列碼,然后在其余機器上運行docker swarm join,給token參數附上上步得到的序列碼,使以工作節(jié)點身份加入群集。集群搭建完畢后,在管理節(jié)點上可以查看到集群中各節(jié)點的狀態(tài)。
最后借助Stack在集群上完成部署[13-14],Stack相當于一個軟件系統(tǒng)整體,其中包括了許許多多的服務(Service),每個服務充當系統(tǒng)中的一個模塊,服務又由很多個容器(Container)組成.一個Stack文件其實就是版本號為3的Compose文件,定義如下:
通過docker stack deploy命令部署運行,在管理節(jié)點可以查看到應用在集群中的部署情況,部署成功之后,5個容器實例被分別分配到ubuntu2和ubuntu3兩臺主機上運行,可以通過集群中的任意一臺主機的ip訪問到部署在其上web應用。
實驗使用Apache旗下的一款測試工具JMeter來模擬用戶訪問。首先單線程循環(huán)訪問100次。查看服務器平均響應時間情況。圖2展示了本地環(huán)境和容器環(huán)境下服務器的響應能力,可以明顯看出本地環(huán)境下的響應時間在2 000 ms上下浮動,而容器環(huán)境下的響應時間大約維持在250 ms左右,對比本地環(huán)境有明顯優(yōu)勢。
圖3所示為50個線程并發(fā)訪問測試情況.隨著訪問量增大,服務器處理能力的局限性,兩種環(huán)境下的響應時間都呈現出逐步增長的趨勢,但仍可看出容器環(huán)境下在訪問量到達頂峰時的響應時間接近10 000 ms,對比本地環(huán)境下的90 000 ms,容器下的服務器也表現出了不錯的處理能力。服務器具體性能指標如表1。觀察發(fā)現,容器環(huán)境下服務器的平均響應速度遠遠高于本地環(huán)境,容器單線程情況下為251 ms,多線程并發(fā)訪問時用時6 039 ms,兩種情景下都遠少于本地環(huán)境下服務的響應時間。服務器的吞吐量也存在明顯差異,容器環(huán)境近約3.9/sec,本地環(huán)境約為0.49/sec。綜合各個方面,容器都擁有更出色的表現。
圖2 單線程本地與容器環(huán)境下響應時間對比
圖3 多線程本地與容器環(huán)境下響應時間對比
表1 各環(huán)境下服務器性能比較
Swarm集群中節(jié)點的伸縮拓展[15-16]:使用docker swarm join命令將一臺主機輕松加入到集群中,docker swarm leave命令則可以將機器從集群中踢出.此外還可以控制容器的副本數量,給程序提供更多的處理資源,保證程序的健壯。
為了測試集群中的容錯性,人為刪除一個容器實例(docker rm命令用于刪除容器,刪除運行中的容器,需加上-f強制刪除)來模擬容器宕機掛掉的情況,稍等片刻,查看集群狀態(tài),如圖4所示。
機器ubuntu2上\_wepapp_web.5為手動宕掉的容器,可以看見Swarm自動在ubuntu3上創(chuàng)建了一個新的容器來替代它。
圖4 集群容器容錯測試
本次實驗中的web服務是由兩臺虛擬機內的五個容器實例提供的,任意的http請求都由Swarm采用默認的負載策略分發(fā)給具體的容器實例進行處理。Swarm保證replicas參數數量的容器實例的運行,如果其中某個容器宕機掛掉,Swarm會自動分配啟動一個新的容器來取代它。
通過實驗發(fā)現了Web應用在容器的環(huán)境中發(fā)揮出了更好的性能,但其帶來的好處遠不止如此,在集群的資源利用、拓展、容錯方面也帶來了極大的便利。本文只是基于Web應用的容器化進行了些許探討,在其他領域方面Docker也掀起了巨大的變革,越來越多的互聯網公司使用Docker來開發(fā)部署自己的系統(tǒng)架構,尤其在云計算、大數據盛行的今天,更凸顯了Docker自身的優(yōu)勢。Docker技術還在不斷完善成長,需要逐步挖掘探討。