天天看點

Docker容器實戰(六) - Docker是如何實作隔離的?(上)1 Namespace

1 Namespace

1.1 容器為何需要程序隔離

  • 被其他容器修改檔案,導緻安全問題
  • 資源的并發寫入導緻不一緻性
  • 資源的搶占,導緻其他容器被影響
docker run -it --name demo_docker busybox /bin/sh
/ # ps -ef      
Docker容器實戰(六) - Docker是如何實作隔離的?(上)1 Namespace

在主控端檢視程序ID

ps -ef|grep busybox      

真實的 docker 容器 pid

Docker容器實戰(六) - Docker是如何實作隔離的?(上)1 Namespace

這就是程序資源隔離表象:

  • 對于主控端

    docker run

    啟動的隻是一個程序,它的pid是44451
  • 而容器程式本身被隔離了,容器的内部都隻能看到自己内部的程序
  • 這其實是基于Linux的Namespace技術(即使是 Windows 版本的 Docker 也是依托于 Windows 實作的類似Namespace的技術)

1.2 Linux Namespace

Linux 命名空間對全局作業系統資源進行了抽象,對于命名空間内的程序來說,他們擁有獨立的資源執行個體,在命名空間内部的程序可以實作資源可見。

對于命名空間外部的程序,則不可見,實作了資源的隔離。這種技術廣泛的應用于容器技術裡。

Namespace實際上修改了應用程序看待整個計算機“視圖”,即它的“視線”被作業系統做了限制,隻能“看到”某些指定的内容。對于主控端來說,這些被“隔離”了的程序跟其他程序并沒有差別。

1.3 Docker Engine 使用了如下 Linux 的隔離技術

  • The pid namespace:管理 PID namespace (PID: Process ID)
  • The net namespace: 管理網絡namespace(NET: Networking)
  • The ipc namespace: 管理程序間通信命名空間(IPC: InterProcess Communication)
  • The mnt namespace:管理檔案系統挂載點命名空間(MNT: Mount).
  • The uts namespace: Unix 時間系統隔離(UTS: Unix Timesharing

    System).

1.4 程序資源隔離原理

Linux Namespaces是Linux建立新程序時的一個可選參數,在Linux系統中建立程序的系統調用是clone()方法。

int clone(int (*fn) (void *),void *child stack,
int flags, void *arg, . . .
/* pid_ t *ptid, void *newtls, pid_ t *ctid */ ) ;
      

通過調用該方法,這個程序會獲得一個獨立的程序空間,它的pid是1 ,并且看不到主控端上的其他程序,也就是在容器内執行PS指令的結果。

不應該把Docker Engine或者任何容器管理工具放在跟Hypervisor相同的位置,因為它們并不像Hypervisor那樣對應用程序的隔離環境負責,也不會建立任何實體的“容器”,真正對隔離環境負責的是主控端os:

Docker容器實戰(六) - Docker是如何實作隔離的?(上)1 Namespace
Docker容器實戰(六) - Docker是如何實作隔離的?(上)1 Namespace

該對比圖應該把Docker畫在跟應用同級别并且靠邊的位置。

使用者運作在容器裡的應用程序,跟主控端上的其他程序一樣,都由主控端作業系統統一管理,隻不過這些被隔離的程序擁有額外設定過的Namespace參數,Docker在這裡更多的是輔助和管理工作。

這也解釋了

為何Docker項目比虛拟機更好?

使用虛拟化技術作為應用沙盒,就必須由Hypervisor負責建立虛拟機,這個虛拟機是真實存在的,它裡面必須運作一個完整的Guest OS才能執行使用者的應用程序。這就不可避免地帶來額外的資源消耗和占用。

據實驗,一個運作着CentOS的KVM虛拟機啟動後,在不做優化的情況下,虛拟機自己就需要占用100~200 MB記憶體。此外,使用者應用運作在虛拟機裡面,它對主控端作業系統的調用就不可避免地要經過虛拟化軟體的攔截和處理,這本身又是一層性能損耗,尤其對計算資源、網絡和磁盤I/O的損耗非常大。

而容器化後的使用者應用,依然還是主控端上的一個普通程序,這就意味着這些因為虛拟化而帶來的性能損耗都不存在。

使用Namespace作為隔離手段的容器無需單獨的Guest OS,使得容器額外的資源占用可忽略不計。

“靈活”和“高性能”是容器相較于虛拟機最大的優勢。

有利必有弊,基于 Namespace 的隔離機制相比虛拟化技術也有很多不足。

1.5 Namespace的缺點

隔離不徹底

多容器間使用的還是同一主控端os核心

盡管可在容器裡通過 Mount Namespace 單獨挂載其他不同版本的os檔案,比如 CentOS 或者 Ubuntu,但這并不能改變共享主控端核心的事實!

是以不可能在Windows主控端運作Linux容器或在低版本Linux主控端運作高版本Linux容器。

而擁有硬體虛拟化技術和獨立Guest OS的虛拟機,比如Microsoft的雲計算平台Azure,就是運作于Windows伺服器叢集,但可在其上面建立各種Linux虛拟機。

Linux核心很多資源無法被Namespace

最典型的比如時間。

若你的容器中的程式使用settimeofday(2)系統調用修改時間,整個主控端的時間都會被随之修改,這并不符合使用者預期。

而相比于在虛拟機裡可自己随便折騰,在容器裡部署應用時,“什麼能做,什麼不能做”,使用者都必須考慮。

尤其是共享主控端核心:

容器給應用暴露出來的攻擊面是相當大的

應用“越獄”難度也比虛拟機低得多。

盡管可使用Seccomp等技術,過濾和甄别容器内部發起的所有系統調用來進行安全加強,但這就多了一層對系統調用的過濾,一定會拖累容器性能。預設情況下,也不知道到底該開啟哪些系統調用,禁止哪些系統調用。

是以,在生産環境中,無人敢把運作在實體機上的Linux容器直接暴露至公網。

基于虛拟化或者獨立核心技術的容器實作,則可以比較好地在隔離與性能之間做出平衡。

繼續閱讀