Docker(一)——docker入門詳解

一、Docker基礎篇

1、什麼是Docker?

Docker是PaaS 提供商 dotCloud 開源的一個基於 LXC 的高級容器引擎,源代碼託管在 Github 上, 基於go語言並遵從Apache2.0協議開源。最初實現是基於LXC,從0.7以後開始去除LXC,轉而使用自行開發的libcontainer,從1.11開始,則進一步演進爲使用runC和containerd。

Docker 容器可以快速自動化地部署應用,並通過操作系統內核技術(namespaces、cgroups等)容器提供資源隔離與安全保障。Docker 作爲輕量級的虛擬化方式,實現了PaaS平臺高效部署、運行和維護。

Docker是完整的一套容器管理系統。Docker提供了一組命令,讓用戶更加方便直接地使用容器技術,而不需要過多關心底層內核技術。

2、容器與虛擬機

我們先區分兩個概念:容器與虛擬機

很多人都用過虛擬機,我們用的傳統虛擬機如 VMware 都需要模擬整臺機器包括硬件。每臺虛擬機都需要有自己的操作系統,虛擬機一旦被開啓,預分配給它的資源將全部被佔用。每臺虛擬機包括應用,必要的二進制和庫,以及一個完整的用戶操作系統。 傳統虛擬機技術是虛擬出一套硬件後,在其上運行一個完整操作系統,在該系統上再運行所需應用進程

容器技術是和我們的宿主機共享硬件資源及操作系統,可以實現資源的動態分配。容器包含應用和其所有的依賴包,但是與其他容器共享內核。容器在宿主機操作系統中,在用戶空間以分離的進程運行容器技術是實現操作系統虛擬化的一種途徑,可以讓您在資源受到隔離的進程中運行應用程序及其依賴關係。

傳統虛擬化結構對比Docker結構

Docker 屬於Linux容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的 Linux 容器解決方案。

容器不是模擬一個完整的操作系統,而是對進程進行隔離,相當於是在正常進程的外面套了一個保護層。對於容器裏面的進程來說,它接觸到的各種資源都是虛擬的,從而實現與底層系統的隔離。

Docker 將應用程序與該程序的依賴,打包在一個文件裏面。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裏運行,就好像在真實的物理機上運行一樣。有了 Docker ,就不用擔心環境問題。

總體來說,Docker 的接口相當簡單,用戶可以方便地創建和使用容器,把自己的應用放入容器。容器還可以進行版本管理、複製、分享、修改,就像管理普通的代碼一樣。

3、Docker 的優勢(爲什麼使用docker)

在這裏插入圖片描述

  • Docker 啓動快速屬於秒級別。虛擬機通常需要幾分鐘去啓動。

  • Docker 需要的資源更少。Docker 在操作系統級別進行虛擬化,Docker 容器和內核交互,幾乎沒有性能損耗,性能優於通過 Hypervisor 層(一種運行在基礎物理服務器和操作系統之間的中間軟件層)與內核層的虛擬化。

  • Docker 更輕量,更高效的系統資源利用。Docker 的架構可共用一個內核與共享應用程序庫,所佔內存極小。同樣的硬件環境,Docker 運行的鏡像數遠多於虛擬機數量,對系統的利用率非常高

  • 一致的運行環境。由於開發環境、測試環境、生產環境不一致,會導致有些bug並未在開發過程中被發現。應用運行環境一致,就不會再出現“這段代碼在我機器上沒問題啊”這類問題。

  • 持續交付和部署。對開發和運維(DevOps)人員來說,最希望的就是一次創建或配置,可以在任意地方正常運行。

  • 更輕鬆的遷移。由於Docker確保了執行環境的一致性,使得應用的遷移更加容易。

  • 更輕鬆的維護和擴展。Docker使用的分層存儲以及鏡像的技術,使得應用重複部分的複用更爲容易,也使得應用的維護更新更加簡單,基於基礎鏡像進一步擴展鏡像也變得非常簡單。

4、Docker 應用場景

在這裏插入圖片描述Docker用途:簡單配置、代碼流水線管理、開發效率、應用隔離、服務器整合、調試能力、多租戶、快速部署

5、Docker 體系架構

在這裏插入圖片描述
docker由 docker-client ,docker engine,containerd,docker-shim,runc組成,現在來談談每個組件是用來幹嘛的:

  • containerddocker engine實際真實調用的還是containerd的api接口(rpc方式實現),containerd是docker engine和runc之間的一箇中間交流組件。

  • docker-shim:docker-shim是一個真實運行的容器的真實墊片載體,每啓動一個容器都會起一個新的docker-shim的一個進程,他直接通過指定的三個參數:容器id,boundle目錄(containerd的對應某個容器生成的目錄,一般位於:/var/run/docker/libcontainerd/containerID),運行是二進制(默認爲runc)來調用runc的api創建一個容器。

  • runc: runc是一個命令行工具端,他根據oci(開放容器組織)的標準來創建和運行容器。

