終於有人把 Docker 講清楚了,萬字詳解!

作者:樂章

鏈接:http://39sd.cn/732DD

博文大綱:
一、簡介
1)瞭解Docker的前生LXC
2)LXC與docker什麼關係?
3)什麼是docker
4)docker官方文檔
5)爲什麼docker越來越受歡迎
6)docker版本
7)docker和openstack的幾項對比
8)容器在內核中支持2種重要技術
9)docker三個重要概念
10)docker的主要用途
11)docker改變了什麼
二、docker架構
1)docker架構(一)
2)docker架構(二)
3、docker架構(三)
三、docker架構各個模塊的功能
1)docker client
2)docker daemon
3)docker server
4)engine
5)job
6)docker registry
7)Graph
8)driver
9)libcontainer
10)docker container
四、docker簡單使用

一、簡介

1)瞭解Docker的前生LXC

LXC爲Linux Container的簡寫。可以提供輕量級的虛擬化,以便隔離進程和資源,而且不需要提供指令解釋機制以及全虛擬化的其他複雜性。相當於C++中的NameSpace。容器有效地將由單個操作系統管理的資源劃分到孤立的組中,以更好地在孤立的組之間平衡有衝突的資源使用需求。

與傳統虛擬化技術相比,它的優勢在於:
(1)與宿主機使用同一個內核,性能損耗小;
(2)不需要指令級模擬;
(3)不需要即時(Just-in-time)編譯;
(4)容器可以在CPU核心的本地運行指令,不需要任何專門的解釋機制;
(5)避免了準虛擬化和系統調用替換中的複雜性;
(6)輕量級隔離,在隔離的同時還提供共享機制,以實現容器與宿主機的資源共享;

總結:Linux Container是一種輕量級的虛擬化的手段。

Linux Container提供了在單一可控主機節點上支持多個相互隔離的server container同時執行的機制。Linux Container有點像chroot,提供了一個擁有自己進程和網絡空間的虛擬環境,但又有別於虛擬機,因爲lxc是一種操作系統層次上的資源的虛擬化。

2)LXC與docker什麼關係?

docker並不是LXC替代品,docker底層使用了LXC來實現,LXC將linux進程沙盒化,使得進程之間相互隔離,並且能對各進程資源合理分配。
在LXC的基礎之上,docker提供了一系列更強大的功能。

3)什麼是docker

docker是一個開源的應用容器引擎,基於go語言開發並遵循了apache2.0協議開源。
docker可以讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,然後發佈到任何流行的linux服務器,也可以實現虛擬化。
容器是完全使用沙箱機制,相互之間不會有任何接口(類iphone的app),並且容器開銷極其低。

4)docker官方文檔

https://docs.docker.com/

5)爲什麼docker越來越受歡迎

容器化越來越受歡迎,因爲容器是:
1)靈活:即使是最複雜的應用也可以集裝箱化;
2)輕量級:容器利用並共享主機內核;
3)可互換:您可以即時部署更新和升級;
4)便攜式:您可以在本地構建,部署到雲,並在任何地方運行;
5)可擴展:您可以增加並自動分發容器副本;
6)可堆疊:您可以垂直和即時堆疊服務;

1)鏡像和容器(contalners)

通過鏡像啓動一個容器,一個鏡像是一個可執行的包,其中包括運行應用程序所需要的所有內容包含代碼,運行時間,庫、環境變量、和配置文件。
容器是鏡像的運行實例,當被運行時有鏡像狀態和用戶進程,可以使用docker ps 查看。

2)容器和虛擬機

容器是在linux上本機運行,並與其他容器共享主機的內核,它運行的一個獨立的進程,不佔用其他任何可執行文件的內存,非常輕量。

虛擬機運行的是一個完成的操作系統,通過虛擬機管理程序對主機資源進行虛擬訪問,相比之下需要的資源更多。

如圖:
終於有人把 Docker 講清楚了,萬字詳解!

6)docker版本

1)Docker Community Edition(CE)社區版
2)Enterprise Edition(EE) 商業版

7)docker和openstack的幾項對比

