容器的六大理解誤區

PaaS小魔仙發表於2018-06-28

誤區一:容器啟動速度快,秒級啟動


這是很多人佈道容器的時候經常說的一句話,往往人們會啟動一個 Nginx 之類的應用,的確很快就能夠啟動起來了。


容器為啥啟動快,一是沒有核心,二是映象比較小。


然而容器是有主程式的,也即 Entrypoint,只有主程式完全啟動起來了,容器才算真正的啟動起來。


用一個比喻:容器更像人的衣服,人站起來了,衣服才站起來,人躺下了,衣服也躺下了。衣服有一定的隔離性,但是隔離性沒那麼好。衣服沒有根(核心),但是衣服可以隨著人到處走。


所以按照一個 Nginx 來評判一個容器的啟動速度有意義麼?對於 Java 應用,裡面安裝的是 Tomcat,而 Tomcat 的啟動,載入 War,並且真正的應用啟動起來。


如果你盯著 Tomcat 的日誌看的話,還是需要一些時間的,根本不是秒級;如果應用啟動起來要一兩分鐘,僅僅談容器的秒級啟動是沒有意義的。


現在 OpenStack 中 VM 的啟動速度也最佳化的越來越快了,啟動一個 VM 的時候,原來需要從 Glance 下載虛擬機器映象。


後來有了一個技術,是在 Glance 和系統盤共享 Ceph 儲存的情況下,虛擬機器映象無需下載,啟動速度就快很多。


而且容器之所以啟動速度快,往往建議使用一個非常小的映象,例如 alpine,裡面很多東西都裁剪掉了,啟動的速度就更快了。


OpenStack 的虛擬機器映象也可以經過大量的裁剪,實現快速的啟動。


我們可以精細的衡量虛擬機器啟動的每一個步驟,裁剪掉相應的模組和啟動的過程,大大降低虛擬機器的啟動時間。


例如在 UnitedStack 的一篇部落格裡面 https://www.ustack.com/blog/build-block-storage-service,我們可以看到這樣的實現和描述:


使用原生的 OpenStack 建立虛擬機器需要 1~3 分鐘,而使用改造後的 OpenStack 僅需要不到 10 秒鐘時間。


這是因為 nova-compute 不再需要透過 HTTP 下載整個映象,虛擬機器可以透過直接讀取 Ceph 中的映象資料進行啟動。


所以對於虛擬機器的整體啟動時間,現在最佳化的不錯的情況下,一般能夠做到十幾秒到半分鐘以內。


這個時間和 Tomcat 的啟動時間相比較,其實不算是負擔,和容器的啟動速度相比,沒有質的差別,可能有人會說啟動速度快一點也是快。


尤其是對於線上環境的掛掉自修復來講,不是分秒必爭麼?關於自修復的問題,我們下面另外說。


然而虛擬機器有一個好處,就是隔離性好,如果容器是衣服,虛擬機器就是房子,房子立在那裡,裡面的人無論站著還是躺著,房子總是站著的,房子也不會跟著人走。


使用虛擬機器就像人們住在公寓裡面一樣,每人一間,互不干擾,使用容器像大家穿著衣服擠在公交車裡面,看似隔離,誰把公交弄壞了,誰都走不了。


綜上所述,容器的啟動速度不足以構成對 OpenStack 虛擬機器的明顯優勢,然而虛擬機器的隔離性,則秒殺容器。


誤區二:容器輕量級,每個主機會執行成百上千個容器


很多人會做實驗,甚至會跟客戶說,容器平臺多麼多麼牛,你看我們一臺機器上可以執行成百上千個容器,虛擬機器根本做不到這一點。


但是一個機器執行成百上千個容器,有這種真實的應用場景麼?對於容器來講,重要的是裡面的應用,應用的核心在於穩定性和高併發支撐,而不在於密度。


我在很多演講的會議上遇到了很多知名的處理雙十一和 618 的講師,普遍反饋當前的 Java 應用基本上 4 核 8G 是標配,如果遇見容量不足的情況,少部分透過縱向擴容的方式進行,大部分採用橫向擴容的方式進行。


