ofo 基於 K8S 容器雲平台的實踐
- 2019 年 12 月 6 日
- 筆記

| 為 | 容 | 器 | 技 | 術 | 而 | 生 |
講師:王強 / ofo 容器雲研發負責人 編輯:小君君
近幾年隨著容器技術生態日趨成熟,中國外互聯網以及傳統 IT 企業都積極擁抱容器技術,並在測試以及生產環境中大量使用容器化部署,容器技術降低了 IT 運維成本,縮短了業務交付周期。基於主流容器編排技術(Docker/Kubernetes)的容器雲平台集上線發布,容器管理,彈性伸縮,資源監控等功能的 PaaS 平台正逐漸流行起來。
今天講的內容分為兩部分。第一部分分享 ofo 基於 Kubernetes 開發的 PaaS 平台的功能簡介。第二部分是關於容器化落地的案例。
容器化平台
如今中國已經有很多容器雲平台產品,但結合我們自身需求的迫切度,放棄 OpenShift 而採用獨立開發,主要是基於對 PaaS 程式碼、實現自主可控性和對底層 Kubernetes/Docker 的優化訂製。

Ruly PaaS 主要功能
系統資源 Dashboard,通過這裡可以查看集群內總體資源使用概覽,以及具體節點資源使用情況。Kubernetes 集群、Namespace 管理是做相關的 Kubernetes 集群及 Namespace 的基本管理。通過 Ruly PaaS 可以管理多個 Kubernetes 集群,當前 Ruly PaaS 管理了 4 個 Kubernetes 集群,包括中國及海外生產/測試集群。
容器化的 CI/CD,底層實現基於 Jenkins Jnlp CI/CD 開發的 API 服務,將 Git 程式碼打包成 Docker image 鏡像,作為容器應用自動部署在 Kubernetes 指定集群里。應用服務和分散式任務管理是基於業務的容器化落地相關需求來實現。統一配置管理是基於 Kubernetes ConfigMap 做的相關應用配置服務,主要是管理線上業務的一些配置文件,比如:Nginx 的配置文件,業務日誌收集 sidecar flume agent 的配置文件等。
最下面是資源審計/帳號分組管理,以及操作審計。我們會根據角色 QA、運維,以及各個不同的研發 Team 作相關帳號分組。每個相關部門的同學只能訪問到指定的應用。操作審計除了在 PaaS 中的基本操作會做審計記錄之外,在 PaaS WebShell 中對容器操作也會記錄下來。
PaaS 架構以及主要功能

這是 PaaS 的整體架構,從基礎層往上層開始做。從最開始做的基礎架構選型、容器宿主機選型、作業系統選型優化、Kubernetes/Docker 選型及相關壓測優化等。同時還包括搭建底層的基礎服務。比如:鏡像倉庫集群,包括中國和海外的鏡像 Replica 同步機制等。
我們目前並行在做自有 IDC 機房的容器基礎設施適配工作。上層工作流層,主要是 CI/CD 功能部分,是 Ruly PaaS 的主要功能模組。程式碼審計功能主要是集成了 SonarQube 作業務程式碼掃描。持續交付,默認 Kubernetes Rolling Update 方式。
運維模組,通過 PaaS 中的應用及 Pod 事件列表,可以看到某個具體業務應用上線/擴縮/健康檢查失敗/OOM 等事件,並根據這些事件作報警。彈性伸縮除支援基於 Kubernetes HPA 容器擴縮之外,還支援集群宿主機節點的動態擴容。最上面一層,主要是做服務治理,APM 全鏈路監控。
CI/CD 功能

目前應用業務的程式語言種類主要有:Node 8、Go、PHP 7、Java 8、C++等。為方便開發者快速掌握 Dockerfile 編寫,抽象出這些程式語言的 Dockerfile 模板。開發者在做自己業務的容器化部署時可以選擇相應的模板,去補全相應的模板參數,比如:部署路徑,是否可以作業務日誌搜集。也可以完全手寫一個完整的 Dockerfile。應用類型,目前支援的是 Kuberneetes Deployment 和 Statefulset,默認業務以無狀態應用為主,少量業務為有狀態應用。
線上應用可以配置指定容器副本數,CPU 及記憶體資源限制,環境變數等。對於 Node 8 或者 Go 業務,環境變數能為測試或生產集群指定相應的環境變數。業務根據其尋找相應的配置。健康檢查策略主要是利用 Kubernetes 標準 HTTP GET、TCP 埠探活,自定義 SHELL 命令行作容器的健康檢查。應用業務上線有一些配置文件。Ruly PaaS 將配置文件導入 PaaS 的配置中心。在 CI/CD 時將該應用與配置項做關聯。
上線部署
上線部署時運維/開發或 QA 同學輸入指定 commit id,作構建及部署。底層構建的鏡像 Tag 主要由自增 ID、集群 ID、commit ID 構成。鏡像構建完成後上傳到鏡像倉庫,請求 Ruly PaaS CDAPI 向指定 Kubernetes 集群中部署。
上線部署方式除支援默認的 RollingUpdate 外,還支援「手動部署」:在部署完一個新容器後,檢查當前業務日誌,在 PaaS 中手動確認上線下一個容器或其餘副本。「金絲雀」:部署方式是等量副本數部署新版本業務,全部將線上流量切到新版本業務容器中。
線上業務容器化後,我們會配置自動擴縮策略,先根據 CPU/記憶體一些經驗值作為閾值,運行一段時間後觀察負載情況做一些具體閾值調整,包括副本數。
資源審計

