微服務實踐之Docker應用

 

關注嘉爲科技,獲取運維新知

最近幾年,幾乎所有的大型互聯網公司都在做兩件同樣的事情,一是重構前端框架,二是重構後端微服務。微服務很火,無論你用或者不用,它都將繼續火下去,這是由日益龐大的系統的高可用需求決定的。

微服務注重單一職責的小型功能模塊拆分,獨立部署運維,模塊間互相隔離,通過API交互來搭建系統。原本一個工程能搞定的事情,現在需要搭建很多工程;原本只需要部署運維一套應用,現在卻需要部署運維很多套。於是,SpringBoot橫空出世,解決了多工程的標準化規範和快速開發需求。

Docker之類的容器也應運而生,解決了多應用快速部署的運維需求。

今天我們的微服務實踐之旅,介紹Docker的基本概念和入門應用。

 

什麼是Docker

Docker是一種容器技術,最開始是dotCloud公司的一個內部項目,開源後迅速火遍IT界,以至於dotCloud公司都改名爲Docker,目前在國內外互聯網公司都着有非常廣泛的應用。

Docker有一個形象的比喻——集裝箱,集裝箱內部可以裝任意類型的物資,而外部表現都是無差異的大型密封箱子,這樣就解決了同一艘貨輪同時運輸食品和化學物品的難題,因爲集裝箱之間互不干擾。Docker就是承載不同軟件服務及運行環境的集裝箱。

 

Docker的LOGO是一條藍鯨載着一堆集裝箱,口號是Build, Ship, and Run Any App, Anywhere,這跟當年Java提出的Write Once, Run Anywhere有異曲同工之處。然而,Docker和Java是兩種完全不一樣的事物,沒有人會把他們放在一起比較,Docker更多的會被拿來跟虛擬機做比較。

如果想通過虛擬機來運行Web應用,首先得給虛擬機分配CPU、內存等硬件資源,接着安裝操作系統,這樣才能讓虛擬機運轉起來,然後才能開始真正的應用部署。即便只是想在虛擬機上運行一個最簡單的HelloWorld頁面,也必須做前面這幾件事情,而且裝完後隨隨便便就是幾個G的虛擬機文件。而用Docker來跑一個Web應用就簡單多了,一行命令搞定,幾乎不佔任何多餘的磁盤空間,毫秒級啓動速度,效果跟虛擬機幾乎完全一樣。

 

上圖是虛擬機(左)和Docker(右)的架構比較,可以看出它們之間主要的不同點在於中間層,虛擬機通過Hypervisor虛擬出多臺客戶機,應用最終運行在客戶機的操作系統上;Docker則沒有客戶機的概念,直接運行在Docker引擎上,應用之間也是相互隔離的。可以這麼說,Docker是輕量版的“虛擬機”,這種輕量給Docker帶來了廣闊的應用。

 

Docker安裝

Docker起源於Linux操作系統,目前官方也開始支持較新版本的Windows操作系統,前提是需要開啓Hyper-V。下面我們以CentOS爲例來說明Docker的安裝過程。

如果系統曾經裝過Docker,那麼先卸載掉舊版本,卸載腳本如下,不曾安裝過則可忽略此步驟:

yum remove docker \

          docker-client \

          docker-client-latest \

          docker-common \

          docker-latest \

          docker-latest-logrotate \

          docker-logrotate \

          docker-selinux \

          docker-engine-selinux \

          docker-engine

然後開始安裝依賴包,需保證操作系統可以訪問互聯網:

yum install -y yum-utils device-mapper-persistent-data lvm2

 

添加Docker的yum源,由於官方源指向國外倉庫,下載速度可能會比較慢,國內鏡像站會快很多,因此這裏選用國內中科大的yum源,添加後刷新一下本地緩存:

yum-config-manager--add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo

yum makecache fast

 

然後就可以用yum命令進行Docker安裝了:

yum install docker-ce

docker-ce指的是社區版,對應的有docker-ee商業版。用yum命令安裝Docker,默認會安裝最新的Stable版本,也可以指定版本安裝,一般採用默認最新穩定版就行。

 

安裝完成後啓動Docker:

systemctl start docker

 

運行hello-world鏡像驗證一下是否啓動成功:

docker run hello-world

 

成功會看到Hello from Docker字樣信息,其他信息在不同電腦上不完全一樣:

 

如果需要讓系統開機自動啓動Docker,運行一下命令:

systemctl enable docker

 

Docker基本概念

Docker有三大組件,分別是鏡像(Image)、容器(Container)和倉庫(Registry),即使是上面最簡單的hello-world測試例子,也存在這三大組件的影子。

鏡像是容器的模板,容器是鏡像的實例,一個鏡像可以啓動多個容器,它們之間的關係跟面向對象程序設計中類和實例的關係是相似的。在上面的例子中,hello-world是一個鏡像,它本身是一個特殊的文件系統,裏面包含運行hello-world所需要的程序、依賴庫、配置信息、腳本等。通過docker run hello-world命令可以啓動一個容器,容器啓動後會按照鏡像中定義的信息,順序執行每一條命令。因此,根據同一個鏡像文件啓動的多個容器,它們之間的運行結果基本上是完全一樣的,這樣有效避免了類似在測試環境正常運行的功能到生產環境就出現Bug的“詭異事件”。

