1. 程式人生 > 實用技巧 >1. Docker容器技術基礎入門

1. Docker容器技術基礎入門

容器

容器是一種基礎工具;泛指任何可以用於容納其他物品的工具,可以部分或完全封閉,被用於容納、儲存、運輸物品;物體可以被放置在容器中,而容器則可以保護內容物。

LXC

全稱:LinuX Container

虛擬化和容器之間的關係

虛擬化常用實現形式有兩種:

  • 主機級虛擬機器化(虛擬化整個完整的物理硬體平臺,如:VMware Workstation ):
    • Type-I:直接硬體基礎上安裝一個虛擬機器管理器Hypervisor,在這之上在安裝虛擬機器;
    • Type-II:在物理機上裝一個宿主機作業系統,在宿主機的基礎上裝一個VMM虛擬機器管理器,然後再建立虛擬機器,例如:VMware Workstation、VirtBox、KVM
  • 容器級虛擬化

主機級虛擬化的實現機制是,首先得有硬體平臺,而後有 VMM,使用者需要在虛擬機器之上部署一個完整的作業系統,包括核心、使用者空間,而後在使用者空間跑應用程式程序。而執行核心不是主要的目的,核心核心作用在於資源分配和管理。在使用者空間跑的應用程序才是真正實現生產力的。 所以說,真正能產生生產力的是使用者空間的應用程序,而不是出於通用目的而設計的資源管理平臺系統核心,而在虛擬化中,核心又是不可獲取的存在。原因在於在一組硬體平臺上使用軟體程式,軟體程式基本都是針對核心的系統呼叫和庫呼叫研發的,如果不安裝核心、不安裝庫、不安裝執行環境,是沒辦法執行應用程式的,所以核心必不可少。更何況,一旦有使用者空間以後,要執行很多程序,這些程序為了協調,也必須要由核心來實現。

假設建立一個虛擬機器的目的就為了執行一個單一的Web服務,為此卻不得不安裝核心安裝使用者空間,然後跑Web服務,這樣的代價就比較大。而且更主要的是,一個程序為了執行,需要實現兩級排程和分派,虛擬機器有自己的核心,此核心就已經實現了,資源分派,IO排程,而虛擬機器的本身也是被宿主機核心管理的一個抽象層而已,因此還需要被宿主機核心或者是 Hypervisor 再需要排程和管理一次,這之間的排程和開銷就不言而喻了。 這種傳統的主機虛擬化技術確實能夠在一組硬體之上實現所謂的跨系統環境的隔離和除錯各種需求,但帶來的資源開銷也是不容忽視的,而很多時候建立虛擬機器的目的僅僅是為了執行有限的一個或幾個富有生產的程序而已,而為此付出的代價有點大了,既然如此,減少中間層、減少中間環節是有效提高效率的方式。比如說,現在需要提升效率的話,能不能把虛擬機器中間的核心抽掉,只保留程序,但是使用虛擬機器是目的之一也是為了環境的隔離。比如同時執行nginx,都監聽80埠,一臺主機是做不到的。有了虛擬機器之後,開兩臺虛擬機器在同一個宿主機上執行兩個nginx是完全沒問題的,這是一種需求。 所以建立虛擬機器的目的,假如只是為了執行程序為什麼不直接放在宿主機上執行,而非要放在虛擬機器中,目標是為了資源的隔離使用,就算 tomcat 在虛擬機器中吃掉了所有的CPU和記憶體資源,都不會影響到其他虛擬機器系統程序,最多損壞的只是那一個虛擬機器,所以隔離才是追求的目標。所以抽掉一層核心,但又不能讓程序直接跑在同一個使用者空間,而是需要讓每一個程序或每一組程序彼此之間是相互隔離的,就像類似執行兩個虛擬機器的程序互相不可達一樣,互不干擾,而共享同一組底層硬體資源而已。

如圖,在虛擬隔離環境管理器之上創建出一個個隔離環境,讓需要隔離出來執行的程序跑在每個隔離環境中,程序是跑在使用者空間的,所以這裡的隔離是在隔離使用者空間。通常來講,使用者空間是隻有一組的,現在期望實現的是將這個使用者空間隔離成多組,彼此之間互相不干擾,一個使用者空間內只執行一個程序或部分程序。但無論怎麼隔離,這其中必定有一個特權空間,一般是第一個。通過這個特權空間來管理其他隔離空間。這些眾多的隔離空間能夠共享同一個核心,大家都被同一個核心管理,但是這些隔離空間執行時能夠看到的邊界卻是自己所屬使用者空間的邊界。這種隔離顯然沒有主機級虛擬化隔離的徹底。這些隔離空間拿來放程序的,給程序提供執行環境並且還能夠保護其內部的程序不受其他程序的干擾,所以這就是容器。 這就是在 Linux 中經常提到的 容器技術。

