本節書摘來華章計算機《容器技術系列》一書中的第1章 ,第1.4節,孫宏亮 著, 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
1.3節着重介紹了docker架構中各個子產品的功能,學完後我們可以對docker的架構有一個宏觀的認識。熟悉一款軟體,研究一個系統,從靜态的角度認識架構的各個子產品,僅僅是第一步;從動态的角度,掌握軟體或者系統的運作原理,即熟知架構中子產品間的通信邏輯,無疑會讓自己對軟體或系統的了解更上一層樓。本節将從實際的docker運作案例出發,串聯docker各子產品,進而學習docker的運作流程。分析原型為docker中的docker pull與docker run兩個指令。
1.3節中我們提到,使用者可以為容器指定鏡像,作為容器運作時的rootfs,既然如此,鏡像從何而來則成為一個關鍵。答案很簡單,一切都歸功于docker pull指令。
docker pull指令的作用是:docker daemon從docker registry下載下傳指定的容器鏡像,并将鏡像存儲在本地的graph中,以備後續建立docker容器時使用。docker pull指令的執行流程如圖1-10所示。
圖1-10中有編号的箭頭表示docker pull指令在發起後,docker架構中相應子產品所做的一系列運作操作。下面我們逐一分析這些步驟。
1)docker client處理使用者發起的docker pull指令,解析完請求以及參數之後,發送一個http請求給docker server,http請求方法為post,請求url為"/images/create?"+"xxx",實際意義為下載下傳相應的鏡像。
2)docker server接收以上http請求,并交給mux.router,mux.router通過url以及請求方法類型來确定執行該請求的具體handler。
3)mux.router将請求路由分發至相應的handler,具體為postimagescreate。
4)在postimagecreate這個handler之中,建立并初始化一個名為"pull"的job,之後觸發執行該job。
5)名為"pull"的job在執行過程中執行pullrepository操作,即從docker registry中下載下傳相應的一個或者多個docker鏡像。
6)名為"pull"的job将下載下傳的docker鏡像交給graphdriver管理。
7)graphdriver負責存儲docker鏡像,一方面将實際鏡像存儲至本地檔案系統中,另一方面為鏡像建立對象,由docker daemon統一管理。
docker run指令的作用是建立一個全新的docker容器,并在容器内部運作指定指令。docker daemon處理使用者發起的這條指令時,所做工作可以分為兩部分:第一,建立docker容器對象,并為容器準備所需的rootfs;第二,建立容器的運作環境,如網絡環境、資源限制等,最終真正運作使用者指令。是以,在dockerrun指令的完整執行流程中,docker client給docker server發送了兩次http請求,第二次請求的發起取決于第一次請求的傳回狀态。docker run指令執行流程如圖1-11所示。
圖1-11中有編号的箭頭表示dockerrun指令在發起後,docker架構中相應子產品所做的一系列運作。下面我們逐一分析這些步驟:
1)docker client處理使用者發起的docker run指令,解析完請求與參數之後,向docker server發送一個http請求,http請求方法為post,請求url為"/containers/create?"+"xxx",實際意義為建立一個容器對象,即docker daemon程式邏輯中的容器對象,并非實際運作的容器。
2)docker server接收以上http請求,并交給mux.router,mux.router通過url以及請求方法來确定執行該請求的具體handler。
3)mux.router将請求路由分發至相應的handler,具體為postcontainerscreate。
4)在postcontainerscreate這個handler之中,建立并初始化一個名為"create"的job,之後觸發執行該job。
5)名為"create"的job在運作過程中執行container.create操作,該操作需要擷取容器鏡像來為docker容器準備rootfs,通過graphdriver完成。
6)graphdriver從graph中擷取建立docker容器rootfs所需要的所有鏡像。
7)graphdriver将rootfs的所有鏡像通過某種聯合檔案系統的方式加載至docker容器指定的檔案目錄下。
8)若以上操作全部正常執行,沒有傳回錯誤或異常,則docker client收到docker server傳回狀态之後,發起第二次http請求。請求方法為"post",請求url為"/containers/"+container_id+"/start",實際意義為啟動時才建立完畢的容器對象,實作實體容器的真正運作。
9)docker server接收以上http請求,并交給mux.router,mux.router通過url以及請求方法來确定執行該請求的具體handler。
10)mux.router将請求路由分發至相應的handler,具體為postcontainersstart。
11)在postcontainersstart這個handler之中,建立并初始化名為"start"的job,之後觸發執行該job。
12)名為"start"的job執行需要完成一系列與docker容器相關的配置工作,其中之一是為docker容器網絡環境配置設定網絡資源,如ip資源等,通過調用networkdriver完成。
13)networkdriver為指定的docker容器配置設定網絡資源,其中有ip、port等,另外為容器設定防火牆規則。
14)傳回名為"start"的job,執行完一些輔助性操作後,job開始執行使用者指令,調用execdriver。
15)execdriver被調用,開始初始化docker容器内部的運作環境,如命名空間、資源控制與隔離,以及使用者指令的執行,相應的操作轉交至libcontainer來完成。
16)libcontainer被調用,完成docker容器内部的運作環境初始化,并最終執行使用者要求啟動的指令。