如果 4 核 8G 是標配,不到 20 個服務就可以佔滿一臺物理伺服器,一臺機器跑成百上千個 Nginx 有意思麼? 這不是一個嚴肅的使用場景。


當然現在有一個很火的 Serverless 無服務架構,在無伺服器架構中,所有自定義程式碼作為孤立的、獨立的、常常細粒度的函式來編寫和執行,這些函式在例如 AWS Lambda 之類的無狀態計算服務中執行。


這些計算服務可以是虛擬機器,也可以是容器。對於無狀態的函式來講,需要快速的建立可刪除,而且很可能執行一個函式的時間本身就非常短,在這種情況下容器相比於虛擬機器還是有一定優勢的。


目前無服務架構比較適用於執行一些任務型批次操作,利用程式級別的橫向彈效能力來抵消程式建立和銷燬帶來的較大的代價。


在 Spark 和 Mesos 的整合中,有一個 Fine-Grained 模式,在大資料的執行時候,任務的執行程式早就申請好了資源,與等在那裡分配資源不同,這種模式是當任務分配到的時候才分配資源。


好處就是對於資源的彈性申請和釋放的能力,壞處是程式的建立和銷燬還是粒度太大,所以這種模式下 Spark 執行的效能會差一些。



Spark 的這種做法思想類似無服務架構,你會發現我們原來學作業系統的時候,說程式粒度太大,每次都建立和銷燬程式會速度太慢。


為了高併發,後來有了執行緒,執行緒的建立和銷燬輕量級的多,當然還是覺得慢,於是有了執行緒池,事先建立在了那裡,用的時候不用現建立,不用的時候交回去就行。


後來還是覺得慢,因為執行緒的建立也需要在核心中完成,所以後來有了協程,全部在使用者態進行執行緒切換。


例如 AKKA,Go 都使用了協程,你會發現趨勢是為了高併發,粒度是越來越細的,現在很多情況又需要程式級別的,有種風水輪流轉的感覺。


誤區三:容器有映象,可以保持版本號,可以升級和回滾


容器有兩個特性,一個是封裝,一個是標準。有了容器映象,就可以將應用的各種配置,檔案路徑,許可權封裝起來,然後像孫悟空說“定”,就定在了封裝好的那一刻。


映象是標準的,無論在哪個容器執行環境,將同樣的映象執行起來,都能還原當時的那一刻。


容器的映象還有版本號,我們可以根據容器的版本號進行升級,一旦升級有錯,可以根據版本號進行回滾,回滾完畢則能夠保證容器內部還是原來的狀態。


但是 OpenStack 虛擬機器也是有映象的,虛擬機器映象也是可以打 snapshot 的,打 snapshot 的時候,也會儲存當時的那一刻所有的狀態,而且 snapshot 也可以有版本號,也可以升級和回滾。



似乎容器有的這些特性 OpenStack 虛擬機器都有,二者有什麼不同呢?


虛擬機器映象大,而容器映象小。虛擬機器映象動不動就幾十個 G 甚至上百 G,而容器映象多幾百 M。


虛擬機器映象不適合跨環境遷移。例如開發環境在本地,測試環境在一個 OpenStack 上,開發環境在另一個 OpenStack 上,虛擬機器的映象的遷移非常困難,需要複製非常大的檔案。


而容器就好的多,因為映象小,可以很快的從不同的環境之間遷移。


虛擬機器映象不適合跨雲遷移。當前沒有一個公有云平臺支援虛擬機器映象的下載和上傳(安全的原因,盜版的原因),因而一個映象在不同的雲之間,或者同一個雲不同的 Region 之間,無法進行遷移,只能重新做一個映象,這樣環境的一致性就得不到保障。


而容器的映象中心是獨立於雲之外的,只要能夠連上映象中心,到哪個雲上都可以下載,並且因為映象小,下載速度快,映象是分層的,每次只需要下載差異的部分。