容器技術最早出現在 FreeBSD上,當年叫 Jail ,其實目的只是為了執行一程序不受其他的干擾。就算這個程序出現bug故障也不會對其他系統造成干擾。這種隔離帶來的是安全執行的初衷。 後來 Jail 這種技術就拿到Linux中叫:vserver,類似與 chroot

一個隔離空間主要實現的目標是隔離,任何程序執行在這個隔離空間中都認為自己是唯一執行在當前這個核心之上使用者空間的程序,所能看到的其他程序也都是。

一個系統執行起來可以看作兩棵樹:

  1. 檔案系統樹
  2. 程序樹

在Linux 程序管理界,從來都是白髮人送黑髮人,子程序由它的父程序建立,而子程序終止並回收也是由父程序來實現的。如果 init 結束了, 它就會把所屬它的所有子程序全部終止。

一個隔離使用者空間應該看到的以下元件:

  1. UTS - 主機名和域名
  2. 根檔案系統
  3. IPC(程序間通訊專用通道)在同一個隔離空間內是可以通訊的,跨隔離空間是無法通訊的。
  4. PID 需要為每個隔離空間偽裝一個PID為1的程序。
  5. User、Group 需要單獨做隔離
  6. Network

Linux 開始在核心級把這些資源作為可以切分為多個相互隔離的空間,就稱為:名稱空間。

意味著在同一個核心之上,創建出多個名稱空間,在這些名稱空間之上把 UTS 資源讓每個名稱空間和其他名稱空間隔離。

為了支撐容器機制的實現,Linux核心級對以上 6種名稱空間的切分原生支援,叫做 namespaces ,直接通過系統呼叫向外輸出。整個 Linux 領域的容器化技術就是靠核心級的 6 個 namespaceschroot 來實現的。

在容器級虛擬化中,隔離的名稱空間是工作在同一核心之上的,如果隔離空間故障佔用大量系統資源,會對其他隔離空間造成影響。因此,核心級還必須實現一個功能來限制每一個使用者空間中的程序的所有可用資源總量。比如:按CPU來分配。而這個功能在核心叫:CGroups

  • Cgroups
  • namespaces
  • chroot

有了 Cgroupsnamespaces 就可以愉快的使用容器了, 實際上容器的隔離能力相比主機級虛擬化來說,差很多。畢竟多個容器同屬於一個核心,只是在核心空間強行設定了邊界,而不像主機級虛擬化,大家原本就不屬於同一個核心,容器的隔離遠不如主機級虛擬化好。因此為了避免這種問題,實用了類似 selinux 等這樣的機制來加強容器的邊界管理。

為了容器更加的易用,將所有的容器實現的工具打包稱為了: LXC(LinuX Container)

LXC 是最早將容器技術用一組簡易實用的工具和模板來極大的簡化了容器技術使用的一種方案。LXC 在容器技術的推廣上功不可沒,但依然存在很多門檻。

  1. 理解LXC各種工具
  2. 需要定製模板
  3. 每一個使用者空間都是安裝生成的,生成資料檔案持久儲存的問題
  4. 批量建立使用者空間

Docker

LXC 雖然極大的簡化了容器的使用,但是比起虛擬機器來講,複雜程度並沒有多大降低的,更何況隔離性也沒有虛擬機器那麼好。好處在於,能讓每個使用者空間的程序使用宿主機的效能,中間沒有額外的開銷。資源方面的節約。於是就出現了 dockerdocker 只是 LXC 的增強版。

docker 是如何簡化的?

LXC 大規模建立容器很難,docker 早起的版本核心就是 LXC ,利用 LXC 做容器管理引擎,在建立容器時,不再是現場安裝模板,而是通過映象技術,整體打包成一個檔案,這個檔案就是映象檔案。這個映象檔案是放在一個集中統一的倉庫中的。

使用 docker create 建立一個容器時,不會啟用模板讓使用者去安裝,而是自動連線到映象倉庫伺服器去下載一個匹配建立容器所需要的映象,並基於映象來啟動容器。所以 docker 極大的簡化了容器的使用難度。

以後使用docker 啟動一個容器,直接使用命令:docker create 結束。

docker容器的原則是一個容器只執行一個程序。LXC 是把一個容器當一個使用者空間來使用,可以執行N個程序。

docker 容器編排工具:

  • machine + swarm + compose
  • mesos + marathon
  • kubernetes -> k8s