虛擬機器已死,容器才是未來?

乖乖之家發表於2016-05-10

  我也曾經是容器技術尤其是 Docker 粉絲,但用了一年後覺得事情也沒那麼美好,而頗有一些同學以及一些公司依然認為容器就是銀彈,虛擬機器已經是昨兒黃花必須打倒,大家趕緊一切皆容器。這裡我對這種觀點吐吐槽。僅代表作者個人看法

  首先要明確的是,軟體開發和運維活動中,可維護性、正確性、效能的優先順序是依次降低的,不要跟我抬槓少數極端情況。關於可維護性和正確性的先後,著 名的 "worse is better" 文章就是很好的無奈的解釋,如果你猶豫這兩者,這還情有可原,畢竟真善美和糙快猛的鬥爭從未停歇,而你如果第一反應覺得效能是最重要的,那就不要繼續往下 看了,洗洗去睡吧——適合的才是最好的。

  那麼對於虛擬機器 vs 容器,自然我們也需要從這三方面考察。

vm vs docker

  回合一:可維護性之爭

  虛擬機器—維護性

  從 hypervisor 講,Xen/KVM/vSphere/HyperV 都很成熟了,久經考驗,BSD 也在湊熱鬧搞 bhyve(FreeBSD) 和 vmm(OpenBSD),最近 unikernel 也在試圖跑在 hypervisor 上,而 AWS/GCE/Azure 等等雲端計算巨頭以及 Intel/AMD 等在CPU、磁碟和網路IO虛擬化技術上的投資顯然不會立馬推翻,Linux 上虛擬機器的開源管理方案也已成熟定型:libvirt, OpenStack, 沒人吃飽了撐的去弄個 “新的開源” 專案替換它們,雖然我很不喜歡 OpenStack 的亂糟和複雜。VM 的動態遷移也是成熟技術,出來好多年了,實現原理非常簡單,反正整個 OS 記憶體一鍋端弄過去,不操心少個依賴程式的記憶體沒過去。想用不同版本核心? 想要自定義核心模組?想調整核心引數?期望更安全的隔離?期望如同物理機版幾乎一致的使用體驗?VM 就是虛擬機器的縮寫嘛,這些都是拿手戲。

  容器— 維護性

  Linux 容器,Linux 一貫的作風,慢慢演化,不求仔細設計,然後就是 cgroup, pid/uts/ipc/net/uid namespace 一個個實現出來,湊出一個容器技術,貌似 uid namespace 還是最近剛剛出來的特性。使用者空間則更是群雄並起,LXC,Docker,rkt,LXD,各有擁蹇,鹿死誰手,還真不好說,在這個局還沒明朗的時 候,Mesos、Swarm、Kubernetes、Nomad 又出來一堆攪局的,眼下看來最吸引眼球的 Kubernetes 儼然有 OpenStack 繼任者的感覺,但依然很嫩,沒幾個人敢在生產環境大規模使用。

  Linux容器裡程式的跨機器動態遷移我還沒聽說,不要說是個服務就得有叢集有 HA 嘛,可還真有不少使用者一個服務就單機頂著呢,就算有熱備或者冷備,線上那臺機器記憶體裡的東西可寶貴了,輕易不能丟。用Linux容器就不能挑核心,不能加 載核心模組,不能掛載檔案系統,不能調整核心引數,不能改網路配置,等等,不要告訴我你能——你是不是開了 docker run --privileged 了? 你是不是沒 drop capability?你是不是沒有 remap uid?話說某大公司的容器還真就用 --privileged 選項跑的呢。 而 Linux 的隔離不徹底恐怕大部分人都沒意識到,/sys, /dev, /selinux 還有 /proc 下的某些關鍵檔案比如 /proc/kcore 沒隔離呢。

  Redhat 做的 project Atomic 意識到這些問題,正在積極的給 Docker 加 SELinux 支援,指定 SELinux policy,但 Docker 官方愛搭不理,而且 SELinux 這種高階技術是凡人玩的麼? 結局大概依然是 "FAQ 1: 關掉 SELinux"。Linux 容器本來並不侷限在一個容器裡跑幾個程式,但 Docker 官方為了加強“輕量級”這詞的洗腦效果,搞出個無比腦殘的 single process 理念,被無數人捧臭腳,所幸有些人慢慢意識到問題,Yelp 搞了個 dumb-init 擦了一半屁股,還有無數 docker image 用 runit、supervisor 之類的做 /sbin/init 替換,但問題在於這要自定義啟動指令碼,需要加 ssh/cron/syslog/logrotate 等等邊角料——這已然是解決了無數遍的問題,還要解決一遍,不覺得麻煩嗎?難道沒有人認為這些包的作者或者打包者更善於處理服務啟動指令碼麼?像 systemd 那種搞法還算正道,特意考慮容器環境,跳過一些步驟,但貌似還沒做完善,需要手動刪除一些 .service 檔案。

  虛擬機器 vs 容器

  也許有人會說 docker pull/push 多方便啊,docker build 多方便啊,可不要忘了,vm image storage 早在 openstack 裡就解決了,自己處理也不是個大事,vm image build 也有 Hashicorp 的 Packer 工具代勞,不是個事。Docker 自豪的官方 docker registry 其實大家最多用用 base os image,那些 app 級別的出於信任以及定製考慮都會自己 build。而 Docker 自豪的 layered storage 也是無數血淚,aufs & overlayfs 坑了多少人?容器社群最近還特崇拜 immutable deployment,以把容器根檔案系統弄做只讀的為榮,全然不管有緊急安全更新或者功能修正怎麼處理——什麼,你要說 docker rm && docker run 再起一批不就完事麼?真有這麼簡單就好了。

  像 Linux kernel 和 git 那種才是正經 unix 設計的思想,分層堆疊,底層提供mechanism,高層提供 policy,各取所需,可惜人總是易於被洗腦,在接受各種高大上policy的時候全然忘了mechanism還在不在自己手裡。

  回合二:正確性之爭

  強隔離、full OS 體驗、保留 mechanism,這才是正道。另外容器還隱藏了一個坑,/proc/cpuinfo和free命令輸出是host os的,這坑了無數探測系統資源自動決定預設執行緒池和記憶體池大小的程式,尤以Java最為普遍。

  回合三:效能之爭

  容器粉絲津津樂道——啟動容器快,容器的開銷少。 這兩點確實如此但好處真的有那麼巨大麼?誰有事沒事不停建立虛擬機器?誰的虛擬機器生命週期平均在分鐘級別?誰的“用完全啟動時間”平均在秒級? 至於說到虛擬機器浪費的資源太多,其實也就是個障眼法。理論上伺服器的資源利用率平均不應該超過 80%而實際上絕大部分公司的伺服器資源利用率應該都不到 50%,大量的CPU、記憶體、本地磁碟都是常年浪費的,所以 VM 的額外開銷不過是浪費了原本就在浪費的資源罷了。就單機的巔峰 I/O 能力來言,VM 確實不敵容器。但平時根本就用不到巔峰狀態, 原本一個 VM 裡多程式乾的事,非得搞多個容器跑,這容器開銷,這人力開銷怎麼算?

  關於容器還有一個幻想,那就是可以在物理機上直接跑容器,開銷巨低、管理巨方便,用專用物理機方式提供多租戶強隔離。前面兩點上面已經駁過了,話說 還有人用 openstack 管理 docker 容器呢。 我只是說一下第三點,在一臺物理機上直接跑容器的一個最容易被忽視的問題:現在用來提供雲服務的物理機一般都是硬體超級牛逼,跑上百個容器都沒問題,但問 題在於使用者很可能只需要幾個容器,所以要麼跟人共用物理機,要麼浪費資源白交錢。哪怕使用者需要上百個容器,出於容災考慮,也不可以把上百容器部署到一臺物 理機上,所以還是要麼跟人共用物理機,要麼浪費資源。

  方案

  以上是我的觀點,我並不是“容器黑”,而是“實用白”。AWS、Azure、GCE 都主推在虛擬機器上跑容器,按虛擬機器收費,這非常明智的解決了問題:老的純 VM 基礎設施不用動,計費照舊,單物理機可以被安全的多租戶共用,資源隔離有保證(起碼比共享核心強多了),把容器管理軟體如“kubernetes”給用 戶,既滿足使用者的容器需求,又不擔心容器的多租戶問題。

  所以我認為:以 VM 為基礎,以容器為輔助點,要買就買 VM,自己管理容器,別買 CAAS 直接提供的容器,別看不到底下物理機或者虛擬機器。用 VM 還是用容器,冷靜考察自己的應用上容器是否有好處。最後,殘念,VM 開源管理軟體能搞個比 OpenStack 簡單的東西嗎?

相關文章