有贊容器化實踐

2 人贊了文章

前言

容器化已經成為一種趨勢,它可以解決很多運維中的痛點,比如效率、成本、穩定性等問題,而接入容器的過程中往往也會碰到很多問題和不便。在有贊最開始做容器化是為了快速交付開發測試環境,在容器化的過程中,我們碰到過容器技術、運維體系適配、用戶使用習慣改變等各種問題,本文主要介紹有贊容器化過程中碰到的問題以及採取的方案。

有贊容器化的初衷

在有贊同時會有很多個項目、日常在並行開發,環境的搶佔問題嚴重影響了開發、測試和上線的效率,我們需要給每個項目提供一套開發聯調(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 應用在線程數和內存使用上都比虛擬機多的多,嚴重影響運行,其他類型的應用也有類似的問題。

我們會根據容器的規格內置一個環境變數 NUMCPUS,然後比如 nodejs 應用就會按照這個變數來創建它的 worker 進程數。在解決 java 類應用的問題時,我們索性通過 LDPRELOAD 將 JVMActiveProcessorCount 函數覆蓋掉,讓它直接返回 NUMCPUS 的值[1]。

應用接入

在容器化之前,有贊的應用已經全部接入到發布系統,在發布系統里已經標準化了應用的打包、發布流程,所以在應用接入方面成本還是比較小的,業務方無需提供 Dockerfile。

  1. nodejs, python,php-soa 等用 supervisord 託管的應用,只需要在 git 倉庫里提供 app.yaml 文件定義運行需要的 runtime 和啟動命令即可。

  1. java 標準化啟動的應用業務方無需改動
  2. java 非標準化的應用需要做標準化改造

鏡像集成

容器鏡像我們分了三層,依次為 stack 層(os),runtime 層(語言環境),應用層(業務代碼和一些輔助agent),應用以及輔助 agent 由 runit 來啟動。由於我們的配置還沒有完全分離,在應用層目前還是每個環境獨立打包,鏡像里除了業務代碼之外,我們還會根據業務的語言類型放一些輔助的 agent。我們一開始也想將各種 agent 拆成多個鏡像,然後每個 pod 運行多個容器,後來因為解決不了 pod 里容器的啟動順序(服務啟動有依賴)問題,就把所有服務都扔到一個容器里去運行了。

我們的容器鏡像集成過程也是通過 kubernetes 來調度的(會調度到指定的打包節點上),在發布任務發起時,管控系統會在集群中創建一個打包的 pod,打包程序會根據應用類型等參數編譯代碼、安裝依賴,並且生成 Dockerifile,然後在這個 pod 中使用 docker in docker 的方式來集成容器鏡像並推送到倉庫。

為了加速應用的打包速度,我們用 pvc 緩存了 python 的 virtualenv,nodejs 的 node_modules,java 的 maven 包等文件。另外就是 docker 早的版本里,Dockerfile ADD 指令是不支持指定文件屬主和分組的,這樣會帶來一個問題就是需要指定文件屬主時(我們的應用是以 app 賬號運行的)需要多運行一次 RUN chown,這樣鏡像也就多了一層數據,所以我們打包節點的 docker 版本採用了官方比較新的 ce 版本,因為新版本支持 ADD --chown 特性。

負載均衡(ingress)

有贊的應用內部調用有比較完善的服務化和 service mesh 方案,集群內的訪問不用過多考慮,負載均衡只需要考慮用戶和系統訪問的 http 流量,在容器化之前我們已經自研了一套統一接入系統,所以在容器化負載均衡上我們並沒有完整按照 ingress 的機制來實現 controller,ingress 的資源配置是配在統一接入里的,配置裡面轉發的 upstream 會和 kubernetes 里的 service 關聯,我們只是做了一個 sync 程序 watch kube-api,感知 service 的變化來實時更新統一接入系統中 upstream 的伺服器列表信息。

容器登錄和調試

在容器化接入過程中開發會反饋是控制台比較難用,雖然我們優化了多次,和 iterm2 等的體驗還是有所不足,最終我們還是放開了項目/持續交付環境這種需要頻繁登陸調試的 ssh 登陸許可權。

另外一個比較嚴重的問題是,當一個應用啟動後健康檢查有問題會導致 pod 一直在重新調度,而在開發過程中開發肯定是希望看到失敗現場的,我們提供了調試發布模式,讓容器不做健康檢查。

日誌

有贊有專門的日誌系統,我們內部叫天網,大部分日誌以及業務監控數據都是通過 sdk 直接打到天網裡去了,所以容器的標準輸出日誌僅僅作為一種輔助排查問題的手段。我們容器的日誌收集採用的是 fluentd,經過 fluentd 處理後按照天網約定的日誌格式打到 kafka,最終由天網處理進入 es 做存儲。

灰度發布

我們涉及到灰度發布的流量主要包含三部分:

  1. 用戶端的 http 訪問流量
  2. 應用之間的 http 調用
  3. 應用之間的 dubbo 調用

首先,我們在入口的統一接入上統一打上灰度需要用的各種維度的標籤(比如用戶、店鋪等),然後需要對統一接入、http client 以及 dubbo client 做改造,目的是讓這些標籤能夠在整個調用鏈上透傳。我們在做容器灰度發布時,會發一個灰度的 deployment,然後在統一接入以及灰度配置中心配置灰度規則,整個鏈路上的調用方都會感知這些灰度規則來實現灰度發布。

標準環境容器化

標準環境的出發點

  1. 和項目環境類似,標準穩定環境中的 daily,qa,pre 以及 prod 中超過一半運行在低水位的伺服器的資源非常浪費。
  2. 因為成本考慮 daily,qa,pre 里都是以單台虛擬機運行的,這樣一旦需要發布穩定環境將會造成標準穩定環境和項目環境的短暫不可用。
  3. 虛擬機交付速度比較慢,使用虛擬機做灰度發布也比較複雜。
  4. 虛擬機往往會存在幾年甚至更長的時間,運行過程中操作系統以及基礎軟體版本的收斂非常麻煩。

標準環境容器化推進

經過之前項目/持續交付的上線和迭代,大部分應用本身已經具備了容器化的條件。不過對於上線來說,需要整個運維體系來適配容器化,比如監控、發布、日誌等等。目前我們生產環境容器化準備基本完成,生產網已經上了部分前端 nodejs 應用,其他應用也在陸續推動中,希望以後可以分享更多生產環境中的容器化經驗。

結束語

以上是有贊在容器化上的應用,以及在容器化過程中碰到的一些問題和解決方案,我們生產環境的容器化還處於開始階段,後面還會碰到各種個樣的問題,希望能夠和大家互相學習,後面能夠有更多的經驗分享給大家。

參考文獻

[1] github.com/fabianenardo

歡迎關注公眾號獲取更多內容:有贊coder(公眾號ID:youzan_coder)


推薦閱讀:
查看原文 >>
相关文章