OpenStack 對於映象方面的最佳化,基本上還是在一個雲裡面起作用,一旦跨多個環境,映象方便的多。


誤區四:容器可以使用容器平臺管理自動重啟實現自修復


容器的自修復功能是經常被吹噓的。因為容器是衣服,人躺下了,衣服也躺下了,容器平臺能夠馬上發現人躺下了,於是可以迅速將人重新喚醒工作。


而虛擬機器是房子,人躺下了,房子還站著。因而虛擬機器管理平臺不知道里面的人能不能工作,所以容器掛了會被自動重啟,而虛擬機器裡面的應用掛了,只要虛擬機器不掛,很可能沒人知道。


這些說法都沒錯,但是人們慢慢發現了另外的場景,就是容器裡面的應用沒有掛,所以容器看起來還啟動著,但是應用已經不工作沒有反應了。


當啟動容器的時候,雖然容器的狀態起來了,但是裡面的應用還需要一段時間才能提供服務。


所以針對這種場景,容器平臺會提供對於容器裡面應用的 health check,不光看容器在不在,還要看裡面的應用能不能用,如果不能,可自動重啟。


一旦引入了 health check,和虛擬機器的差別也不大了,因為有了 health check,虛擬機器也能看裡面的應用是否工作了,不工作也可以重啟應用。


還有就是容器的啟動速度快,秒級啟動,如果能夠自動重啟修復,那就是秒級修復,所以應用更加高可用。


這個觀點當然不正確,應用的高可用性和重啟的速度沒有直接關係。高可用性一定要透過多個副本來實現,在任何一個掛掉之後,不能透過這一個應用快速重啟來解決,而是應該靠掛掉的期間,其他的副本馬上把任務接過來進行解決。


虛擬機器和容器都可以有多副本,在有多個副本的情況下,重啟是 1 秒還是 20 秒,就沒那麼重要了,重要的是掛掉的這段時間內,程式做了什麼。


如果程式做的是無關緊要的操作,那麼掛了 20 秒,也沒啥關係;如果程式正在進行一個交易和支付,那掛掉 1 秒也不行,也必須能夠修復回來。


所以應用的高可用性要靠應用層的重試,冪等去解決,而不應該靠基礎設施層重啟的快不快來解決。


對於無狀態服務,在做好重試的機制的情況下,透過自動重啟修復是沒有問題的,因為無狀態的服務不會儲存非常重要的操作。


對於有狀態服務,容器的重啟不但不是推薦的,而且可能是災難的開始。


一個服務有狀態,例如資料庫,在高併發場景下,一旦掛了,哪怕只有 1 秒,我們必須要弄清楚這 1 秒都發生了什麼,哪些資料儲存了,哪些資料丟了,而不能盲目的重啟,否則很可能會造成資料的不一致性,後期修都沒法修。


例如高頻交易下的資料庫掛了,按說 DBA 應該嚴格稽核丟了哪些資料,而不是在 DBA 不知情的情況下,盲目的重啟了,DBA 還覺得沒什麼事情發生,最終很久才能發現問題。


所以容器是比較適合部署無狀態服務的,隨便重啟都可以。


而容器部署有狀態容器不是不能,而是要非常小心,甚至都是不推薦的。


雖然很多的容器平臺都支援有狀態容器,然而平臺往往解決不了資料問題,除非你對容器裡面的應用非常非常熟悉。


當容器掛了,你能夠準確的知道丟了哪些,哪些要緊,哪些不要緊,而且要寫程式碼處理這些情況,然後才能支援重啟。


網易這面的資料庫在主備同步的情況下,是透過修改 MySQL 原始碼,保證主備之間資料完全同步,才敢在主掛了的情況下,備自動切換主。


而宣傳有狀態容器的自動重啟,對於服務客戶來講是很不經濟的行為,因為客戶往往沒有那麼清楚應用的邏輯,甚至應用都是買的。


如果使用有狀態容器,任憑自動重啟,最終客戶發現資料丟失的時候,還是會怪到你的頭上。