類別 Docker openstack
部署難度 非常簡單 組件多,部署複雜
啓動速度 秒級 分鐘級
執行性能 和物理系統幾乎一致 vm會佔用一些資源
鏡像體積 鏡像MB級別 虛擬機鏡像GB級別
管理效率 管理簡單 組件相互依賴,管理複雜
隔離性 隔離性高 徹底隔離
可管理性 單進程 完整的系統管理
網絡連接 比較弱 藉助neutron可以靈活組件各類網絡管理

8)容器在內核中支持2種重要技術

docker本質就是宿主機的一個進程,docker是通過namespace實現資源隔離,通過cgroup實現資源限制,通過寫時複製技術(copy-on-write)實現了高效的文件操作(類似虛擬機的磁盤比如分配500g並不是實際佔用物理磁盤500g)

1)namespaces 名稱空間

namespace的六項隔離:

namespace 系統調用參數 隔離內容
UTS CLONE_MEWUTS 主機名與域名
IPC CLONE_NEWWIPC 信號量、消息隊列、共享內存
PID CLONE_NEWPID 進程編號
NETWORK CLONE_NEWNET 網絡設備、網絡棧、端口等
MOUNT CLONE_NEWNS 掛載點(文件系統)
USER CLONE_NEWUSER 用戶和用戶組(3.8以後的內核才支持)

2)control Group 控制組

cgroup的特點:
1)cgroup的api以一個僞文件系統的實現方式,用戶的程序可以通過文件系統實現cgroup的組件管理;
2)cgroup的組件管理操作單元可以細粒度到線程級別,另外用戶可以創建和銷燬cgroup,從而實現資源的分配和再利用;
3)所有資源管理的功能都以子系統的方式實現,接口統一子任務創建之初與其父任務處於同一個cgroup的控制組;

四大功能:

1)資源限制:可以對任務使用的資源總額進行限制;
2)優先級分配:通過分配的cpu時間片數量以及磁盤IO帶寬大小,實際上相當於控制了任務運行優先級;
3)資源統計:可以統計系統的資源使用量,如cpu時長,內存用量等;
4)任務控制:cgroup可以對任務執行掛起、恢復等操作;

9)docker三個重要概念

1)image鏡像

docker鏡像就是一個只讀模板,比如,一個鏡像可以包含一個完整的centos,裏面僅安裝apache或用戶的其他應用,鏡像可以用來創建docker容器,另外docker提供了一個很簡單的機制來創建鏡像或者更新現有的鏡像,用戶甚至可以直接從其他人那裏下一個已經做好的鏡像來直接使用;

2)container容器

docker利用容器來運行應用,容器是從鏡像創建的運行實例,它可以被啓動,開始、停止、刪除、每個容器都是互相隔離的,保證安全的平臺,可以把容器看做是要給簡易版的linux環境(包括root用戶權限、鏡像空間、用戶空間和網絡空間等)和運行在其中的應用程序;

3)repostory倉庫

倉庫是集中存儲鏡像文件的滄桑,registry是倉庫主從服務器,實際上參考註冊服務器上存放着多個倉庫,每個倉庫中又包含了多個鏡像,每個鏡像有不同的標籤(tag);

倉庫分爲兩種:公有倉庫、私有倉庫,最大的公開倉庫是docker Hub,存放了數量龐大的鏡像供用戶下載;

10)docker的主要用途

官方就是Bulid 、ship、run any app/any where,編譯、裝載、運行、任何app/在任意地方都能運行。
就是實現了應用的封裝、部署、運行的生命週期管理只要在glibc的環境下,都可以運行。

運維生成環境中:docker化。
1)發佈服務不用擔心服務器的運行環境,所有的服務器都是自動分配docker,自動部署,自動安裝,自動運行;
2)再不用擔心其他服務引擎的磁盤問題,cpu問題,系統問題了;
3)資源利用更出色;
4)自動遷移,可以製作鏡像,遷移使用自定義的鏡像即可遷移,不會出現什麼問題;
5)管理更加方便了;

11)docker改變了什麼

1)面向產品:產品交付;
2)面向開發:簡化環境配置;
3)面向測試:多版本測試;
4)面向運維:環境一致性
5)面向架構:自動化擴容(微服務)

二、docker架構

1)docker架構(一)

如圖:
終於有人把 Docker 講清楚了,萬字詳解!

