微服務架構之「 容器技術 」

如今一聊到容器技術,你們就默認是指 Docker 了。但事實上,在 Docker 出現以前,PaaS社區早就有容器技術了,以 Cloud Foundry、OpenShift 爲表明的就是當時的主流。docker

那爲啥最終仍是 Docker  火起來了呢?服務器

由於傳統的PaaS技術雖然也能夠一鍵將本地應用部署到雲上,而且也是採用隔離環境(容器)的形式去部署,可是其兼容性很是的很差。由於其主要原理就是將本地應用程序和啓停腳本一同打包,而後上傳到雲服務器上,而後再在雲服務器裏經過腳本啓動這個應用程序。微信

這樣的作法,看起來很理想。可是在實際狀況下,因爲本地與雲端的環境差別,致使上傳到雲端的應用常常各類報錯、運行不起來,須要各類修改配置和參數來作兼容。甚至在項目迭代過程當中不一樣的版本代碼都須要從新去作適配,很是耗費精力。網絡

然而 Docker  卻經過一個小創新完美的解決了這個問題。在 Docker 的方案中,它不只打包了本地應用程序,並且還將本地環境(操做系統的一部分)也打包了,組成一個叫作「 Docker鏡像 」的文件包。因此這個「 Docker鏡像 」就包含了應用運行所需的所有依賴,咱們能夠直接基於這個「 Docker鏡像 」在本地進行開發與測試,完成以後,再直接將這個「 Docker鏡像 」一鍵上傳到雲端運行便可。架構

Docker 實現了本地與雲端的環境徹底一致,作到了真正的一次開發隨處運行。微服務

1、容器究竟是什麼?

容器究竟是什麼呢?也許對於容器不太瞭解,但咱們對虛擬機熟悉啊,那麼咱們就先來看一下容器與虛擬機的對比區別:測試

 

上圖的左側是虛擬機的原理,右側是Docker容器的原理。大數據

虛擬機是在宿主機上基於 Hypervisor 軟件虛擬出一套操做系統所需的硬件設備,再在這些虛擬硬件上安裝操做系統 Guest OS,而後不一樣的應用程序就能夠運行在不一樣的 Guest OS 上,應用之間也就相互獨立、資源隔離了,可是因爲須要 Hypervisor 來建立虛擬機,且每一個虛擬機裏須要完整的運行一套操做系統 Guest OS,所以這個方式會帶來不少額外資源的開銷。spa

而 Docker容器 中卻沒有 Hypervisor 這一層,雖然它須要在宿主機中運行 Docker Engine,但它的原理卻徹底不一樣於 Hypervisor,它並無虛擬出硬件設備,更沒有獨立部署全套的操做系統 Guest OS。操作系統

Docker容器沒有那麼複雜的實現原理,它其實就是一個普通進程而已,只不過它是一種通過特殊處理過的普通進程。

咱們啓動容器的時候(docker run …),Docker Engine 只不過是啓動了一個進程,這個進程就運行着咱們容器裏的應用。但 Docker Engine 對這個進程作了一些特殊處理,經過這些特殊處理以後,這個進程所看到的外部環境就再也不是宿主機的那個環境了(它看不到宿主機中的其它進程了,覺得本身是當前操做系統惟一一個進程),而且 Docker Engine 還對這個進程所使用得資源進行了限制,防止它對宿主機資源的無限使用。

那 Docker Engine 具體是作了哪些特殊處理纔有這麼神奇的效果呢?

2、容器是如何作到資源隔離和限制的?

Docker容器對這個進程的隔離主要採用2個技術點:

  • Namespace 技術

  • Cgroups 技術

弄清楚了這兩個技術點對理解容器的原理很是重要,它們是容器技術的核心。

