1. 程式人生 > >docker容器技術基礎

docker容器技術基礎

什麼是容器

容器是對應用程式及其依賴關係的封裝。

容器的優點

  • 容器與主機的作業系統共享資源,提高了效率,效能損耗低

  • 容器具有可移植性

  • 容器是輕量的,可同時執行數十個容器,模擬分散式系統

  • 不必花時間在配置和安裝上,無需擔心繫統的改動,以及依賴關係是否滿足

容器與虛擬機器 執行在同一主機的3個虛擬機器

執行在同一主機的3個容器

區別: A.容器只能執行與主機一樣的核心 B.程式庫可以共用 C.容器中執行的程序與主機的程序等價(沒有虛擬機器管理程式的損耗) D.隔離能力,虛擬機器更高(將容器執行在虛擬機器中)

容器與Docker Docker利用現有的Linux容器技術,以不同方式將其封裝及擴充套件(通過提供可移植的映象及友好的介面),來建立及釋出方案。

兩部分:

  • 負責建立與執行容器的Docker引擎

  • 用來發布容器的雲服務Docker Hub

Docker是個什麼東西

Docker是PaaS 提供商 dotCloud 開源的一個基於 LXC 的高階容器引擎,原始碼託管在 Github 上, 基於go語言並遵從Apache2.0協議開源。 Docker是通過核心虛擬化技術(namespace以及cgroups等)來提供容器的資源隔離與安全保障。由於Docker通過作業系統層的虛擬化實現隔離,所以Docker容器在執行時,不需要類似虛擬機器( VM)額外的作業系統開銷,提高資源利用率。

Docker是一個程式執行、測試、交付的開放平臺,Docker被設計為能夠使你快速地交付應用。

在Docker中,你可以將你的程式分為不同的基礎部分,對於每一個基礎部分都可以當做一個應用程式來管理。

Docker能夠幫助你快速地測試、快速地編碼、快速地交付,並且縮短你從編碼到執行應用的週期。

Docker使用輕量級的容器虛擬化平臺,並且結合工作流和工具,來幫助你管理、部署你的應用程式。

Docker在其核心,Docker實現了讓幾乎任何程式都可以在一個安全、隔離的容器中執行。安全和隔離可以使你可以同時在機器上執行多個容器。

Docker容器輕量級的特性,意味著你可以得到更多的硬體效能。

圍繞著Docker容器的虛擬化工具和平臺,可以在以下幾個方面為你提供幫助:

1)幫助你把應用程式(包括其餘的支援元件)放入到Docker容器中。

2)分發和轉移你的容器至你的團隊其它成員來進行進一步的開發和測試。

3)部署這些應用程式至你的生產環境,不論是本地的資料中心還是雲平臺。

原理建立-->傳送-->執行

image

Docker架構

1.總架構

主要模組: DockerClient(與Daemon建立通訊,發起容器的管理請求) DockerDaemon(接收Client請求,處理請求) Docker Regisrty(映象管理) Graph(儲存映象) Drvier(映象管理驅動) libcontainer(系統核心特性,提供完整、明確的介面給Daemon) Docker Container

2.各模組功能及實現 1)Docker Client Docker架構中使用者與Docker Daemon建立通訊的客戶端。 使用者可以使用可執行檔案docker作為Docker Client,發起Docker容器的管理請求。

三種方式建立通訊: tcp://host:port unix://path_to_socket fd://socketfd

Docker Client傳送容器管理請求後,請求由Docker Daemon接收並處理,當Docker Client接收到返回的請求響應並做簡單處理後,Docker Client一次完整的生命週期就結束了。

2)Docker Daemon 常駐在後臺的系統程序。

主要作用: 接收並處理Docker Client傳送的請求 管理所有的Docker容器

Docker Daemon執行時,會在後臺啟動一個Server,Server負責接收Docker Client傳送的請求;接收請求後,Server通過路由與分發排程,找到相應的Handler來處理請求。

三部分組成: A.Docker Server 專門服務於Docker Client,接收並排程分發Client請求。 Server通過包gorilla/mux建立mux。Router路由器,提供請求的路由功能,每一個路由項由HTTP請求方法(PUT、POST、GET、DELETE)、URL和Handler組成。

