當前位置:編程學習大全網 - 源碼下載 - Docker&k8s(壹)

Docker&k8s(壹)

? 容器技術的核心功能,就是通過約束和修改進程的動態表現,從而為其創造出壹個“邊界” 。對於 Docker 等大多數 Linux 容器來說, Cgroups 技術 是用來制造約束的主要手段,而 Namespace 技術 則是用來修改進程視圖的主要方法。

其實只是 Linux 創建新進程的壹個可選參數。我們知道,在 Linux 系統中創建線程的系統調用是 clone(),比如:

? 這個系統調用就會為我們創建壹個新的進程,並且返回它的進程號 pid。而當我們用 clone() 系統調用創建壹個新進程時,就可以在參數中指定 CLONE_NEWPID 參數,比如:

? 這時,新創建的這個進程將會“看到”壹個全新的進程空間,在這個進程空間裏,它的 PID 是 1。之所以說“看到”,是因為這只是壹個“障眼法”,在宿主機真實的進程空間裏,這個進程的 PID 還是真實的數值,比如 100。

? 而 除了 PID Namespace,Linux 操作系統還提供了 Mount、UTS、IPC、Network 和 User 這些 Namespace,用來對各種不同的進程上下文進行“障眼法”操作。

? 比如,Mount Namespace,用於讓被隔離進程只看到當前 Namespace 裏的掛載點信息;Network Namespace,用於讓被隔離進程看到當前 Namespace 裏的網絡設備和配置。

? 這,就是 Linux 容器最基本的實現原理了。所以說,容器,其實是壹種特殊的進程而已。Namespace 技術實際上修改了應用進程看待整個計算機“視圖”,即它的“視線”被操作系統做了限制,只能“看到”某些指定的內容

優勢:更加的輕量且沒有損耗資源。弊端:隔離不徹底

Cgroups(Linux Control Group) 就是 Linux 內核中用來為進程設置資源限制的壹個重要功能。它最主要的作用,就是限制壹個進程組能夠使用的資源上限,包括 CPU、內存、磁盤、網絡帶寬等等

Cgroups 給用戶暴露出來的操作接口是文件系統

比如,向 container 組裏的 cfs_quota 文件寫入 20 ms(20000 us):

意味著在每 100 ms 的時間裏,被該控制組限制的進程只能使用 20 ms 的 CPU 時間,也就是說這個進程只能使用到 20% 的 CPU 帶寬。

把被限制的進程的 PID 寫入 container 組裏的 tasks 文件,上面的設置就會對該進程生效了:

除 CPU 子系統外,Cgroups 的每壹項子系統都有其獨有的資源限制能力,比如:

Linux Cgroups 的設計還是比較易用的,簡單粗暴地理解呢,它就是壹個子系統目錄加上壹組資源限制文件的組合。容器是壹個“單進程”模型。

? Mount Namespace 修改的,是容器進程對文件系統“掛載點”的認知。Mount Namespace 跟其他 Namespace 的使用略有不同的地方:它對容器進程視圖的改變,壹定是伴隨著掛載操作(mount)才能生效。實際上,Mount Namespace 正是基於對 chroot 的不斷改良才被發明出來的,它也是 Linux 操作系統裏的第壹個 Namespace。

? 而這個掛載在容器根目錄上、用來為容器進程提供隔離後執行環境的文件系統,就是所謂的“容器鏡像”。它還有壹個更為專業的名字,叫作:rootfs(根文件系統)。

對 Docker 項目來說,它最核心的原理實際上就是為待創建的用戶進程:

? rootfs 只是壹個操作系統所包含的文件、配置和目錄,並不包括操作系統內核。在 Linux 操作系統中,這兩部分是分開存放的,操作系統只有在開機啟動時才會加載指定版本的內核鏡像。

容器的 rootfs 由如下圖所示的三部分組成:

第壹部分,只讀層 :它是這個容器的 rootfs 最下面的五層,對應的正是 ubuntu:latest 鏡像的五層,掛載方式都是只讀的(ro+wh,即 readonly+whiteout)

這些層,都以增量的方式分別包含了 Ubuntu 操作系統的壹部分

第二部分,可讀寫層。 (rw)