在這裏插入圖片描述

Docker 是一個客戶/服務器(Client/Server,CS)架構Docker Client是遠程控制器,可通過TCP RESTDocker Host 發送請求(創建容器、運行容器、保存容器、刪除容器等)。Docker服務端的Daemon 對客戶端的請求進行相應的管理,隨後通過 driver轉發至容器中的libcontainer執行環境。libcontainer提供與不同Linux內核隔離的接口,類似命名空間及控制組。這種架構允許多個容器在共享同一個Linux內核的情況下完全隔離的運行。

在這裏插入圖片描述

二、Docker 三大核心概念

Docker 包括三個基本概念:

  • 鏡像(Image)
  • 容器(Container)
  • 倉庫(Repository)

1、Docker 鏡像(Image)

Docker 鏡像類似於虛擬機鏡像,可以將它理解爲一個只讀的模板,每一個鏡像由一系列的層 (layers) 組成。例如,一個鏡像可以包含一個基本的操作系統環境,裏面僅安裝了 Apache 應用程序(或用戶需要的其他軟件)。可以把它稱爲一個 Apache鏡像。

鏡像是創建Docker 容器的基礎。通過版本管理和增量的文件系統,Docker提供了一套十分簡單的機制來創建和更新現有的鏡像,用戶甚至可以從網上下載一個已經做好的應用鏡像,並直接使用。

Docker 使用 UnionFS 來將這些層聯合到單獨的鏡像中。UnionFS 允許獨立文件系統中的文件和文件夾(稱之爲分支)被透明覆蓋,形成一個單獨連貫的文件系統。正因爲有了這些層的存在,Docker 是如此的輕量。當你改變了一個 Docker 鏡像,比如升級到某個程序到新的版本,一個新的層會被創建。因此,不用替換整個原先的鏡像或者重新建立(在使用虛擬機的時候你可能會這麼做),只是一個新 的層被添加或升級了。現在你不用重新發布整個鏡像,只需要升級,層使得分發 Docker 鏡像變得簡單和快速。

2、Docker 容器(Container)

Docker 容器類似於一個輕量級的沙箱,Docker 利用容器來運行和隔離應用。容器是從鏡像創建的應用運行實例,可以將其啓動、開始、停止、刪除,而這些容器都是彼此相互隔離的、互不相見的。

可以把容器看做是一個簡易版的Linux系統環境(包括root用戶權限、進程空間、用戶空間和網絡空間等)以及運行在其中的應用程序打包而成的盒子。

每一個 Docker 容器都是獨立和安全的應用平臺,Docker 容器是 Docker 的運行部分。

3、Docker 倉庫(Repository)

Docker 倉庫類似於代碼倉庫,它是Docker集中存放鏡像文件的場所。

倉庫註冊服務器是存放倉庫的地方,其上往往存放着多個地方。每個倉庫集中存放某一類鏡像,往往包括多個鏡像文件,通過不同的標籤(tag)來進行區分。一個倉庫會包含同一個軟件不同版本的鏡像,而標籤就常用於對應改軟件的各個版本。我們可以通過 <倉庫名>:<標籤>的格式來指定具體是這個軟件哪個版本的鏡像。如果不給出標籤,將以 latest 作爲默認標籤。
  
Docker 倉庫也有公有和私有的概念。
公有 Docker 倉庫名字是 Docker Hub。Docker Hub 提供了龐大的鏡像集合供使用。這些鏡像可以是自己創建,或者在別人的鏡像基礎上創建。 國內還有(時速雲、阿里雲)等公開倉庫。

當用戶不希望公開自己的鏡像文件,Docker 也支持用戶在本地網絡內創建一個只能自己訪問的私有倉庫。當用戶創建了自己的鏡像之後就可以使用push命令將其上傳到指定的公有或者私有倉庫。這樣下次在另外一臺機器上使用該鏡像時,只需要將其從倉庫上pull 下來就可以了。Docker 倉庫是 Docker 的分發部分。

4、 Docker容器運行時會做哪些事情?

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

docker run -i -t ubuntu /bin/bash

可以來分析這個命令,Docker客戶端使用docker命令來運行,run參數表明客戶端要運行一個新的容器。
Docker客戶端要運行一個容器需要告訴Docker守護進程的最小參數信息是:
-> 這個容器從哪個鏡像創建,這裏是ubuntu,基礎的Ubuntu鏡像。
-> 在容器中要運行的命令,這裏是/bin/bash,在容器中運行Bash shell。

那麼運行這個命令之後在底層發生了什麼呢?按照順序,Docker做了這些事情:
-> 拉取ubuntu鏡像:Docker檢查ubuntu鏡像是否存在,如果在本地沒有該鏡像,Docker會從Docker Hub下載。如果鏡像已經存在,Docker會使用它來創建新的容器。
-> 創建新的容器:當Docker有了這個鏡像之後,Docker會用它來創建一個新的容器。
-> 分配文件系統並且掛載一個可讀寫的層:容器會在這個文件系統中創建,並且一個可讀寫的層被添加到鏡像中。
-> 分配網絡/橋接接口:創建一個允許容器與本地主機通信的網絡接口。
-> 設置一個IP地址:從池中尋找一個可用的IP地址並且服加到容器上。
-> 運行你指定的程序:運行指定的程序。
-> 捕獲並且提供應用輸出:連接並且記錄標準輸出、輸入和錯誤讓你可以看到你的程序是如何運行的。
由此就可以擁有一個運行着的Docker容器了!從這裏開始你可以管理你的容器,與應用交互,應用完成之後,可以停止或者刪除你的容器。

三、Docker容器的底層技術

Docker容器的底層技術:Namesapce(資源隔離)Cgroup(資源限制)

1、Namespaces

命名空間(namespaces)是 Linux 爲我們提供的用於分離進程樹、網絡接口、掛載點以及進程間通信等資源的方法。

如果我們在服務器上啓動了多個服務,每一個服務都能看到其他服務的進程,也可以訪問宿主機器上的任意文件。一旦服務器上的某一個服務被入侵,那麼入侵者就能夠訪問當前機器上的所有服務和文件,這也是我們不想看到的,而 Docker 其實就通過 Linux 的 Namespaces 對不同的容器實現了隔離。

(1)pid namespace:使用在進程隔離(Process ID):
不同用戶的進程就是通過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:使用在管理掛載點(Mount)
類似 chroot,將一個進程放到一個特定的目錄執行。mnt namespace 允許不同namespace的進程看到的文件結構不同,這樣每個namespace 中的進程所看到的文件目錄就被隔離開了。同 chroot 不同,每個 namespace 中的 container 在 /proc/mounts 的信息只包含所在namespace的mount point。

(3)net namespace:使用在進程網絡接口(Networking)
網絡隔離是通過 net namespace 實現的, 每個 net namespace 有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每個 container 的網絡就能隔離開來。 docker 默認採用 veth 的方式將 container 中的虛擬網卡同 host 上的一個 docker bridge 連接在一起。

(4)uts namespace:使用在隔離內核和版本標識 (Unix Timesharing System)
UTS (“UNIX Time-sharing System”) namespace 允許每個 container 擁有獨立的 hostname 和 domain name, 使其在網絡上可以被視作一個獨立的節點而非 Host 上的一個進程。

(5)ipc namespace:使用在管理進程間通信資源 (InterProcess Communication)
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 種 NameSpaces 從進程、網絡、IPC、文件系統、UTS和用戶角度的隔離,一個 container 就可以對外展現出一個獨立計算機的能力,並且不同 container 從 OS 層面實現了隔離。

然而不同 namespace 之間資源還是相互競爭的,仍然需要類似ulimit來管理每個 container 所能使用的資源。

2、cgroups(Control groups)

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

cgroups實現了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似文件的接口,在 /cgroup 目錄下新建一個文件夾即可新建一個 group,在此文件夾中新建 task 文件,並將 pid 寫入該文件,即可實現對該進程的資源控制。

  • memory:內存相關的限制
  • cpu:在 cgroup 中,並不能像硬件虛擬化方案一樣能夠定義 CPU 能力,但是能夠定義 CPU 輪轉的優先級,因此具有較高 CPU 優先級的進程會更可能得到 CPU 運算。 通過將參數寫入 cpu.shares ,即可定義改 cgroup 的 CPU 優先級 - 這裏是一個相對權重,而非絕對值
  • blkio:block IO 相關的統計和限制,byte/operation 統計和限制 (IOPS 等),讀寫速度限制等,但是這裏主要統計的都是同步 IO
  • devices:設備權限限制

3、Docker 聯合文件系統

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

4、Docker 容器格式

Docker連接這些組建到一個包裝中,稱爲一個 container format(容器格式)。默認的容器格式是libcontainer。Docker同樣支持傳統的Linux容器使用LXC。在未來,Docker也許會支持其它的容器格式,例如與BSD Jails 或 Solaris Zone集成。

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