每一個Client請求,Server均會建立一個全新的goroutine來服務,在goroutine中,Server首先讀取請求內容,然後做請求解析工作,接著匹配相應的路由項,隨後呼叫相應的Handler來處理,最後Handler處理完請求後給Client回覆響應。

B.Engine 核心模組,執行引擎。 儲存著大量容器資訊,管理著Docker大部分Job的執行。

handlers物件: 儲存眾多特定Job各自的處理方法handler。 例如: {"create":daemon.ContainerCreate,} 當執行名為"create"的Job時,執行的是daemon.ContainerCreate這個handler。

C.Job Engine內部最基本的執行單元,Daemon完成的每一項工作都體現為一個Job。

3)Docker Registry 儲存容器映象(Docker Image)的倉庫。 Docker Image是容器建立時用來初始化容器rootfs的檔案系統內容。

主要作用:

  • 搜尋映象

  • 下載映象

  • 上傳映象

方式:

  • 公有Registry

  • 私有Registry

4)Graph 容器映象的保管者。

5)Driver 驅動模組,通過Driver驅動,Docker實現對Docker容器執行環境的定製,定製的維度包括網路、儲存、執行方式。

作用: 將與Docker容器有關的管理從Daemon的所有邏輯中區分開。

實現: A.graphdriver 用於完成容器映象管理。

初始化前的四種檔案系統或類檔案系統的驅動在Daemon中註冊: aufs、btrfs、devmapper用於容器映象的管理 vfs用於容器volume的管理

B.networkdriver 完成Docker容器網路環境的配置。

C.execdriver 執行驅動,負責建立容器執行時的名稱空間,負責容器資源使用的統計與限制,負責容器內部程序的真正執行等。 Daemon啟動過程中載入ExecDriverflag引數在配置檔案中預設設為native。

6)libcontainer 使用Go語言設計的庫,不依靠任何依賴,直接訪問核心中與容器相關的系統呼叫。

7)Docker Container 服務交付的最終體現。

使用者對Docker容器的配置:

  • 通過指定容器映象,使得Docker容器可以自定義rootfs等檔案系統;

  • 通過指定物理資源的配額,使得Docker容器使用受限的資源;

  • 通過配置容器網路及其安全策略,使得Docker容器擁有獨立且安全的網路環境; *通過指定容器的執行命令,使得Docker容器執行指定的任務

Docker的用途

1)快速交付你的應用程式

Docker可以為你的開發過程提供完美的幫助。Docker允許開發者在本地包含了應用程式和服務的容器進行開發,之後可以整合到連續的一體化和部署工作流中。

舉個例子,開發者們在本地編寫程式碼並且使用Docker和同事分享其開發棧。當開發者們準備好了之後,他們可以將程式碼和開發棧推送到測試環境中,在該環境進行一切所需要的測試。從測試環境中,你可以將Docker映象推送到伺服器上進行部署。

2)開發和拓展更加簡單

Docker的以容器為基礎的平臺允許高度可移植的工作。Docker容器可以在開發者機器上執行,也可以在實體或者虛擬機器上執行,也可以在雲平臺上執行。

Docker的可移植、輕量特性同樣讓動態地管理負載更加簡單。你可以用Docker快速地增加應用規模或者關閉應用程式和服務。Docker的快速意味著變動幾乎是實時的。

3)達到高密度和更多負載

Docker輕巧快速,它提供了一個可行的、符合成本效益的替代基於虛擬機器管理程式的虛擬機器。這在高密度的環境下尤其有用。例如,構建你自己的雲平臺或者PaaS,在中小的部署環境下同樣可以獲取到更多的資源效能。

Docker的主要組成

Docker有兩個主要的部件:

Docker:     開源的容器虛擬化平臺。

Docker Hub: 用於分享、管理Docker容器的Docker SaaS平臺。

Docker的架構 C/S架構

Docker使用客戶端-伺服器(client-server)架構模式。

Docker 客戶端會與Docker守護程序進行通訊。Docker 守護程序會處理複雜繁重的任務,例如建立、執行、釋出你的 Docker 容器。

Docker 客戶端和守護程序可以執行在同一個系統上,當然也可以使用Docker客戶端去連線一個遠端的 Docker 守護程序。

Docker 客戶端和守護程序之間通過socket或者RESTful API進行通訊。

1)Docker守護程序