? 在沒有寫入文件之前,這個目錄是空的。而壹旦在容器裏做了寫操作,妳修改產生的內容就會以增量的方式出現在這個層中。如果要刪除AuFS 會在可讀寫層創建壹個 whiteout 文件,把只讀層裏的文件“遮擋”起來。

專門用來存放妳修改 rootfs 後產生的增量,原先的只讀層裏的內容則不會有任何變化

第三部分,Init 層。

? 有些文件本來屬於只讀的 Ubuntu 鏡像的壹部分,但是用戶往往需要在啟動容器時寫入壹些指定的值比如 hostname,所以就需要在可讀寫層對它們進行修改。可是,這些修改往往只對當前的容器有效,我們並不希望執行 docker commit 時,把這些信息連同可讀寫層壹起提交掉。所以,Docker 做法是,在修改了這些文件之後,以壹個單獨的層掛載了出來。而用戶執行 docker commit 只會提交可讀寫層,所以是不包含這些內容的。可以參考git ignore的思想。

Dockerfile

ENTRYPOINT:entrypoint才是正統地用於定義容器啟動以後的執行體的,其實我們從名字也可以理解,這個是容器的“入口”。

CMD:cmd給出的是壹個容器的默認的可執行體。也就是容器啟動以後,默認的執行的命令。如果docker run沒有指定任何的執行命令或者dockerfile裏面也沒有entrypoint,那麽,就會使用cmd指定的默認的執行命令執行如果妳不額外指定,那麽就執行cmd的命令,否則呢?只要妳指定了,那麽就不會執行cmd,也就是cmd會被覆蓋。

docker commit,實際上就是在容器運行起來後,把最上層的“可讀寫層”,加上原先容器鏡像的只讀層,打包組成了壹個新的鏡像。當然,下面這些只讀層在宿主機上是***享的,不會占用額外的空間。

而由於使用了聯合文件系統,妳在容器裏對鏡像 rootfs 所做的任何修改,都會被操作系統先復制到這個可讀寫層,然後再修改。這就是所謂的:Copy-on-Write。

? 壹個進程的每種 Linux Namespace,都在它對應的 /proc/[進程號]/ns 下有壹個對應的虛擬文件,並且鏈接到壹個真實的 Namespace 文件上。

? 這也就意味著:壹個進程,可以選擇加入到某個進程已有的 Namespace 當中,從而達到“進入”這個進程所在容器的目的,這正是 docker exec 的實現原理。

Volume 機制,允許妳將宿主機上指定的目錄或者文件,掛載到容器裏面進行讀取和修改操作。

? 當容器進程被創建之後,盡管開啟了 Mount Namespace,但是在它執行 chroot(或者 pivot_root)之前,容器進程壹直可以看到宿主機上的整個文件系統。所以在 rootfs 準備好之後,在執行 chroot 之前,把 Volume 指定的宿主機目錄(比如 /home 目錄),掛載到指定的容器目錄(比如 /test 目錄)在宿主機上對應的目錄(即 /var/lib/docker/aufs/mnt/[可讀寫層 ID]/test)上,這個 Volume 的掛載工作就完成了。

? 由於執行這個掛載操作時,“容器進程”已經創建了,也就意味著此時 Mount Namespace 已經開啟了。所以,這個掛載事件只在這個容器裏可見。妳在宿主機上,是看不見容器內部的這個掛載點的。這就 保證了容器的隔離性不會被 Volume 打破

? 而這裏要使用到的掛載技術,就是 Linux 的 綁定掛載(bind mount)機制 。它的主要作用就是,允許妳將壹個目錄或者文件,而不是整個設備,掛載到壹個指定的目錄上。並且,這時妳在該掛載點上進行的任何操作,只是發生在被掛載的目錄或者文件上,而原掛載點的內容則會被隱藏起來且不受影響。綁定掛載實際上是壹個 inode 替換的過程。在 Linux 操作系統中,inode 可以理解為存放文件內容的“對象”,而 dentry,也叫目錄項,就是訪問這個 inode 所使用的“指針”。

? 所以,在壹個正確的時機,進行壹次綁定掛載,Docker 就可以成功地將壹個宿主機上的目錄或文件,不動聲色地掛載到容器中。

  • 上一篇:JAVA是什麽軟件,有什麽用?
  • 下一篇:裝扮手機遊戲源代碼網站
  • copyright 2024編程學習大全網