下面來詳細解釋一下:

  1. Namespace 技術

    Namespace 並非一個什麼新技術,它是Linux操做系統默認提供的API,包括 PID Namespace、Mount Namespace、IPC Namespace、Network Namespace等等。

    以 PID Namespace 舉例,它的功能是可讓咱們在建立進程的時候,告訴Linux系統,咱們要建立的進程須要一個新的獨立的進程空間,而且這個進程在這個新的進程空間裏的PID=1,也就是說這個進程只看獲得這個新進程空間裏的東西,看不到外面宿主機環境裏的東西,也看不到其它進程(不過這只是一個虛擬空間,事實上這個進程在宿主機裏PID該是啥仍是啥,沒有變化,只不過在這個進程空間裏,該進程覺得本身的PID=1)。

    打個比方,就像是一個班級,每一個人在這個班裏都有一個編號,班裏有90人,而後來了一位新同窗,那他在班裏的編號就是91,但是老師爲了給這位同窗特別照顧,因此在班裏開闢了一塊獨立的看不到外面的小隔間,並告訴這個同窗他的編號是1,因爲這位同窗在這個小空間裏隔離着,因此他真的覺得本身就是班上的第一位同窗且編號爲1,固然了,事實上這位同窗在班上的編號依然是91。

    另外,Network Namespace 的技術原理也是相似的,讓這個進程只能看到當前Namespace空間裏的網絡設備,看不到宿主機真實狀況。同理,其它 Mount、IPC等 Namespace 也是這樣。

    Namespace 技術其實就是修改了應用進程的視覺範圍,但應用進程的本質卻沒有變化。

    不過,Docker容器裏雖然帶有一部分操做系統(文件系統相關),但它並無內核,所以多個容器之間是共用宿主機的操做系統內核的。這一點與虛擬機的原理是徹底不同的。

  2. Cgroups 技術

    Cgroup 全稱是 Control Group,其功能就是限制進程組所使用的最大資源(這些資源能夠是 CPU、內存、磁盤等等)。

    既然 Namespace 技術 只能改變一下進程組的視覺範圍,並不能真實的對資源作出限制。那麼爲了防止容器(進程)之間互相搶資源,甚至某個容器把宿主機資源所有用完致使其它容器也宕掉的狀況發生。所以,必須採用 Cgroup 技術對容器的資源進行限制。

    Cgroup 技術也是Linux默認提供的功能,在Linux系統的 /sys/fs/cgroup 下面有一些子目錄 cpu、memory等,Cgroup技術提供的功能就是能夠基於這些目錄實現對這些資源進行限制。

    例如:在 /sys/fs/cgroup/cpu 下面建立一個 dockerContainer 子目錄,系統就會自動在這個新建的目錄下面生成一些配置文件,這些配置文件就是用來控制資源使用量的。例如能夠在這些配置文件裏面設置某個進程ID對CPU的最大使用率。

    Cgroup 對其它內存、磁盤等資源也是採用一樣原理作限制。

3、容器的鏡像是什麼?

一個基礎的容器鏡像其實就是一個 rootfs,它包含操做系統的文件系統(文件和目錄),但並不包含操做系統的內核。

rootfs 是在容器里根目錄上掛載的一個全新的文件系統,此文件系統與宿主機的文件系統無關,是一個徹底獨立的,用於給容器進行提供環境的文件系統。

對於一個Docker容器而言,須要基於 pivot_root 指令,將容器內的系統根目錄切換到rootfs上,這樣,有了這個 rootfs,容器就可以爲進程構建出一個完整的文件系統,且實現了與宿主機的環境隔離,也正是有了rootfs,才能實現基於容器的本地應用與雲端應用運行環境的一致。

另外,爲了方便鏡像的複用,Docker 在鏡像中引入了層(Layer)的概念,能夠將不一樣的鏡像一層一層的迭在一塊兒。這樣,若是咱們要作一個新的鏡像,就能夠基於以前已經作好的某個鏡像的基礎上繼續作。

如上圖,這個例子中最底層是操做系統引導,往上一層就是基礎鏡像層(Linux的文件系統),再往上就是咱們須要的各類應用鏡像,Docker 會把這些鏡像聯合掛載在一個掛載點上,這些鏡像層都是隻讀的。只有最上面的容器層是可讀可寫的。

這種分層的方案實際上是基於 聯合文件系統UnionFS(Union File System)的技術實現的。它能夠將不一樣的目錄所有掛載在同一個目錄下。舉個例子,假若有文件夾 test1 和 test2 ,這兩個文件夾裏面的文件 有相同的,也有不一樣的。而後咱們能夠採用聯合掛載的方式,將這兩個文件夾掛載到 test3 上,那麼 test3 目錄裏就有了 test1 和 test2 的全部文件(相同的文件有去重,不一樣的文件都保留)。

這個原理應用在Docker鏡像中,好比有2個同窗,同窗A已經作好了一個基於Linux的Java環境的鏡像,同窗S想搭建一個Java Web環境,那麼他就沒必要再去作Java環境的鏡像了,能夠直接基於同窗A的鏡像在上面增長Tomcat後生成新鏡像便可。

以上,就是對微服務架構之「 容器技術 」的一些思考。

碼字不易啊,喜歡的話不妨轉發朋友,或點擊文章右下角的「在看」吧。😊

本文原創發佈於微信公衆號「 不止思考 」,歡迎關注。涉及 思惟認知、我的成長、架構、大數據、Web技術 等。 

相關文章
相關標籤/搜索