所以有狀態的服務自動重啟不是不可用,需要足夠專業才行。


誤區五:容器可以使用容器平臺進行服務發現


容器平臺 Swarm,Kubernetes,Mesos 都是支援服務發現的,當一個服務訪問另一個服務,都會有服務名轉化為 VIP,然後訪問具體的容器。


然而人們會發現,基於 Java 寫的應用,服務之間的呼叫多不會用容器平臺的服務發現,而是用 Dubbo 或者 Spring Cloud 的服務發現。


因為容器平臺層的服務發現,還是做的比較基礎,基本是一個域名對映的過程,對於熔斷,限流,降級都沒有很好的支援。


然而既然使用服務發現,還是希望服務發現中介軟體能夠做到這一點,因而服務之間的服務發現之間使用容器平臺的少,越是需要高併發的應用,越是如此。


那容器平臺的服務發現沒有用了麼?不是,慢慢你會發現,內部的服務發現是一方面,這些 Dubbo 和 Spring Cloud 能夠搞定,而外部的服務發現就不同了。


比如訪問資料庫,快取等,到底是應該配置一個資料庫服務的名稱,還是 IP 地址呢?


如果使用 IP 地址,會造成配置十分複雜,因為很多應用配置之所以複雜,就是依賴了太多的外部應用,也是最難管理的一方面。


如果有了外部的服務發現,配置就會簡單很多,也只需要配置外部服務的名稱就可以了,如果外部服務地址變了,可以很靈活的改變外部的服務發現。


誤區六:容器可以基於映象進行彈性伸縮


在容器平臺上,容器有副本數的,只要將副本數從 5 改到 10,容器就基於映象進行了彈性伸縮。


其實這一點虛擬機器也能做到,AWS 的 Autoscaling 就是基於虛擬機器映象的,如果在同一個雲裡面,就沒有區別。


當然如果是跨雲無狀態容器的彈性伸縮,容器方便很多,可以實現混合雲模式,當高併發場景下,將無狀態容器擴容到公有云,這一點虛擬機器是做不到的。



容器理解誤區總結:



如上圖,左面是經常掛在嘴邊的所謂容器的優勢,但是虛擬機器都能一一懟回去。


如果部署的是一個傳統的應用,這個應用啟動速度慢,程式數量少,基本不更新,那麼虛擬機器完全能夠滿足需求:

  • 應用啟動慢:應用啟動 15 分鐘,容器本身秒級,虛擬機器很多平臺能最佳化到十幾秒,兩者幾乎看不出差別。

  • 記憶體佔用大:動不動 32G,64G 記憶體,一臺機器跑不了幾個。

  • 基本不更新:半年更新一次,虛擬機器映象照樣能夠升級和回滾。

  • 應用有狀態:停機會丟資料,如果不知道丟了啥,就算秒級啟動有啥用,照樣恢復不了,而且還有可能因為丟資料,在沒有修復的情況下,盲目重啟帶來資料混亂。

  • 程式數量少:兩三個程式相互配置一下,不用服務發現,配置不麻煩。


如果是一個傳統應用,根本沒有必要花費精力去容器化,因為白花了力氣,享受不到好處。



容器化,微服務,DevOps 三位一體




什麼情況下,才應該考慮做一些改變呢?


傳統業務突然被網際網路業務衝擊了,應用老是變,三天兩頭要更新,而且流量增大了,原來支付系統是取錢刷卡的,現在要網際網路支付了,流量擴大了 N 倍。


沒辦法,一個字:拆


拆開了,每個子模組獨自變化,少相互影響。拆開了,原來一個程式扛流量,現在多個程式一起扛。


所以稱為微服務。


微服務場景下,程式多,更新快,於是出現 100 個程式,每天一個映象。


容器樂了,每個容器映象小,沒啥問題,虛擬機器哭了,因為虛擬機器每個映象太大了。


所以微服務場景下,可以開始考慮用容器了。


虛擬機器怒了,老子不用容器了,微服務拆分之後,用 Ansible 自動部署是一樣的。