如上圖所示,Docker守護程序執行在一臺主機上。使用者並不直接和守護程序進行互動,而是通過 Docker 客戶端間接和其通訊。

2)Docker 客戶端

Docker 客戶端,實際上是 docker 的二進位制程式,是主要的使用者與 Docker 互動方式。它接收使用者指令並且與背後的 Docker 守護程序通訊,如此來回往復。

3)Docker 內部

要理解 Docker 內部構建,需要理解以下三種部件:

Docker 映象 - Docker images

Docker 倉庫 - Docker registeries

Docker 容器 - Docker containers

Docker的元件

Docker 映象

Docker 映象是Docker容器執行時的只讀模板,每一個映象由一系列的層 (layers) 組成。Docker 使用 UnionFS 來將這些層聯合到單獨的映象中。UnionFS 允許獨立檔案系統中的檔案和資料夾(稱之為分支)被透明覆蓋,形成一個單獨連貫的檔案系統。正因為有了這些層的存在,Docker 是如此的輕量。當你改變了一個 Docker 映象,比如升級到某個程式到新的版本,一個新的層會被建立。因此,不用替換整個原先的映象或者重新建立(在使用虛擬機器的時候你可能會這麼做),只是一個新 的層被新增或升級了。現在你不用重新發布整個映象,只需要升級,層使得分發 Docker 映象變得簡單和快速。

Docker 倉庫

Docker 倉庫用來儲存映象,可以理解為程式碼控制中的程式碼倉庫。同樣的,Docker 倉庫也有公有和私有的概念。公有的 Docker 倉庫名字是 Docker Hub。Docker Hub 提供了龐大的映象集合供使用。這些映象可以是自己建立,或者在別人的映象基礎上建立。Docker 倉庫是 Docker 的分發部分。

Docker 容器

Docker 容器和資料夾很類似,一個Docker容器包含了所有的某個應用執行所需要的環境。每一個 Docker 容器都是從 Docker 映象建立的。Docker 容器可以執行、開始、停止、移動和刪除。每一個 Docker 容器都是獨立和安全的應用平臺,Docker 容器是 Docker 的執行部分。

4)libcontainer

Docker 從 0.9 版本開始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系統的互動圖如下:

5)名稱空間「Namespaces」

1)pid namespace

不同使用者的程序就是通過pid namespace隔離開的,且不同 namespace 中可以有相同 PID。

具有以下特徵:

每個namespace中的pid是有自己的pid=1的程序(類似 /sbin/init 程序)

每個 namespace 中的程序只能影響自己的同一個 namespace 或子 namespace 中的程序

因為 /proc 包含正在執行的程序,因此在 container 中的 pseudo-filesystem 的 /proc 目錄只能看到自己namespace 中的程序

因為 namespace 允許巢狀,父 namespace 可以影響子 namespace 的程序,所以子 namespace 的程序可以在父namespace中看到,但是具有不同的 pid

2)mnt namespace

類似 chroot,將一個程序放到一個特定的目錄執行。mnt namespace 允許不同namespace的程序看到的檔案結構不同,這樣每個namespace 中的程序所看到的檔案目錄就被隔離開了。同 chroot 不同,每個 namespace 中的 container 在 /proc/mounts 的資訊只包含所在namespace的mount point。

3)net namespace

網路隔離是通過 net namespace 實現的, 每個 net namespace 有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每個 container 的網路就能隔離開來。 docker 預設採用 veth 的方式將 container 中的虛擬網絡卡同 host 上的一個 docker bridge 連線在一起。

4)uts namespace

UTS ("UNIX Time-sharing System") namespace 允許每個 container 擁有獨立的 hostname 和 domain name, 使其在網路上可以被視作一個獨立的節點而非 Host 上的一個程序。

5)ipc namespace

container 中程序互動還是採用 Linux 常見的程序間互動方法 (interprocess communication - IPC), 包括常見的訊號量、訊息佇列和共享記憶體。然而同 VM 不同,container 的程序間互動實際上還是 host 上具有相同 pid namespace 中的程序間互動,因此需要在IPC資源申請時加入 namespace 資訊 - 每個 IPC 資源有一個唯一的 32bit ID。

6)user namespace

每個 container 可以有不同的 user 和 group id, 也就是說可以以 container 內部的使用者在 container 內部執行程式而非 Host 上的使用者。