1)distribution 負責與docker registry交互,上傳系統鏡像以及v2 registry 有關的源數據;
2)registry負責docker registry有關的身份認證、鏡像查找、鏡像驗證以及管理registry mirror等交互操作;
3)image 負責與鏡像源數據有關的存儲、查找,鏡像層的索引、查找以及鏡像tar包有關的導入、導出操作;
4)reference負責存儲本地所有鏡像的repository和tag名,並維護與鏡像id之間的映射關係;
5)layer模塊負責與鏡像層和容器層源數據有關的增刪改查,並負責將鏡像層的增刪改查映射到實際存儲鏡像層文件的graphdriver模塊;
6)graghdriver是所有與容器鏡像相關操作的執行者;

2)docker架構(二)

如果覺得上面架構圖比較亂可以看這個架構,如圖:
終於有人把 Docker 講清楚了,萬字詳解!

從上圖不難看出,用戶是使用Docker Client與Docker Daemon建立通信,併發送請求給後者。

而Docker Daemon作爲Docker架構中的主體部分,首先提供Server的功能使其可以接受Docker Client的請求;而後Engine執行Docker內部的一系列工作,每一項工作都是以一個Job的形式的存在。

Job的運行過程中,當需要容器鏡像時,則從Docker Registry中下載鏡像,並通過鏡像管理驅動graphdriver將下載鏡像以Graph的形式存儲;當需要爲Docker創建網絡環境時,通過網絡管理驅動networkdriver創建並配置Docker容器網絡環境;當需要限制Docker容器運行資源或執行用戶指令等操作時,則通過execdriver來完成。

而libcontainer是一項獨立的容器管理包,networkdriver以及execdriver都是通過libcontainer來實現具體對容器進行的操作。當執行完運行容器的命令後,一個實際的Docker容器就處於運行狀態,該容器擁有獨立的文件系統,獨立並且安全的運行環境等。

3、docker架構(三)

再來看看另外一個架構,這個個架構就簡單清晰指明瞭server/client交互,容器和鏡像、數據之間的一些聯繫。如圖:
終於有人把 Docker 講清楚了,萬字詳解!

docker daemon就是docker的守護進程即server端,可以是遠程的,也可以是本地的,這個不是C/S架構嗎,客戶端Docker client 是通過rest api進行通信。

docker cli 用來管理容器和鏡像,客戶端提供一個只讀鏡像,然後通過鏡像可以創建多個容器,這些容器可以只是一個RFS(Root file system根文件系統),也可以ishi一個包含了用戶應用的RFS,容器在docker client中只是要給進程,兩個進程之間互不可見。

用戶不能與server直接交互,但可以通過與容器這個橋樑來交互,由於是操作系統級別的虛擬技術,中間的損耗幾乎可以不計。

三、docker架構各個模塊的功能

以第二步驟的docker架構(二)爲例,主要的模塊有:Docker Client、Docker Daemon、Docker Registry、Graph、Driver、libcontainer以及Docker container。

1)docker client

docker client 是docker架構中用戶用來和docker daemon建立通信的客戶端,用戶使用的可執行文件爲docker,通過docker命令行工具可以發起衆多管理container的請求。

docker client發送容器管理請求後,由docker daemon接受並處理請求,當docker client 接收到返回的請求相應並簡單處理後,docker client 一次完整的生命週期就結束了,當需要繼續發送容器管理請求時,用戶必須再次通過docker可以執行文件創建docker client。

2)docker daemon

docker daemon 是docker架構中一個常駐在後臺的系統進程,功能是:接收處理docker client發送的請求。該守護進程在後臺啓動一個server,server負載接受docker client發送的請求;接受請求後,server通過路由與分發調度,找到相應的handler來執行請求。

docker daemon啓動所使用的可執行文件也爲docker,與docker client啓動所使用的可執行文件docker相同,在docker命令執行時,通過傳入的參數來判別docker daemon與docker client。

docker daemon的架構可以分爲:docker server、engine、job、daemon

3)docker server

docker server在docker架構中是專門服務於docker client的server,該server的功能是:接受並調度分發docker client發送的請求,架構圖如下:
終於有人把 Docker 講清楚了,萬字詳解!

