容器技術和虛擬機器技術的對比

jiayou111發表於2024-08-24

目錄
  • 容器和虛擬機器的對比
    • 遷移性和效能
    • 隔離性
    • 資源限制
  • 解決的問題
    • 1.容器是如何進行隔離的?
    • 2.容器是如何進行資源限制的?
    • 3.簡述下 docker 的檔案系統?
    • 4.容器的啟動過程?
    • 5.容器內執行多個應用的問題?

容器和虛擬機器的對比

下面這張圖是 docker 官方中擷取下來的,我們來分析下 docker 和 傳統 VM 的區別:

遷移性和效能

傳統 VM: 需要基於 Hypervisor 的硬體虛擬化技術,模擬出 CPU,記憶體等硬體。然後在其上搭建一套完整的作業系統,自然在效能上會有很大的損失。遷移自然更不用說,傳統的 ova 匯出後就是一個完整的作業系統。
Docker:Docker 將 Hypervisor 的位置換成自己的 Docker Engine,然後執行的容器僅僅是一個特殊的程序,自然效能不會有太大的損失。並且可以應用和其所需要的系統檔案打包成映象,無論在哪讀可以正常執行,而且相對於 ova 來說體積也小了更多。(需要核心支援)

一般來說,執行著 CentOS 的 KVM,啟動後,在不做最佳化的前提下,需要佔用 100~200M 記憶體。在加上使用者對宿主機的呼叫,需要透過虛擬化軟體攔截和處理,又是一層效能損耗,特別是對計算資源,網路和磁碟I/O等。

隔離性

傳統 VM:由於是虛擬化出一套完整的作業系統,所以隔離性非常好。比如微軟的 Azure 平臺,就是在 Windows 伺服器上,虛擬出大量的 Linux 虛擬機器。
Docker:在隔離性上相差就很多了,因為本身上容器就是一種程序,而所有的程序都需要共享一個系統核心。

  • 這就意味著,在 Windows 上執行 Linux 容器,或者 Linux 宿主機執行高版本核心的容器就無法實現。
  • 在 Linux 核心中,有許多資源和物件不能 Namespace 化,如時間,比如透過settimeofday(2) 系統呼叫修改時間,整個宿主機的實際都會被修改。
  • 安全的問題,共享宿主機核心的事實,容器暴露出的攻擊面更大。

資源限制

傳統 VM:非常便於管理,控制資源的使用,依賴於虛擬的作業系統。
Docker:由於 docker 內資源的限制透過 Cgroup 實現,而 Cgroup 有很多不完善的地方,比如

  • 對 /proc 的處理問題。進入容器後,執行 top 命令,看到的資訊和宿主機是一樣的,而不是配置後的容器的資料。(可以透過 lxcfs 修正)。
  • 在執行 java 程式時,給容器內設定的記憶體為 4g,使用預設的 jvm 配置。而預設的 jvm 讀取的記憶體是宿主機(可能大於 4g),這樣就會出現 OOM 的情況。

解決的問題

1.容器是如何進行隔離的?

在建立新程序時,透過 Namespace 技術,如 PID namespaces 等,實現隔離性。讓執行後的容器僅能看到本身的內容。
比如,在容器執行時,會預設加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace。

2.容器是如何進行資源限制的?

透過 Linux Cgroup 技術,可為每個程序設定限制的 CPU,Memory 等資源,進而設定程序訪問資源的上限。

3.簡述下 docker 的檔案系統?

docker 的檔案系統稱為 rootfs,它的實現的想法來自與 Linux unionFS 。將不同的目錄,掛載到一起,形成一個獨立的檢視。並且 docker 在此基礎上引入了層的概念,解決了可重用性的問題。
在具體實現上,rootfs 的儲存區分根據 linux 核心和 docker 本身的版本,分為 overlay2 , overlay, aufs, devicemapper 等。rootfs(映象)其實就是多個層的疊加,當多層存在相同的檔案時,上層的檔案會將下層的檔案覆蓋掉。

4.容器的啟動過程?

1.指定 Linux Namespace 配置
2.設定指定的 Cgroups 引數
3.切換程序的根目錄

5.容器內執行多個應用的問題?

首先更正一個概念,我們都說容器是一個單程序的應用,其實這裡的單程序不是指在容器中只允許著一個程序,而是指只有一個程序是可控的。在容器內當然可以使用 ping,ssh 等程序,但這些程序是不受 docker 控制的。
容器內的主程序,也就是 pid =1 的程序,一般是透過 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一個容器內如果存在著多個服務(程序),就可能出現主程序正常執行,但是子程序退出掛掉的問題,而對於 docker 來說,僅僅控制主程序,無法對這種意外的情況作出處理,也就會出現,容器明明正常執行,但是服務已經掛掉的情況,這時編排系統就變得非常困難。而且多個服務,在也不容易進行排障和管理。
所以如果真的想要在容器內執行多個服務,一般會透過帶有systemd或者supervisord這類工具進行管理,或者透過--init方法。其實這些方法的本質就是讓多個服務的程序擁有同一個父程序。
但考慮到容器本身的設計,就是希望容器和服務能夠同生命週期。所以這樣做,有點背道而馳的意味。

相關文章