這樣說從技術角度來講沒有任何問題,然而問題是從組織角度出現的。


一般的公司,開發會比運維多的多,開發寫完程式碼就不用管了,環境的部署完全是運維負責,運維為了自動化,寫 Ansible 指令碼來解決問題。


然而這麼多程式,又拆又合併的,更新這麼快,配置總是變,Ansible 指令碼也要常改,每天都上線,不得累死運維。


所以在如此大的工作量情況下,運維很容易出錯,哪怕透過自動化指令碼。這個時候,容器就可以作為一個非常好的工具運用起來。


除了容器從技術角度,能夠使得大部分的內部配置可以放在映象裡面之外,更重要的是從流程角度,將環境配置這件事情,往前推了,推到了開發這裡,要求開發完畢之後,就需要考慮環境部署的問題,而不能當甩手掌櫃。


這樣做的好處就是,雖然程式多,配置變化多,更新頻繁,但是對於某個模組的開發團隊來講,這個量是很小的,因為 5-10 個人專門維護這個模組的配置和更新,不容易出錯。


如果這些工作量全交給少數的運維團隊,不但資訊傳遞會使得環境配置不一致,部署量會大非常多。


容器是一個非常好的工具,就是讓每個開發僅僅多做 5% 的工作,就能夠節約運維 200% 的工作,並且不容易出錯。


然而本來運維該做的事情開發做了,開發的老大願意麼?開發的老大會投訴運維的老大麼?


這就不是技術問題了,其實這就是 DevOps,DevOps 不是不區分開發和運維,而是公司從組織到流程,能夠打通,看如何合作,邊界如何劃分,對系統的穩定性更有好處。


所以微服務,DevOps,容器是相輔相成,不可分割的。


不是微服務,根本不需要容器,虛擬機器就能搞定,不需要 DevOps,一年部署一次,開發和運維溝通再慢都能搞定。


所以,容器的本質是基於映象的跨環境遷移。


映象是容器的根本性發明,是封裝和執行的標準,其他什麼 namespace,cgroup,早就有了,這是技術方面。


在流程方面,映象是 DevOps 的良好工具。容器是為了跨環境遷移的,第一種遷移的場景是開發,測試,生產環境之間的遷移。


如果不需要遷移,或者遷移不頻繁,虛擬機器映象也行,但是總是要遷移,帶著幾百 G 的虛擬機器映象,太大了。


第二種遷移的場景是跨雲遷移,跨公有云,跨 Region,跨兩個 OpenStack 的虛擬機器遷移都是非常麻煩,甚至不可能的,因為公有云不提供虛擬機器映象的下載和上傳功能,而且虛擬機器映象太大了,一傳傳一天。


所以跨雲場景下,混合雲場景下,容器也是很好的使用場景。這也同時解決了僅僅私有云資源不足,扛不住流量的問題。



容器的十大正確使用場景



根據以上的分析,我們發現容器推薦使用在下面的場景下:

  • 部署無狀態服務,同虛擬機器互補使用,實現隔離性。

  • 如果要部署有狀態服務,需要對裡面的應用十分的瞭解。

  • 作為持續整合的重要工具,可以順利在開發,測試,生產之間遷移。

  • 適合部署跨雲,跨 Region,跨資料中心,混合雲場景下的應用部署和彈性伸縮。

  • 以容器作為應用的交付物,保持環境一致性,樹立不可變更基礎設施的理念。

  • 執行程式基本的任務型別的程式。

  • 用於管理變更,變更頻繁的應用使用容器映象和版本號,輕量級方便的多。

  • 使用容器一定要管理好應用,進行 health check 和容錯的設計。


So,想體驗容器進行實踐演練可以前往華為雲進行操作體驗!華為雲容器引擎,高效能、企業級、開放相容、簡單易用!
大有可為雲容器!https://www.huaweicloud.com/product/cce.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31543630/viewspace-2156984/,如需轉載,請註明出處,否則將追究法律責任。

相關文章