有了以上6種namespace從程序、網路、IPC、檔案系統、UTS 和使用者角度的隔離,一個 container 就可以對外展現出一個獨立計算機的能力,並且不同container從OS層面實現了隔離。然而不同 namespace 之間資源還是相互競爭的,仍然需要類似ulimit 來管理每個container所能使用的資源。

6)資源配額「cgroups」

cgroups

實現了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似檔案的介面,在 /cgroup 目錄下新建一個資料夾即可新建一個 group,在此資料夾中新建 task 檔案,並將 pid 寫入該檔案,即可實現對該程序的資源控制。具體的資源配置選項可以在該資料夾中新建子 subsystem ,{子系統字首}.{資源項} 是典型的配置方法, 如 memory.usageinbytes 就定義了該 group 在 subsystem memory 中的一個記憶體限制選項。

另外,cgroups 中的 subsystem 可以隨意組合,一個 subsystem 可以在不同的 group 中,也可以一個 group 包含多個 subsystem - 也就是說一個 subsystem。

memory

記憶體相關的限制

cpu

在 cgroup 中,並不能像硬體虛擬化方案一樣能夠定義 CPU 能力,但是能夠定義 CPU 輪轉的優先順序,因此具有較高 CPU 優先順序的程序會更可能得到 CPU 運算。 通過將引數寫入 cpu.shares ,即可定義改 cgroup 的 CPU 優先順序 - 這裡是一個相對權重,而非絕對值

blkio

block IO 相關的統計和限制,byte/operation 統計和限制 (IOPS 等),讀寫速度限制等,但是這裡主要統計的都是同步 IO

devices

裝置許可權限制

Docker的工作原理

1)可以建立一個容納應用程式的容器。

2)可以從Docker映象建立Docker容器來執行應用程式。

3)可以通過Docker Hub或者自己的Docker倉庫分享Docker映象。

Docker映象是如何工作的?

Docker映象是Docker容器執行時的只讀模板,每一個映象由一系列的層(layers)組成;

Docker使用UnionFS(聯合檔案系統)來將這些層聯合到一二映象中,UnionFS檔案系統允許獨立檔案系統中的檔案和資料夾(稱之為分支)被透明覆蓋,形成一個單獨連貫的檔案系統。

正因為有了這些層(layers)的存在,Docker才會如此的輕量。當你改變了一個Docker映象,比如升級到某個程式到新的版本,一個新的層會被建立。因此,不用替換整個原先的映象或者重新建立(在使用虛擬機器的時候你可能會這麼做),只是一個新的層被新增或升級了。所以你不用重新發布整個映象,只需要升級。層使得分發Docker映象變得簡單和快速。

每個映象都是從一個基礎的映象開始的,比如ubuntu,一個基礎的Ubuntu映象,或者是Centos,一個基礎的Centos映象。你可以使用你自己的映象作為新映象的基礎,例如你有一個基礎的安裝了Nginx的映象,你可以使用該映象來建立你的Web應用程式映象。(Docker通常從Docker Hub獲取基礎映象)

Docker映象從這些基礎的映象建立,通過一種簡單、具有描述性的步驟,我們稱之為 指令(instructions)。

每一個指令會在映象中建立一個新的層,指令可以包含這些動作:

1)執行一個命令。

2)增加檔案或者資料夾。

3)建立一個環境變數。

5)當執行容器的時候哪些程式會執行。

這些指令儲存在Dockerfile檔案中。當你需要建立映象的時候,Docker可以從Dockerfile中讀取這些指令並且執行,然後返回一個最終的映象。

Docker倉庫是如何工作的?

Docker倉庫是Docker映象的儲存倉庫。可以推送映象到Docker倉庫中,然後在Docker客戶端,可以從Docker倉庫中搜索映象。

Docker容器是如何工作的?

一個Docker容器包含了一個作業系統、使用者新增的檔案和元資料(meta-data)。每個容器都是從映象建立的,映象告訴Docker容器內包含了什麼,當容器啟動時執行什麼程式,還有許多配置資料。

Docker映象是隻讀的,當Docker執行一個從映象建立的容器,它會在映象頂部新增一個可讀寫的層,應用程式可以在這裡執行。

當執行docker容器時發生了什麼?

使用docker命令時,Docker客戶端都告訴Docker守護程序執行一個容器。

docker run -i -t ubuntu /bin/bash