倉庫是存放Docker鏡像的地方,分爲本地倉庫和中央倉庫。Docker鏡像在製作完成後,可以看作是一個由多層文件組成的一個特殊程序包,可以在網絡上進行分發,分發出去的鏡像跟原始鏡像完全一樣,因此根據鏡像創建的容器也是一樣的。Docker提供了一個官方鏡像倉庫Docker Hub,上面已經包含非常多高質量的開源產品鏡像,比如Nginx、IIS、Tomcat,也包括一些精簡版的操作系統鏡像,,比如centos、ubuntu等,這些鏡像都可以拿來即用。當我們需要定製一個鏡像時,往往是從這些高質量鏡像中選用一個功能接近的,然後進行相應的改造,生成適用自身產品的鏡像,用於產品的快速發佈、上線。

當需要創建容器時,運行一下docker run [鏡像名]:[版本號],Docker引擎會先在本地倉庫搜索對應版本號的鏡像,當本地找不到該鏡像時,會根據配置的中央倉庫地址到遠程服務器上去搜,找到後下載到本地倉庫。回頭看一下前面docker run hello-world例子的輸出截圖,第一行是Unanle to find image ‘hello-world:latest’ locally,因爲是第一次運行,所以本地還沒有hello-world鏡像;第二行開始從遠程鏡像倉庫拉取鏡像,最後纔是啓動容器,輸出結果。再次運行docker run hello-world,會直接輸出結果,不再有相關下載信息了。

 

中央倉庫可以通過添加或修改在/etc/docker/daemon.json文件來指定,內容如下:

{ "registry-mirrors": ["https://registry.docker-cn.com"] }

 

Docker示例

現有裝好Docker的Linux服務器一臺,Java程序包ip.war一個,要求將這個ip.war部署並運行起來。

 

如果不用Docker的話,傳統的部署方式我們需要做下面這些步驟:

  1. 安裝JDK,並設置JAVA_HOME、PATH等環境變量;

  2. 安裝Tomcat,並設置CATALINA_HOME等環境變量;

  3. 將ip.war放到Tomcat的webapps目錄下,或者修改server.xml文件指向ip.war;

  4. 運行startup.sh腳本啓動Tomcat。

 

傳統方式我們就不動手做了。如果改用Docker來運行ip.war,上面的步驟統統可以省掉,只需要一行命令就夠,如下:

docker run -v /data/package:/usr/local/tomcat/webapps -it --net=host tomcat:latest

 

說明一下,ip.war包裏有一個/ip/IPServlet的API,用於獲取客戶端的IP地址。我本地的IP是192.168.128.1,服務器的IP是192.168.128.200。訪問接口驗證一下部署結果,沒毛病。

 

注意,Linux服務器上可沒有安裝JDK和Tomcat,程序是在Docker容器裏面運行的。

 

解釋一下這行神奇的命令。

docker run tomcat:latest是命令主體,中間部分是參數列表。

-v /data/package:/usr/local/tomcat/webapps表示將Linux上的/data/package目錄掛載到Docker容器裏的/usr/local/tomcat/webapps目錄下,這樣當容器內讀寫/usr/local/tomcat/webapps目錄時,實際上操作的是Linux上的/data/package目錄,ip.war包就是放在這個目錄下的。容器可以看作是一個無狀態的黑盒,需要跟外界交互才能產生有效的結果,掛載目錄就成了Docker黑盒與外界打交道的主要接口。

-net=host表示容器內直接共享主機的網絡和端口,因此我們可以通過主機的IP和端口來訪問實際上運行在容器中的服務。

-it指啓用一個交互式的僞終端,國際慣例。

 

此外還有其他各種各樣的參數,此處只是列出了運行Tomcat的最小化參數列表。

 

Docker作用

前面的例子已經給我們展示了Docker短小精悍的特點,這個特點可以讓Docker在很多場合有用武之地,比如微服務就是Docker的主場之一。

在一個純淨的系統中,一行命令運行一個war包,意味着應用的遷移和水平擴展也能一行命令搞定,這對微服務來說簡直就是雪中送炭。微服務架構講究服務拆分和獨立部署,程序包的粒度小、數量多,每個服務還要多副本、高可用,這用傳統方式來運維的話工作量巨大,而用Docker來做就跟玩兒似的。服務掛了?沒事,給我10秒鐘,我再給你起5個!

Docker的輕量化,也使得同一臺服務器上可以運行更多互不干擾的獨立服務。微服務支持用異構語言來開發服務,想在一臺Linux服務器上同時運行Java5、Java8、C#、Go、Python、PHP程序?沒問題,Docker容器統統幫你實現,每種語言分別創建一個容器來運行,而且理論上都只需要一行命令就能讓服務跑起來。

有一種程序跟Docker鏡像很像,那就是iOS的App;有一種商店也跟Docker Hub類似,那就是AppStore。既然如此,未來何嘗不可以通過Docker中央倉庫來發布軟件服務呢?事實上這正在發生。以後從網上下載一個軟件,可能是exe,也可能是一個Docker鏡像文件。將鏡像load到電腦上的本地倉庫,運行一條命令,一套或開源或商業的軟件系統就運行起來了,所有複雜的操作、配置都已經封裝在鏡像裏頭,用戶可以直接體驗最終的結果。

似乎Docker強大的功能皆來源於鏡像,然而,無論多麼強大的鏡像,最終都可以通過一個叫做Dockerfile的文件來構建。Dockerfile玄機幾何,我們以後再介紹。

 

本文首發於微信公衆號:嘉爲科技,轉載請註明出處。​​​​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章