天天看點

極客時間雲原生訓練營

 docker跟以往的vm虛拟機有什麼差別?

為什麼我們經常說docker是輕量級的虛拟機,它跟我們之前用的vmware,virtualbox等虛拟機有什麼差別,輕在哪兒呢?讓我們首先看看兩者對比圖:

vm虛拟機 vs docker

從上圖我們可以很直覺地看到這兩者的差別:

vm虛拟機:從下到上,分别是server(實體機,如macbook)、host os(實體機的作業系統,如macos)、hypervisor(用于運作虛拟機負責虛拟化的管理軟體,如virtualbox)、guest os(在虛拟機上安裝的作業系統,如ubuntu,跟上層應用服務沒有明顯綁定關系)、bins/libs(app依賴的各種類庫)、apps(應用程式)。

其中我們可以很明顯地看出來,app跟依賴庫(libs)以及虛拟機作業系統之間沒有很明顯的綁定關系,app在能夠到虛拟機作業系統上面運作之前,需要提前準備環境,增加不少運維成本,更重要的是,部署應用程式的時候,不能保證依賴的運作環境必然充分。

docker:從下往上,分别是server、host os(前二相同)、docker engine(docker的運作引擎,守護程序,我們待會也會着重講解這塊的核心設計)、containers(多個運作容器)。

docker的精髓主要展現在docker engine層的資源隔離設計以及container層的一體化打包方式上。另外,docker比vm虛拟機輕的地方在于,由docker engine抽象出來的虛拟化技術,讓上層的container服務可以設計得非常輕量:穩定的鏡像+空間節約+秒級啟動。

docker engine

docker基本思想

基礎設施即代碼(infrastructure as code)

docker的出現,主要是解決在開發、測試、線上運維的各個階段,需要一種虛拟化技術來解決環境不一緻的問題。

docker把基礎設施的建構過程通過dockerfile讓我們将應用程式的運作環境依賴跟業務代碼一起納入到版本控制中,避免因為環境不一緻造成運作結果不符預期的可能。這種方式就是我們常說的基礎設施即代碼的思想。

不可變基礎設施(immutable infrastructure)

通過版本控制 + ci/cd過程 + docker技術,我們可以在每次釋出時建構出來一個不可變的鏡像,這個鏡像不管在什麼平台上面運作,都能借助docker engine的能力,維持應用程式的環境穩定,減少運維維護成本。這就是“不可變基礎設施(immutable infrastructure)”。

docker的出現确實是應時代所需,那麼,docker的這種虛拟化技術的出現有哪些核心技術的支撐呢?

docker核心實作

docker 技術架構

docker的虛拟化技術借助了linux系統的基礎技術,如使用namespace來隔離資源,使用cgroups來隔離執行單元,使用ufs來組合不同檔案系統。

下面我們逐個對這些概念做下了解。

namespace

docker虛拟化的第一個問題,是如何在同一台機器上,把程序、記憶體、檔案系統、網絡這些基本要素隔離起來,讓每一個容器之間互不影響?

解決方案是namespace,目前,linux核心裡面提供了7種不同類型的namespace:

名稱        宏定義             隔離内容

cgroup      clone_newcgroup   cgroup root directory (since linux 4.6)

ipc         clone_newipc      system v ipc, posix message queues (since linux 2.6.19)

network     clone_newnet      network devices, stacks, ports, etc. (since linux 2.6.24)

mount       clone_newns       mount points (since linux 2.4.19)

pid         clone_newpid      process ids (since linux 2.6.24)

user        clone_newuser     user and group ids (started in linux 2.6.23 and completed in linux 3.8)

uts         clone_newuts      hostname and nis domain name (since linux 2.6.19)

其中,docker主要使用了其中的cgroups, ipc, network, mount, pid:

1、程序隔離(pid namespace)

我們運作一個redis的docker容器,通過docker exec的方式進入容器内部,檢視程序清單,可以看到:

# ps -ef

uid        pid  ppid  c stime tty          time cmd

redis        1     0  0  2018 ?        09:01:49 redis-server 0.0.0.0:6379      

root     61599     0  1 15:18 ?        00:00:00 /bin/bash

root     61604 61599  0 15:18 ?        00:00:00 ps -ef

看到裡面展示的隻有這個container的程序清單,卻對主控端的其他程序一無所知,而且這個程序清單的第一條程序的pid是1,也就是init程序,這就不是簡單的程序過濾了,而是通過clone_newpid這個namespace實作的,完全建立出來了一套獨立的程序管理體系來實作程序隔離。

2、網絡隔離(network namespace)

docker中的服務,大部分是需要通過網絡來實作與外界通信的,那如何讓container有自己的網絡位址避免端口沖突,又能通過主控端跟外界互動呢?

linux network namespace能讓程序擁有一個完全獨立的網絡協定棧視圖,而docker利用它為每個container提供一個獨立的虛拟網卡,并提供了4種網絡隔離的方式給container使用,它們分别是:

host模式,--net=host,使用跟主控端一樣的網絡,不會配置設定獨立的network namespace。

container模式,--net=containerid,指定跟其他container共同使用同一個已建立的network namespace。

none模式,--net=none,擁有空的獨立network namespace,但不會建立獨立虛拟網卡。

bridge模式,--net=bridge,是docker的預設方式,擁有獨立的network namespace及虛拟網卡、獨立ip,并通過虛拟網橋的方式連接配接到主控端對外通信。

繼續閱讀