在Docker的啓動過程中,通過包gorilla/mux(golang的類庫解析),創建了一個mux.Router,提供請求的路由功能。在Golang中,gorilla/mux是一個強大的URL路由器以及調度分發器。該mux.Router中添加了衆多的路由項,每一個路由項由HTTP請求方法(PUT、POST、GET或DELETE)、URL、Handler三部分組成。

若Docker Client通過HTTP的形式訪問Docker Daemon,創建完mux.Router之後,Docker將Server的監聽地址以及mux.Router作爲參數,創建一個httpSrv=http.Server{},最終執行httpSrv.Serve()爲請求服務。

在Server的服務過程中,Server在listener上接受Docker Client的訪問請求,並創建一個全新的goroutine來服務該請求。在goroutine中,首先讀取請求內容,然後做解析工作,接着找到相應的路由項,隨後調用相應的Handler來處理該請求,最後Handler處理完請求之後回覆該請求。

需要注意的是:Docker Server的運行在Docker的啓動過程中,是靠一個名爲”serveapi”的job的運行來完成的。原則上,Docker Server的運行是衆多job中的一個,但是爲了強調Docker Server的重要性以及爲後續job服務的重要特性,將該”serveapi”的job單獨抽離出來分析,理解爲Docker Server。

4)engine

Engine是Docker架構中的運行引擎,同時也Docker運行的核心模塊。它扮演Docker container存儲倉庫的角色,並且通過執行job的方式來操縱管理這些容器。

在Engine數據結構的設計與實現過程中,有一個handler對象。該handler對象存儲的都是關於衆多特定job的handler處理訪問。舉例說明,Engine的handler對象中有一項爲:{“create”: daemon.ContainerCreate,},則說明當名爲”create”的job在運行時,執行的是daemon.ContainerCreate的handler。

5)job

一個Job可以認爲是Docker架構中Engine內部最基本的工作執行單元。Docker可以做的每一項工作,都可以抽象爲一個job。例如:在容器內部運行一個進程,這是一個job;創建一個新的容器,這是一個job,從Internet上下載一個文檔,這是一個job;包括之前在Docker Server部分說過的,創建Server服務於HTTP的API,這也是一個job,等等。

Job的設計者,把Job設計得與Unix進程相仿。比如說:Job有一個名稱,有參數,有環境變量,有標準的輸入輸出,有錯誤處理,有返回狀態等。

6)docker registry

Docker Registry是一個存儲容器鏡像的倉庫。而容器鏡像是在容器被創建時,被加載用來初始化容器的文件架構與目錄。

在Docker的運行過程中,Docker Daemon會與Docker Registry通信,並實現搜索鏡像、下載鏡像、上傳鏡像三個功能,這三個功能對應的job名稱分別爲”search”,”pull” 與 “push”。

其中,在Docker架構中,Docker可以使用公有的Docker Registry,即大家熟知的Docker Hub,如此一來,Docker獲取容器鏡像文件時,必須通過互聯網訪問Docker Hub;同時Docker也允許用戶構建本地私有的Docker Registry,這樣可以保證容器鏡像的獲取在內網完成。

7)Graph

Graph在Docker架構中扮演已下載容器鏡像的保管者,以及已下載容器鏡像之間關係的記錄者。一方面,Graph存儲着本地具有版本信息的文件系統鏡像,另一方面也通過GraphDB記錄着所有文件系統鏡像彼此之間的關係。

Graph的架構如下:
終於有人把 Docker 講清楚了,萬字詳解!

其中,GraphDB是一個構建在SQLite之上的小型圖數據庫,實現了節點的命名以及節點之間關聯關係的記錄。它僅僅實現了大多數圖數據庫所擁有的一個小的子集,但是提供了簡單的接口表示節點之間的關係。

同時在Graph的本地目錄中,關於每一個的容器鏡像,具體存儲的信息有:該容器鏡像的元數據,容器鏡像的大小信息,以及該容器鏡像所代表的具體rootfs。

8)driver

Driver是Docker架構中的驅動模塊。通過Driver驅動,Docker可以實現對Docker容器執行環境的定製。由於Docker運行的生命週期中,並非用戶所有的操作都是針對Docker容器的管理,另外還有關於Docker運行信息的獲取,Graph的存儲與記錄等。因此,爲了將Docker容器的管理從Docker Daemon內部業務邏輯中區分開來,設計了Driver層驅動來接管所有這部分請求。

