與容器技術同樣受到關注的微服務架構也在潛移默化的改變著應用的部署方式,其提倡將應用分割成一系列細小的服務,每個服務專注于單一業務功能,服務之間采用輕量級通信機制相互溝通。同時數據庫解決方案也在發生在變化,多種持久化混合方案(Polyglot Persistence)提倡將數據存放在適合的數據庫解決方案中,而傳統的數據庫解決方案將數據存在在同一個數據庫服務中。服務數量的增加也就意味著容器數量的增多,逐漸增加的容器數量為容器部署,運行及管理帶來了挑戰。Docker Compose的出現解決多個容器部署的問題并提高了多個容器解決方案的可移植性。
Docker Compose的前身是Fig,它是一個定義及運行多個Docker容器的工具。使用Docker Compose你只需要在一個配置文件中定義多個Docker容器,然后使用一條命令將多個容器啟動,Docker Compose會通過解析容器件的依賴關系(link, 網絡容器 –net-from或數據容器 –volume-from)按先后順序啟動所定義的容器。
可以通過下載二進制可執行文件的方式安裝Docker Compose

Docker Compose將所管理的容器分為三層,工程(project),服務(service)以及容器(contaienr)。Docker Compose運行的目錄下的所有文件(docker-compose.yml, extends文件或環境變量文件等)組成一個工程,若無特殊指定工程名即為當前目錄名。一個工程當中可包含多個服務,每個服務中定義了容器運行的鏡像,參數,依賴。一個服務當中可包括多個容器實例,Docker Compose并沒有解決負載均衡的問題,因此需要借助其他工具實現服務發現及負載均衡。
Docker Compose的工程配置文件默認為docker-compose.yml,可通過環境變量COMPOSE_FILE或-f參數自定義配置文件,其定義了多個有依賴關系的服務及每個服務運行的容器。以下是一個簡單的配置文件:

其定義了兩個服務web和redis。web服務的鏡像需要在當前目錄實時構建,其容器運行時需要在宿主機開放端口5000并映射到容器端口5000,并且掛載存儲卷/code以及關聯服務redis。redis服務通過鏡像redis啟動。
Docker Compose是由python語言實現的,它通過調用docker-py庫(可參考https://github.com/docker/docker-py)與docker engine通信實現構建docker鏡像,啟動停止docker容器等。Docker-py庫調用docker remote API(可參考https://docs.docker.com/reference/api/docker_remote_api/)與Docker Daemon通信,可通過DOCKER_HOST配置本地或遠程Docker Daemon的地址。
下面我們通過分析docker-compose復雜的命令up的源碼來了解一下docker compose的工作原理。
通過命令docker-compose up -d啟動以上docker-compose.yml定義的服務。

我們可以看到redis服務先于web服務創建,這是因為docker-compose解析到服務間的依賴關系,web服務依賴于redis服務,所以進行了排序。我們來看一下docker compose up的工作流程。
1. 工程初始化 – 解析配置文件(包括docker-compose.yml,外部配置文件extends files,環境變量配置文件env_file),并將每個服務的配置轉換成python字典,初始化docker-py客戶端用于與本地或遠端的docker engine通信。
2. 根據docker-compose的命令參數將命令分發給相應的處理函數,此處為up
3. 調用project類的up函數,得到當前工程中的所有服務,并根據服務的依賴性(links,external links – 本工程或docker-compose之外的容器,多用于多項目共用容器,網絡容器net-from以及數據容器volume-from)進行排序并去掉重復出現服務(此情況可因某服務被其他多個服務依賴所造成)

4. Docker Compose使用labels標記啟動的容器
使用docker inspect可以看到一個通過docker compose啟動的容器被添加了一些compose使用的標記

5. Docker Compose通過compose工程名以及服務名從docker engine獲取當前所有含有此標記的容器以檢查當前工程所包含的服務狀態,根據當前狀態為每個服務制定接下來的動作。
a. 若容器不存在,則服務動作設置為創建(create)
b. 若容器存在但設置不允許重建,則服務動作設置為啟動(start)
c. 若容器配置發生變化(config-hash)或者設置強制重建標志,則服務動作設置為重建(recreate)
d. 若容器狀態為停止,則服務動作設置為啟動(start)
e. 若容器狀態為運行但其依賴容器需要重建,則服務狀態設置為重建(recreate)
f. 若容器狀態為運行其無配置改變則不作操作
6. 根據每個服務不同的動作執行不同的操作
服務動作為創建
a. 檢查鏡像是否存在(調用docker-py client inspect函數從本地或遠程的docker engine獲取鏡像信息)。若鏡像不存在,則檢查配置文件中關于鏡像的定義。如果在配置文件中設置為build則調用docker-py build函數與docker engine通信完成docker build的功能。如果在配置文件中設置為image則通過docker-py pull函數與docker engine通信完成docker pull的功能。
b. 獲取當前服務中容器的配置信息,如端口,存儲卷,主機名,使用鏡像環境變量等配置的信息。若在配置中指定本服務必須與某個服務在同一臺主機(previous_container,用于集群)則在環境變量中設置affinity:container=<container name>。通過docker-py與docker engine通信創建并啟動容器。
服務動作為重建
a. 停止當前的容器
b. 將現有的容器重命名,這樣數據卷在原容器被刪除前就可以拷貝到新創建的容器中了
c. 創建并啟動新容器,previsous_container設置為原容器確保其運行在同一臺主機(存儲卷掛載)
d. 刪除舊容器
服務動作為啟動則啟動停止的容器
7. 若docker-compose up沒有指明-d即前臺運行,則將所有各個容器的輸出匯聚打印
8. 注冊信號SIGINT處理函數,若收到信號SIGINT則并行殺掉所有容器
到此為止docker-compose up的命令執行完畢,docker-compose.yml文件中定義的服務 全部啟動。
Docker Compose的命令主要分為以下幾類
管理服務:up/start/scale/stop/restart/rm/kill
管理鏡像:build/pull
查看服務運行狀態:ps/port
打印運行中的服務log:logs
在一個服務中執行一個一次性命令:run
以上這些命令都是通過label標記來過濾當前工程里的容器,然后調用docker-py庫調用Docker remote API與docker engine通信控制容器。
Docker Compose是一個部署多個容器的簡單但是非常必要的工具,它使你使用一條簡單的命令部署多個容器。Docker Compose在實際工作中非常有價值,其大大簡化了多容器的部署過程,避免了在不同環境運行多個重復步驟所帶來的錯誤可能,使多容器移植變得簡單可控。從其Roadmap可以看出,Docker Compose的目標是做一個生產環境可用的工具,包括服務回滾,多環境支持(dev/test/staging/prod),支持在線服務部署升級,防止服務中斷并且監控服務使其始終運行在正確的狀態。Roadmap中的另一個目標是更好的與Docker Swarm集成,目前版本存在的主要問題是無法保證處于多個主機的容器間正常通信因為目前不支持跨主機間容器通信,我們相信新的Docker網絡實現將會解決這一問題。另一個問題是在Docker Compose中定義構建的鏡像只存在在一臺Docker Swarm主機上,無法做到多主機共享,因此目前需要手動構建鏡像并上傳到一個鏡像倉庫使多個Docker Swarm主機可以訪問并下載鏡像。相信隨著Docker Compose的完善,其必將取代docker run成為開發者啟動docker容器的首選。
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。