認識大明星——輕量級容器docker知識樹點亮
docker是一個輕量級容器,屬於操作系統層面的虛擬化技術,封裝了文件系統(AUFS)以及網絡互聯,進程隔離等特性。
傳統虛擬化架構:
docker虛擬化架構:
可以看出,docker是沒有Guest OS一層的,它屬於宿主機上面開啟的一個單獨進程,共享宿主機的內核和硬件。 傳統虛擬化技術每個實例都要虛擬出一套OS的硬件支持,當一臺宿主機開啟多個虛擬機的時候,這些硬件虛擬無疑是重復的,且占用了大量宿主機的資源。 因此,docker這種輕量級的容器技術會更高效地使用宿主機的內核和硬件資源。同時由於沒有完整OS的啟動,docker的啟動也非常快,就像你在win10裏面開啟一個瀏覽器一樣,可以類比出,docker的級別與OS上面的application是一層的。
docker庫的架構: docker registry -> docker repository -> docker image docker
registry相當於一個郵輪,repository是郵輪上的集裝箱,image是集裝箱內部的系統鏡像。
docker的最小單元為image,docker image是只讀的,不支持修改,因此當你看上去修改了一個docker image,哪怕是只改了它的名字,docker的真實實現是復制出來一份列在下面,而原來的仍舊被保留。同時為便於文件管理,docker image 可以通過命令被export為tar包,也可以import tar包成為本地的image。
註意:docker只是提供了一個環境,這個概念是獨特的,其他虛擬機是一個完全隔離開的封閉的就像一個完整的物理機那樣,而docker的用戶獲得的是一個基於通用OS上面的一個相同的環境,只要使用相同的image,docker能運行起來,那麽環境就是一致的。docker不限制OS的種類、版本,現在docker已經可以支持幾乎所有流行的OS,這就使docker變成了跨平臺技術,避免了用戶環境變化導致的Bug。
docker container 是 docker image 的實例化。
docker提供的這個環境,可以達到如一個純凈OS一樣對其進行具體的操作,如安裝新的包,文件變更等。上面提到的docker的image是只讀,不支持修改image本身,那麽這個環境變更真的不是對image進行操作嗎?
答:確實不是的,docker的文件系統是AUFS,當我們對image進行修改的時候,表面上是進入那個container,然後做安裝命令,文件變更等修改,其實這些變更並不是發生在像傳統虛擬系統那樣在容器內部,而是在外部!docker container並不是一個封閉獨立的空間。
這些變更是存在於本地文件路徑/var/lib/docker/aufs/中,每次與原image不同的修改都會放在本地的這個目錄中。然而docker也提供了修改這個默認目錄的方式,就是在啟動容器的時候,使用-v參數設置這個本地目錄的映射,每一次修改都是針對映射的這個本地目錄,但是要註意以後的每次啟動都要帶著這個-v參數和這個本地目錄,否則又指向了默認的目錄相當於啟動一個新的container了。
我們來深究一下上面的操作,進入docker container以後,會發現終端的用戶名和主機名,包括該用戶的root目錄([email protected]:~/)都與進入之前不同了,這就是linux的change root命令的效果,利用chroot命令將當前目錄映射為該用戶的root目錄。當exit的時候,恢復到真正的用戶root目錄,對應的container也被退了出來。
如果想提交這個最新的變更後的環境,實際也是提交一個本地的image,通常是使用commit和dockerfile的方式,而commit方式每次都要提交具體的變更細節,深入docker的實現原理,它是將每次的commit的差異文件存在AUFS文件系統的diff文件夾中,這就很麻煩,因為每次部署環境的時候,如果要檢查其中某次提交的文件變更,就要捋順一遍這個commit列表,這實在是不方便。因此dockerfile的方式被廣泛應用。dockerfile會記錄以初始的基礎image為原點的每次對環境的變更,例如安裝了某個新的命令,它像一個描述文件,每當以dockerfile啟動的時候,它會先啟動其依賴的基礎image,然後在按照dockerfile中的命令順序一條條去執行,最終會獲得一個變更後的環境。這樣,部署人員只需要維護dockerfile中的代碼即可。所有docker的用戶僅需要本地擁有一個基礎image,然後按照業務需要去get相應的dockerfile,啟動的時候就會獲得最新的環境,與同組其他同事獲得的也會保持一致。
總結一下,docker是如此輕巧靈活僅相當於一個普通app開啟一個宿主機的進程,image是只讀,dockerfile用來描述變更,container修改映射到本地卷。
補充:
上面多次提到了docker的aufs文件系統,它非常強大,對應的路徑是在/var/lib/docker/aufs,它可以分塊Blob的去存儲一個image,這個image是只讀的,所以分塊存儲可以更快地讀取。如果不做-v修改本地映射卷的話,它還可以存儲用戶在container中修改的變更文件。它還可以存儲commit時與基礎image的差異文件。提到分塊存儲image的特性,就要說一下linux的mount,它可以將兩個具體路徑映射成一個目錄,合並包含兩個具體路徑下的內部文件。例如,mount -t aufs -o dirs="/tmp/a;/tmp/b" none /mnt。執行以後,原/tmp/a和/tmp/b中的內容都會出現在/mnt中。
在docker run一個image的時候,如果不加任何參數,則默認是在docker-hub(https://hub.docker.com/)去下載,這就如同maven,有一個public registry。同樣的,如果我想給team建立一個局域網的“郵輪”,提高傳輸(上傳下載,push和pull)的效率,就要自己創建一個registry服務端。 registry創建也非常簡單,registry服務本身在docker hub中仍舊是以一個image的形式存在的,所以直接在服務器上docker run registry就ok了。 客戶端container可以指定服務端的IP端口去pull image,也可以將本地的image tag成服務端的IP端口下的image,然後push到服務端去。
認識大明星——輕量級容器docker知識樹點亮