在Docker Driver的實現中,可以分爲以下三類驅動:graphdriver、networkdriver和execdriver。

graphdriver主要用於完成容器鏡像的管理,包括存儲與獲取。即當用戶需要下載指定的容器鏡像時,graphdriver將容器鏡像存儲在本地的指定目錄;同時當用戶需要使用指定的容器鏡像來創建容器的rootfs時,graphdriver從本地鏡像存儲目錄中獲取指定的容器鏡像。

在graphdriver的初始化過程之前,有4種文件系統或類文件系統在其內部註冊,它們分別是aufs、btrfs、vfs和devmapper。而Docker在初始化之時,通過獲取系統環境變量”DOCKER_DRIVER”來提取所使用driver的指定類型。而之後所有的graph操作,都使用該driver來執行。

graphdriver的架構如下:
終於有人把 Docker 講清楚了,萬字詳解!

networkdriver的用途是完成Docker容器網絡環境的配置,其中包括Docker啓動時爲Docker環境創建網橋;Docker容器創建時爲其創建專屬虛擬網卡設備;以及爲Docker容器分配IP、端口並與宿主機做端口映射,設置容器防火牆策略等。networkdriver的架構如下:
終於有人把 Docker 講清楚了,萬字詳解!

execdriver作爲Docker容器的執行驅動,負責創建容器運行命名空間,負責容器資源使用的統計與限制,負責容器內部進程的真正運行等。在execdriver的實現過程中,原先可以使用LXC驅動調用LXC的接口,來操縱容器的配置以及生命週期,而現在execdriver默認使用native驅動,不依賴於LXC。

具體體現在Daemon啓動過程中加載的ExecDriverflag參數,該參數在配置文件已經被設爲”native”。這可以認爲是Docker在1.2版本上一個很大的改變,或者說Docker實現跨平臺的一個先兆。execdriver架構如下:
終於有人把 Docker 講清楚了,萬字詳解!

9)libcontainer

libcontainer是Docker架構中一個使用Go語言設計實現的庫,設計初衷是希望該庫可以不依靠任何依賴,直接訪問內核中與容器相關的API。

正是由於libcontainer的存在,Docker可以直接調用libcontainer,而最終操縱容器的namespace、cgroups、apparmor、網絡設備以及防火牆規則等。這一系列操作的完成都不需要依賴LXC或者其他包。libcontainer架構如下:
終於有人把 Docker 講清楚了,萬字詳解!

另外,libcontainer提供了一整套標準的接口來滿足上層對容器管理的需求。或者說,libcontainer屏蔽了Docker上層對容器的直接管理。又由於libcontainer使用Go這種跨平臺的語言開發實現,且本身又可以被上層多種不同的編程語言訪問,因此很難說,未來的Docker就一定會緊緊地和Linux捆綁在一起。而於此同時,Microsoft在其著名雲計算平臺Azure中,也添加了對Docker的支持,可見Docker的開放程度與業界的火熱度。

暫不談Docker,由於libcontainer的功能以及其本身與系統的鬆耦合特性,很有可能會在其他以容器爲原型的平臺出現,同時也很有可能催生出雲計算領域全新的項目。

10)docker container

Docker container(Docker容器)是Docker架構中服務交付的最終體現形式。

Docker按照用戶的需求與指令,訂製相應的Docker容器:
1)用戶通過指定容器鏡像,使得Docker容器可以自定義rootfs等文件系統;
2)用戶通過指定計算資源的配額,使得Docker容器使用指定的計算資源;
3)用戶通過配置網絡及其安全策略,使得Docker容器擁有獨立且安全的網絡環境;
4)用戶通過指定運行的命令,使得Docker容器執行指定的工作;

如圖:
終於有人把 Docker 講清楚了,萬字詳解!

四、docker簡單使用

關於docker的基本操作請參考博文:Docker簡介及安裝配置詳解

如需對docker詳細瞭解請參考文章:
https://cloud.tencent.com/developer/article/1006116
https://yq.aliyun.com/articles/65145
https://blog.51cto.com/10085711/2068290
https://www.cnblogs.com/zuxing/articles/8717415.html

——————————本文到此結束,感謝閱讀————————————

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