提供集群,Namespace 以及項目等維度資源的使用情況,主要是為容器或宿主機的升降配,擴縮等提供參考。
高級功能
這裡主要是容器化落地。而後會有一些訂製化的需求,比如前面介紹的部分配置中心功能,基於 Kubernetes ConfigMap 實現,增加了版本控制便於回滾。
服務定義
基於 Kubernetes SVC 來實現。大部分 http/gRPC 型業務是為了保證性能最佳,都是以 4 層服務的形式導出。使用 Kubernetes svc spec external TrafficPolicy: Local 方式,不對客戶端 IP 做 SNAT。
第一,性能最優最穩定。第二,後端容器可以拿到客戶端的真實 IP,為指定應用定義服務,導出服務 IP 和埠後,下游業務只需訪問這個服務 IP 加埠即可,而無需關心後端有多少個容器。關於 SVC SNAT 模式下帶來的穩定性問題社區有過回饋,說一下我們採用的解決方案。
在去年 12 月選型做基本測試時發現這個問題:單一併發短連接對 SVC 後端 Nginx 容器壓測,約 2 分鐘後就會有 1 至 2 筆 1 秒 到 3 秒的請求,同時客戶端會有 5** 的響應碼。我們通過對容器內及宿主機進行抓包分析,發現經過宿主機上 SNAT 後到容器內,出現了 Socket tuple5 元組重合的問題導致了 TCP 重傳。使用 4 層 LB 做為 Kubernetes SVC。同時 external Traffic Policy:Local 方式,所有向外部暴露的服務都是採用這種方式。
流量複製
我們 QA 和安全部門的同學需要一種方案可以模擬線上真實流量複製到測試的容器集群中。對於安全團隊來說,需要做線上流量旁路監聽,流量複製。目前我們的內部版本是 v0.1-alpha,這一版基於 Envoy 實現,存在一些弊端:無法做流量翻倍,由於引入一層 Envoy 代理,性能有所損失,無法做全流量複製,只能複製某一個或幾個 Pod 流量。
Webshell
這是從 PaaS 0.1 實現的功能,便於開發者連接容器,做實時 Debug。這種查看方式與原有 ECS 部署差不多,用於看線上實時輸出日誌,進程狀態等。
分散式任務
這是基於 Kubernetes 原生的 Cronjob 和 job 做的,跑一些分散式任務。
特權容器(privileged)
主要用於優化容器性能以及容器問題診斷,比如 TCP listen backlog 需要特權容器模式對該容器配置系統參數。另外,特權容器內可以運行 strace 以及類似的診斷工具對容器進程性能做診斷分析。
初始化容器(initContainers)
Ruly PaaS 對 Kubernetes initContainers 的支援結合了安全因素以及性能優化因素。特權容器,可以修改容器本身的系統參數(sysctl),以及運行一些類 strace 的診斷工具。
一個業務容器,本身在特權容器模式下是有風險的,遵循最小許可權原則。我們的做法是在業務容器內的 initContainers 階段,執行系統參數優化腳本。執行完成後,實際業務就集成在這優化過的系統環境中。該業務容器不必再使用特權模式。
主機網路
在業務容器化遷移過程中,適配現有的自註冊架構業務而採取的方案。這種架構業務是基於 Zookeeper 或 Spring Cloud Eureka 來做服務發現。業務服務啟動時要把自己的 ip 及埠註冊在服務註冊中心,供下游訪問。由於遷移過程中,下游業務沒有立即容器化,還是運行在原來的 ECS 宿主機上。這需要在不更改業務服務程式碼的前提下,採用主機網路模式啟動。該模式下業務註冊的 ip 及埠可以被下游非容器化業務直接訪問。
容器及基礎設施優化

