前言
容器化已經成為一種趨勢,它可以解決很多運維中的痛點,比如效率、成本、穩定性等問題,而接入容器的過程中往往也會碰到很多問題和不便。在有贊最開始做容器化是為了快速交付開發測試環境,在容器化的過程中,我們碰到過容器技術、運維體系適配、使用者使用習慣改變等各種問題,本文主要介紹有贊容器化過程中碰到的問題以及採取的方案。
有贊容器化的初衷
在有贊同時會有很多個專案、日常在並行開發,環境的搶佔問題嚴重影響了開發、測試和上線的效率,我們需要給每個專案提供一套開發聯調(daily)、測試環境(qa),並且隨著專案、日常的生命週期專案環境也會隨著建立和銷燬,我們最早的容器化需求就是怎麼解決環境快速交付的問題。
[有贊環境]

上面是有贊大致的研發流程,在標準流程中我們有四套穩定環境,分別是 Daily 環境、Qa 環境、預發環境和測試環境。我們的開發、測試、聯調工作一般並不會直接在穩定環境中進行,而是會拉一套獨立的專案環境出來,隨著程式碼經過開發、測試、預發驗收最終釋出到生產環境後再同步回 Daily/Qa 的穩定環境中。
[專案環境]

我們提供了一套以最小的資源投入滿足最大專案並行度的環境交付方案,在 Daily/Qa 穩定環境的基礎上,隔離出N個專案環境,在專案環境裡只需要建立該專案所涉及應用的計算資源,其它缺失的服務呼叫由穩定環境提供,在專案環境裡,我們大量使用了容器技術。
[持續交付]

後面我們又在專案環境快速交付的解決方案的基礎上實現了持續交付流水線,目前已經有超過 600 套專案/持續交付環境,加上 Daily/Qa 穩定環境,涉及計算例項四五千個,這些計算例項無論是 cpu 還是記憶體使用率都是非常低的,容器化可以非常好的解決環境交付的效率問題,以及提高資源使用率來節省成本的投入。
有贊容器化方案
我們的容器化方案基於 kubernetes(1.7.10)和 docker(1.12.6)、docker(1.13.1),下面介紹一下我們在各個方面遇到的問題以及解決方案。
網路
有贊後端主要是 java 應用,採用定製的 dubbo 服務化方案,過程中無法做到整個單元全量容器化,和原有叢集在網路路由上互通也就成了剛需,由於我們無法解決公有云上 overlay 網路和公有云網路的互通問題,所以一開始我們放棄了 overlay 網路方案,採用了託管網路下的 macvlan 方案,這樣既解決了網路互通的問題也不存在網路效能問題,但是也就享受不到公有云彈性資源的優勢了。隨著有贊多雲架構的發展以及越來越多的雲廠商支援容器 overlay 網路和 vpc 網路打通,彈性資源的問題才得到了緩解。
隔離性
容器的隔離主要利用核心的 namespace 和 cgroup 技術,在程式、cpu、記憶體、IO等資源隔離限制上有比較好的表現,但其他方面和虛擬機器相比存在著很多的不足,我們在使用過程中碰到最多的問題是容器裡看到的 cpu 數和記憶體大小不準確,因為/proc檔案系統無法隔離,導致容器裡的程式"看到"的是物理機的 cpu 數以及記憶體大小。
記憶體問題
我們的 java 應用會根據伺服器的記憶體大小來決定 jvm 引數應該怎麼配置,我們是採用 lxcfs 方案來規避的。

CPU 數的問題
因為我們有超賣的需求以及 kubernetes 預設也是採用 cpu share 來做 cpu 限制,雖然我們使用了 lxcfs,CPU 數還是不準的。jvm 以及很多 Java sdk 都會根據系統的 CPU 數來決定建立多少執行緒,導致 java 應用線上程數和記憶體使用上都比虛擬機器多的多,嚴重影響執行,其他型別的應用也有類似的問題。 我們會根據容器的規格內建一個環境變數 NUM_CPUS,然後比如 nodejs 應用就會按照這個變數來建立它的 worker 程式數。在解決 java 類應用的問題時,我們索性通過 LD_PRELOAD 將 JVM_ActiveProcessorCount 函式覆蓋掉,讓它直接返回 NUM_CPUS 的值[1]。
應用接入
在容器化之前,有讚的應用已經全部接入到釋出系統,在釋出系統裡已經標準化了應用的打包、釋出流程,所以在應用接入方面成本還是比較小的,業務方無需提供 Dockerfile。
- nodejs, python,php-soa 等用 supervisord 託管的應用,只需要在 git 倉庫裡提供 app.yaml 檔案定義執行需要的 runtime 和啟動命令即可。
- java 標準化啟動的應用業務方無需改動
- java 非標準化的應用需要做標準化改造
映象整合


負載均衡(ingress)

容器登入和除錯

日誌

灰度釋出
我們涉及到灰度釋出的流量主要包含三部分:
- 使用者端的 http 訪問流量
- 應用之間的 http 呼叫
- 應用之間的 dubbo 呼叫 首先,我們在入口的統一接入上統一打上灰度需要用的各種維度的標籤(比如使用者、店鋪等),然後需要對統一接入、http client 以及 dubbo client 做改造,目的是讓這些標籤能夠在整個呼叫鏈上透傳。我們在做容器灰度釋出時,會發一個灰度的 deployment,然後在統一接入以及灰度配置中心配置灰度規則,整個鏈路上的呼叫方都會感知這些灰度規則來實現灰度釋出。
標準環境容器化
標準環境的出發點
- 和專案環境類似,標準穩定環境中的 daily,qa,pre 以及 prod 中超過一半執行在低水位的伺服器的資源非常浪費。
- 因為成本考慮 daily,qa,pre 裡都是以單臺虛擬機器執行的,這樣一旦需要釋出穩定環境將會造成標準穩定環境和專案環境的短暫不可用。
- 虛擬機器交付速度比較慢,使用虛擬機器做灰度釋出也比較複雜。
- 虛擬機器往往會存在幾年甚至更長的時間,執行過程中作業系統以及基礎軟體版本的收斂非常麻煩。
標準環境容器化推進
經過之前專案/持續交付的上線和迭代,大部分應用本身已經具備了容器化的條件。不過對於上線來說,需要整個運維體系來適配容器化,比如監控、釋出、日誌等等。目前我們生產環境容器化準備基本完成,生產網已經上了部分前端 nodejs 應用,其他應用也在陸續推動中,希望以後可以分享更多生產環境中的容器化經驗。
結束語
以上是有贊在容器化上的應用,以及在容器化過程中碰到的一些問題和解決方案,我們生產環境的容器化還處於開始階段,後面還會碰到各種個樣的問題,希望能夠和大家互相學習,後面能夠有更多的經驗分享給大家。
參考文獻