可以來分析這個命令,Docker客戶端使用docker命令來執行,run引數表明客戶端要執行一個新的容器。

Docker客戶端要執行一個容器需要告訴Docker守護程序的最小引數資訊是:

1)這個容器從哪個映象建立,這裡是ubuntu,基礎的Ubuntu映象。

2)在容器中要執行的命令,這裡是/bin/bash,在容器中執行Bash shell。

那麼執行這個命令之後在底層發生了什麼呢?

按照順序,Docker做了這些事情:

1)拉取ubuntu映象: Docker檢查ubuntu映象是否存在,如果在本地沒有該映象,Docker會從Docker Hub下載。如果映象已經存在,Docker會使用它來建立新的容器。

2)建立新的容器: 當Docker有了這個映象之後,Docker會用它來建立一個新的容器。

3)分配檔案系統並且掛載一個可讀寫的層: 容器會在這個檔案系統中建立,並且一個可讀寫的層被新增到映象中。

4)分配網路/橋接介面: 建立一個允許容器與本地主機通訊的網路介面。

5)設定一個IP地址: 從池中尋找一個可用的IP地址並且服加到容器上。

6)執行你指定的程式: 執行指定的程式。

7)捕獲並且提供應用輸出: 連線並且記錄標準輸出、輸入和錯誤讓你可以看到你的程式是如何執行的。

由此你就可以擁有一個執行著的Docker容器了!從這裡開始你可以管理你的容器,與應用互動,應用完成之後,可以停止或者刪除你的容器。

Docker的底層技術

Docker使用Go語言編寫,並且使用了一系列Linux核心提供的效能來實現我們已經看到的這些功能。

名稱空間(Namespaces)(這個上面也詳細說明了)

Docker充分利用了一項稱為namespaces的技術來提供隔離的工作空間,我們稱之為 container(容器)。當你執行一個容器的時候,Docker為該容器建立了一個名稱空間集合。

這樣提供了一個隔離層,每一個應用在它們自己的名稱空間中執行而且不會訪問到名稱空間之外。

一些Docker使用到的名稱空間有:

pid名稱空間: 使用在程序隔離(PID: Process ID)。

net名稱空間: 使用在管理網路介面(NET: Networking)。

ipc名稱空間: 使用在管理程序間通訊資源 (IPC: InterProcess Communication)。

mnt名稱空間: 使用在管理掛載點 (MNT: Mount)。

uts名稱空間: 使用在隔離核心和版本標識 (UTS: Unix Timesharing System)。

群組控制

Docker還使用到了cgroups技術來管理群組。使應用隔離執行的關鍵是讓它們只使用你想要的資源。這樣可以確保在機器上執行的容器都是良民(good multi-tenant citizens)。群組控制允許Docker分享或者限制容器使用硬體資源。例如,限制指定的容器的內容使用。

聯合檔案系統

聯合檔案系統(UnionFS)是用來操作建立層的,使它們輕巧快速。Docker使用UnionFS提供容器的構造塊。Docker可以使用很多種類的UnionFS包括AUFS, btrfs, vfs, and DeviceMapper。

容器格式

Docker連線這些組建到一個包裝中,稱為一個 container format(容器格式)。預設的容器格式是libcontainer。Docker同樣支援傳統的Linux容器使用LXC。在未來,Docker也許會支援其它的容器格式,例如與BSD Jails 或 Solaris Zone整合。

Docker與VM的區別:

image

docker與Openstack的對比

image

Docker與虛擬機器比較

作為一種輕量級的虛擬化方式,Docker在執行應用上跟傳統的虛擬機器方式相比具有顯著優勢:

  • Docker容器很快,啟動和停止可以在秒級實現,這相比傳統的虛擬機器方式要快得多。

  • Docker容器對系統資源需求很少,一臺主機上可以同時執行數千個Docker容器。

  • Docker通過類似Git的操作來方便使用者獲取、分發和更新應用映象,指令簡明,學習成本較低。

  • Docker通過Dockerfile配置檔案來支援靈活的自動化建立和部署機制,提高工作效率。

虛擬機器實現了硬體上的虛擬,而Docker則實現了作業系統級別的虛擬。

Docker用途簡單配置、程式碼流水線管理、開發效率、應用隔離、伺服器整合、除錯能力、多租戶、快速部署

image

​參考連結: