我們都知道Docker是一個容器化工具,那么什么是容器呢,Docker和容器有什么關系,Docker又能解決什么問題呢?
麻煩的環境配置
軟件開發最大的麻煩事之一就是環境配置,在開發之前我們需要準備各種運行環境、IDE、輔助工具。就像我們要使用電腦前,先要安裝操作系統一樣。
而一個可用軟件的交付過程通常包含兩個部分 - 開發和維護。不幸的是,我們很難保證軟件開發測試和運行維護階段的軟件能運行在一模一樣的環境下。開發常說:"It works on my machine",很多時候我們都要花大量的時間去配置環境和教別人配置環境。
現在的應用程序
- 以前的應用程序:
- 幾乎都是單塊應用: 大系統, 多模塊
- 緊耦合: 內部調用
- 不常變更: 需求穩定(改動成本高)
- 如今的應用程序:
- 解耦: 微服務/異步
- 經常變更: 快速迭代
- 動態創建和部署: 服務化
新架構的挑戰
- 多樣化的技術棧
- 需要動態創建機器
- 很多活動組件
- 運維人員需要管理復雜的架構
在新的應用程序架構下,我們部署應用的成本大大增加。
不但要搭建不同語言、不同技術棧適配的運行環境,還要部署到多個服務器主機上;并且這些主機還可能來自不同地方(公/私有云主機、物理主機)。
統一的管理
其實在軟件開發的過程中我們就思考過類似的問題 - 如何統一的管理我們的代碼包。例如,Maven、Gradle、NPM,我們使用一個相同的格式(規范)將我們的代碼劃分成模塊,并使用一套工具去管理他們。在此之后我們不需要重復的copy代碼、復制文件,只需要聲明式的引入我們需要的代碼包就可以了。
當然,我們希望我們的應用部署也能如此簡單。
“容器”
“容器”是一個黑盒,對于它的使用者來說:
- 無需關心里面有什么:只關注“容器”能做什么
- 有一套工具來管理黑盒:打包、運輸、運行
- 減少了部署單元的數量,從而減少了花銷:多個工具聚集在一個“容器”內
- 更容易管理多個環境:以“容器”為單位進行部署和管理
虛擬化技術
-
虛擬機
-
精心配置的虛擬機也是滿足我們(基本)要求的容器,我們能夠通過虛擬機鏡像來打包我們的應用。但是,龐大的操作系統占用了大量的系統資源,使運行成本大大上升。
VM.png
-
-
容器
-
(作為進程)共用內核并提供額外的隔離手段,避免虛擬的操作系統占用。
container.png
-
虛擬機
- 應用
- 運行環境(Java/數據庫/libs...)
- 客戶機操作系統(Guest Operating System)
- 虛擬機管理系統(Hypervisor)
- 操作系統級:MacOS(HyperKit),Windows的Hyper-V
- 應用軟件級:VirtualBox,VMWare Workstation
- 主操作系統(Host Operating System)
- 硬件(Infrastructure)/云主機
容器
- 應用
- 運行環境(Java/數據庫/libs...)
- Docker守護進程(Docker Daemon): 類似虛擬機管理系統
- 主操作系統(Host Operating System)
- 硬件(Infrastructure)/云主機
容器技術
容器技術已經發展了一段時間了, 例如, LXC, BSD Jails, Solaris Zones...
- 看起來像虛擬機
- 可以SSH到容器
- 具有root的訪問權限
- 可以安裝包
- 可以mount文件系統
- 擁有自己的eth0接口
- 可以修改iptables 規則和routing table
- 共享宿主機的內核
- 隔離 cgroups (memory, cpu, blkio)
- 擁有進程空間 (pid, mnt, net, ipc, uts)
- pid - 隔離進程PID
- mnt - 允許創建不同的文件系統層級
- net - 隔離網絡控制、iptables、防火墻、路由
- ipc - 定義內部進程交流的范圍
- uts - 允許修改hostname
容器技術的局限
- 容器沒有標準的格式
- 所以容器是不可移植的
- 沒有標準的工具,所以比如要自己管理網絡
- 沒有可重用的模塊和API
Docker
- 使容器變得更容易使用
- 容器鏡像的商品化
- 可插拔的模塊易于吸引供應商加入
- 適當的API可用來創建高層次抽象的工具
- 和微服務誕生在同一個時代
Docker架構
- Docker Client:接收命令和Docker Host進行交互的客戶端
- Docker Host:運行Docker服務的主機
- Docker Daemon:守護進程,用于管理所有鏡像和容器
- Docker Images/Containers:鏡像和容器實例
- Registry(Hub):鏡像倉庫
Docker底層實現
Docker核心技術
- Namespace 命名空間
Linux 的命名空間機制提供了以下七種不同的命名空間,包括CLONE_NEWCGROUP、CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS
,通過這七個選項我們能在創建新的進程時設置新進程應該在哪些資源上與宿主機器進行隔離。因此容器只能感知內部的進程,而對宿主機和其他容器一無所知。 - CGroups (Control Groups)
Linux 的 CGroup 能夠為一組進程分配資源,也就是我們在上面提到的 CPU、內存、網絡帶寬等資源. -
UnionFS
union-fs.png
Docker中的每一個鏡像都是由一系列的只讀層組成的,Dockerfile 中的每一個命令都會在已有的只讀層上創建一個新的層。通過 docker run 命令可以在鏡像的最上層添加一個可寫的層 - 容器層,所有對于運行時容器的修改其實都是對這個容器讀寫層的修改。
容器和鏡像的區別就在于,所有的鏡像都是只讀的,而每一個容器其實等于鏡像加上一個可讀寫的層,也就是同一個鏡像可以對應多個容器。同時已構建的每一層鏡像也可以作為其他鏡像的基礎層進行共用。