硬體系統選型,大部分用 16 核/32 G 的虛機作為 Kubernetes 的節點。隨著大量後端業務容器化後,我們也採用一些 32 核/64 G 的虛擬機。
作業系統相關優化最低標準是單機支援 TCP 的百萬並發,藉助內核本身的優勢,主要是優化一些內核參數配置:/ect/sysctl.conf、/etc/security/limits.conf、TCP、iptables、arp表、句柄數等參數限制(net.nf_conntrack_max,net.core.somaxconn,fs.file-max,net.ipv4.neigh.default.gc_thresh*等),對於 limits.conf 文件主要是優化非 root 許可權文件句柄數(nofile),進程數(nproc)等。以此便於容器內 www 許可權應用(nodejs/go/java)能盡量使用最優性能的基礎配置。對於宿主機作業系統的優化,我們編寫了優化腳本,以統一打包作為宿主機作業系統的鏡像。
Kubernetes 容器層面優化
我們包括基礎鏡像的製作(本地化,如東八區時區)。性能優化方面,我們把容器內的優化腳本也打包到了基礎鏡像中,便於 initContainers 階段執行。運行 go/node/java 業務的基礎鏡像是基於 Alpine Linux3.7、3.8 訂製。
還有其他優化,比如 Go 程式默認 TLS 握手時,本地默認要有一個證書 CA 環境。常規方式是安裝一個 ca-certificates 包,容器化後 Go 業務做 TLS 握手,會掃描包里所有的證書文件,大概 30 個以上的文件 io 操作。實際只需要一個 CA 證書,所以我們把基礎鏡像中其他無用證書都刪除。
CentOS 7.3 主要是用來運行複雜的 C++ 業務,還有 PHP 7 業務場景。使用 strip 工具對編譯好的二進位文件裁剪,使鏡像保持最小。後續也會把這部分基礎鏡像用 Alpine Linux 來代替。
kube-dns優化
目前使用原生的 kube-dns 做容器 DNS 解析。最開始的方式是 HPA 自動擴縮。在自動縮容時,會增大業務響應時間,導致依賴的 DNS 業務超時。目前採用的方式是 kube-dns-autoscaler,它可以根據整個集群 CPU 核數,還有 Pod 數去做相應的比例增加。優化方面,主要是增大 cache-size,設置 neg-ttl,對無效的 DNS 設置一個快取,增大 DNS 進程的 CPU/memory。
日誌的自動清理,以 DaemonSet 形式進行部署,在做容器化業務上線時,對在 PaaS 中的環境變數配置要清理的日誌路徑和日誌文件保留時長。我們會定時清理有業務日誌。
業務容器優化
對於 GO 業務來說,GO 自身的 MPG 模型是根據 GOMAXPROCS 相關值來啟動具體的工作執行緒。但 GO 容器化後,按照所在宿主機的 CPU 核數來啟動工作執行緒。不是實際為該容器分配 CPU 核數,在有些業務場景下會出現更多的 CPU 爭用。例如高 iowait,當我們在 PaaS 中設置環境變數 GOMAXPROCS。該值為容器指定具體的分配核數後,我們業務的 QPS 會提升一倍以上,平均響應時間會下降到原來的 1/3 甚至更多。宿主機上的 CPU iowait 也會降至正常水平。對於 Java 業務,它的新版 JDK 8 或 10 都提供一些相關參數(如:-XX:+UnlockExperimentalVMOptions),可以智慧感知到 cgroup 的 CPU/memory 限制。
業務容器化案例

我們的一些容器化案例:API 業務基本無狀態,對接 APP 端。有用戶中心、位置服務、配置服務還有一些網關服務等。基於 node/go 開發,內部會使用 gRPC 方式訪問底層依賴服務。
gRPC 服務相當於在 API 服務後的服務。基於現在的 ZK 服務發現機制,要求容器啟動後向 ZK 註冊,容器銷毀時需要反註冊。這裡涉及到業務容器安全退出問題,業務程式碼需要做訊號(SIGINT/SIGTERM)處理。這個反註冊和之前的 ECS 部署方式一致,容器化後不需要再修改程式碼。
長連接服務
我們的長連接服務有 APP 推送服務和 IoT 鎖網關接入層服務。APP 推送是 6 月初全量容器化部署。包括 TCP 接入層,會話層,以及底層的持久化存儲層。目前,並發連接數是百萬級別,APP 推送的接入層是由 3 個 4 核 8G 的容器承載。這個 APP 推送分散式壓測工具也是容器化部署。
定時任務,利用分散式離線計算來做日誌的離線分析。統一從 Redis 去讀分散式任務分片,做日誌文件下載,處理後會匯到 Kafka/Hbase 中。
實時任務和實時日誌分析是利用上游消息隊列。Kafka,實時處理後發布到下游也有類似的消息隊列服務。其他業務是一些常規性的 Daemon 後台服務,做一些數據格式拉取,再轉換寫入到另外一個持久化存儲中去。
結語
我們的 Ruly PaaS 自上線以來,目前支撐了約 90% 的容器日常管理工作(上線部署,彈性擴縮,監控等),容器化的宿主機資源利用率提升了約 3 倍。後續為應對逐漸增多的有狀態業務,以及企業微服務架構的容器化落地,我們會在 Ruly PaaS 迭代過程中,集成有狀態存儲的管理,ServiceMesh 等高級功能。謝謝大家!

王強 / ofo 容器雲研發負責人
14 年以上互聯網、安全、互金等開發架構經驗,專註於基礎架構服務設計實現。
END