同程藝龍數據中心容器化背景

作爲同程藝龍的數據底層支撐部門,我們每天會產生海量的數據進行存儲和計算,爲了更好的支撐業務,我們在2018年推動所有的服務都採用了Docker Host模式部署。

我們一開始採用腳本管理容器服務,雖然能夠做到自動化部署,但是不同組件的資源池沒有打通,機器剩餘資源的把控不到位,服務的滾動更新和故障轉移也處於一個人工處理的狀態,這個時候我們急需一個統一調度和管理集羣資源的平臺,所以2019年我們開始嘗試將所有服務部署到Kubernetes上,已經投產的存儲服務有Elasticsearch,Tikv,Kudu,Kafka等一些節點類型少的服務,計算組件有Hive,Spark SQL等服務,在這條艱辛的on Kubernetes之路,我們也遇到了很多問題,今天向大家分享一下。

K8S集羣如何和外部世界打通

首先看下我們Kubernetes集羣的架構圖:

Kubernetes集羣和外部機器通信,我們採用的OVS虛擬交換機的方式將物理網絡和容器網絡做成一個大二層的網絡,這樣Kubernetes集羣外部的機器也能訪問到容器。因爲我們會部署分佈式系統,有些分佈式系統要求IP不變,所以Pod我們做了IP Local,根據Namespace和pod name來記錄每個Pod的IP,IP保留時間爲三天。爲了防止極端情況下的需求,我們給Pod做了指定IP的功能,但是由於我們部署使用的是自定義對象或者StatefulSet對象,這個功能還需要在上層對象的Controller中支持。

上面這些功能我們都是基於Contiv的netplugin插件,在使用過程中我們遇到節點veth pair刪除不乾淨的情況,我們採用定時檢查刪除無用veth pair來保證網絡的乾淨。

OVS架構圖如下:

Pod網絡的問題解決以後,Service的負載我們希望和Pod網絡一樣可以直接訪問。這裏我們使用Kubernetes Java Client Watch Service和Endpoints Event事件,將EndPoints和Service Cluster IP同步到同程藝龍的基礎設施組件TVS上,TVS是一個四層負載均衡,我們通過HTTP的方式進行同步。在剛開始上線的時候,我們發現Kubernetes Client切換leader節點的時候會重新消費之前的Service event事件,所以同步一定要保證冪等性,Service刪除事件同步要加上Kubernetes Service是否存在的校驗,確認Service真的不在的時候,再去刪除TVS的VIP。這種方式將我們的路由規則更集中式的管理,不會像kube-proxy將所有的規則同步到每臺物理機器上。

Service網絡解決以後,由於分佈式系統的一些特性,有些組件是一定要通過域名才能啓動和訪問。所以我們會把Kubernetes集羣內的節點域名全部註冊到公司的DNS服務上,這裏我們只要將Kubernetes內部域名改成公司提供的域名尾綴並重啓集羣和CoreDNS,然後將CoreDNS的域名同步一份到公司的DNS服務上。

做了上面這些支持後,我們覺得這樣一個集羣才符合生產環境的使用,既可以使用Kubernetes的很多特性,也和公司內部組件做了整合,用戶的體驗感也沒有太大的變化,反而藉助於Service和域名的自動同步,Kubernetes的編排能力,體驗更佳。

存儲計算組件上K8S集羣的實踐

因爲Kubernetes設計的初衷是爲了部署計算型的組件,所以我們覺得部署計算節點對我們來說難度不大,我們部署了 Hive,Spark SQL,Tensorflow server等計算組件,不同組件我們採用不同的Namespace進行管理,不同組件的機器資源我們打上標籤,做好資源池的劃分。針對Hive這種兩種及以上類型的節點,一開始我們會採用Helm寫好模板做好一鍵部署,然後我們會投入人力做Hive的Operator,開發Operator可以將我們的一些人工容災的思想用代碼去變現出來,更新多節點類型的組件也會簡單很多。

我們都會遇到存儲組件應不應該上Kubernetes,我到底應不應該用共享存儲的問題。我們認爲存儲組件是可以上Kubernetes的,這裏我們採用的 Local PV+Ceph的方式,針對大數據存儲組件,比如ES,TiKV,Kafka等組件,我們採用Local PV的方式,像物理機一樣將數據存在本地磁盤,保證性能。針對Jupyter一些非重要的組件我們會採用Ceph RBD Image的方式,用來節省本地磁盤的空間。剛開始的時候我們採用批量創建Local PV的方式,後來我們希望控制磁盤的使用,一個或者兩個存儲組件配一些計算組件做到資源的混部,我們將Local PV的創建做成按需分配,合理的控制磁盤的使用。

存儲組件我們第一個部署的組件是ElasticSearch,ES是非常容易支持的,因爲客戶端是http訪問,對外只需要提供 ES client節點類型,不需要暴露集羣內部節點信息,利用Service只需要提供一個TVS的VIP給到用戶。剛開始我們使用StatefulSet部署Elasticsearch,由於Statefulset順序性的限制,我們不能指定下掉某個節點,於是我們開發了一個高級版的AdvanceStatefulSet,通過指定序號就可以下線Pod。

像這樣配置即可:

offlineStrategy :

podOrdinals :

- 0

我們將ES部署方式用Helm模板寫好,做到自動化部署,每一個節點類型的容錯還侷限於AdvanceStatefulSet的Controller。ES官方也提供了Operator,因爲處於beta版本,自定義資源還有很多問題,沒有基於Sts做CRD,所以我們沒有選擇這種方式。我們覺得在Sts上層再建立一層CRD,可以更方便去管理多種節點類型,但是人力有限,我們對這個需求的優先級還不是很高,當前基於AdvanceSts管理也能夠運維起來。

在部署Kudu組件的時候,我們延用ES的套路,發現節點域名解析不到的問題,當時我們還沒有將Kubernetes內部域名同步到公司層面的DNS。在分佈式系統中,很常見的場景是客戶端連接到Master節點,Master節點會返回Worker節點域名,在Kubernetes集羣外部的機器是沒法訪問到Worker的域名的。在沒解決DNS問題之前,我們先採用Host模式部署,注意一下port衝突問題就好了。

因爲我們在2018年所有的組件已經on Docker,我們只要將組件的部署方式遷移到Kubernetes上來管理,所以像Kafka,TiKV,PG,ZK這些組件,我們都可以輕鬆的上Kubernetes。

不過在大數據組件當中,機器資源最多就屬Hadoop組件,在以前Docker Host部署的時候,DataNode和yarn節點會掛載sata的12塊盤,TiKV EleatiscSearch我們採用的是ssd raid50單塊盤的方式,我們發現Local PV的方式不能很好的掛載多塊盤,如果強行的掛載12個PV,scheduler需要支持每個PV在不同的磁盤,才能符合我們利用多塊盤讀寫的目的。

Local PV沒法解決我們的需求,我們開始嘗試HostPath,HostPath現在沒有一個好的資源管理器,HostPath不能和機器屬性綁定在一起,簡單來說就是讓HostPath具備Local PV機器綁定的特性。所以我們正在開發一個將HostPath也轉變成PV資源進行管理,具備和Local PV一樣的特性的Agent。當前我們採用的折中方案是AdvanceStatefulSet+nodeSelector+Affinity來部署yarn和DataNode,不過我們沒有大規模使用,因爲不夠優雅。

K8S集羣部署分佈式系統總結

我們認爲在Kubernetes上部署存儲或者計算型的組件是可行的,做好外部世界和Kubernetes集羣內部的通信,或者將所有的組件都放在Kubernetes集羣內部。

針對性能要求比較高的組件,採用Host模式+Local PV的方式部署。在沒有人力和開源成熟的Operator的時候,可以先用Helm模板化部署方式,先解決自動化部署。提供可視化的運維操作,通過人工組合操作的方式先代替Operator自動化運維。 將一些通用的功能搬到Operator之上,並將Operator定製化能力提供給用戶,讓用戶成爲你的開發者,共同構建Kubernetes生態。

當前我們維護了自己的AdvanceStatefulSet Controller,提供鏡像原地升級,指定下線節點的功能,維護一個基礎的Base Operator,我們希望將一些功能通用的覆蓋所有組件,針對Hive這種多節點類型的服務開發獨立的Operator。 在社區我們積極參與TiDB Operator的開發,我們覺得當前TiDB的雲原生方案是比較成熟,利用TiDB Operator部署的TiKV我們已經上生產了。 這些支持得益於我們對於Service Pod DNS的支持,賦予Kubernetes的網絡和磁盤靜態分配綁定的能力。

以前我們會部署一個大的分佈式系統業務混用,比如ES,現在我們可以利用Kubernetes切成小集羣,每個集羣都做好日誌和監控的功能,業務可以申請自己的集羣,資源上是隔離的,不會因爲資源互相影響。懂組件的業務也可以根據自己的場景,不斷優化自己集羣的配置。當我們對組件性能把控不到位的時候,採用小集羣是規避風險的一種方式。

關於監控,我們使用一個集羣配一個Prometheus+Grafana的方案,做到監控隔離,Prometheus我們採用Thanos架構,提供統一的監控查詢。

監控參考:

關於日誌,我們採用sidecar注入到Pod的方式,收集到Kafka,Flink落地ES,保留七天,我們可以針對日誌做一些報警策略。

日誌參考:

一些天生支持雲原生的組件探索

除了已有組件嘗試部署到Kubernetes,我們也在探索新的組件,比如JupyterHub,JupyterHub我們採用的是Ceph共享存儲。基於JupyterHub接口能力,提供自定義鏡像和定製化框架的能力,每個用戶可以申請自己的Jupyter,分配固定的資源配比。我們也嘗試部署了KubeFlow,想借助於TensorFlow Operator 部署分佈式任務能力提升算法側的能力,不過因爲KubeFlow要綁定Istio組件,我們覺得太大了,所以沒有將其放到線上。我們會基於Jupyter提供更好的數據分析層面的交互能力。

我們還部署了TensorFlow Server,打通HDFS和TensorFlow Server,用戶使用Spark訓練的TF model生成到HDFS之上,可以自動部署成TF server,做到模型的自動部署和滾動更新。還有Dask等等服務。

我們發現已有組件官方都在做雲原生的支持,新組件會自帶Kubernetes的支持,所以on Kubernetes未來一定可以走的更遠。

遇到的問題和未來規劃

在on Kubernetes這條路上,Kubernetes不能拿來即用,要根據自己的場景適配。在不影響已有業務的情況下,提供不改變用戶行爲的場景。原本用戶可以很方便看到日誌,知道請求落到哪個點上,那麼你就需要提供很好的日誌收集服務,提供更穩定的服務,才能讓用戶相信你的能力。

在網絡方面,我們會嘗試DPDK來加速容器網絡以及其他硬件方案,將大數據服務本地性需求弱化,做到存儲和計算的分離,提升擴展性。

在磁盤方面,我們會提供不同的規格的嘗試,當前我們是混部,我們會提供LVM+混部+分區的方案選擇,提供更靈活的部署方式。

在平臺層面,我們會將機器和底層研發用戶分開,可視化的運維集羣,提升安全性和便捷。

在技術變革的快車道上,我們要制定好如何在行駛中換輪胎,甚至是換引擎。

Q & A

Q1: 存儲集羣,出現Pod遷移怎麼解決數據盤問題?

A: Local PV,只要你不刪除PV和PVC,不會產生Pod偏移。你可以使用Sts volume Template試試。

Q2 :以前做過Zeppelin(類似Jupyter的工具)+Spark的應用,經常因爲各種隊列資源計算不足需要調整配置那些,如果上Docker的話,這種方便操作嗎?就是擔心容器集羣會不會不穩定?

A: 方便的。當前我們使用JupyterHub來創建Jupyter,Jupyter和Spark集羣打通,提供用戶直接寫代碼和集羣交互。不過要注意資源控制。我們直接和Spark交互用的是Apache的Livy。Kubernetes集羣你提高穩定性就可以了,我們現在用的很穩定。

Q3: 日誌監控保留一週,那資源利用的數據保留多久?比如CPU內存網絡硬盤這些數據?

A: 容器的監控我們保留12天。歷史數據我們用的Thanos架構,保存到Ceph中。物理機的監控我們是放在小米的Falcon。

Q4 :如果Pod掛了,出現Pod自動漂移到其他節點,掛載的Local PV數據是否也要做遷移?

A: 如果Pod掛了無法拉起,不刪除PV和PVC,Pod是不會漂移到其他節點。這是Local PV調度決定的。如果需要漂移到其他節點,需要手動的刪除PV和PVC,Pod漂移到其他節點,然後將有問題那個物理機上的數據遷移到新的PV上來。

Q5: Thanos監控數據如何存放?查詢速度比原生的Prometheus如何?

A: Thanos是Prometheus的高可用架構,我們用來做一個集中查詢。歷史歸檔數據是存儲在Ceph中,Prometheus存儲比如七天的數據,還是和原來一樣存儲在本地。查詢速度我們使用下來還可以,查詢速度取決於你的監控數據的體量,你可以做一些橫向擴展,數據量大的時候該慢還是慢的。

Q6: 請問一下Pod指定IP是怎麼實現的?

A: Kubernetes是支持CNI接口的,我們使用Contiv的netplugin插件,當Pod調度起來,會走CNI接口申請一個IP。根據Namespace+podname對應一個唯一標識,這個標識和IP是存儲在一個單獨的etcd中。podname用deployment部署是隨機的,所以我們基本上都會用我們開發的AdvanceSts來部署,這樣名字是固定的。

作者丨程威,同程藝龍數據中心Kubernetes負責人

來源丨 分佈式實驗室 (ID:dockerone)

dbaplus社羣歡迎廣大技術人員投稿,投稿郵箱: [email protected]

近年來大數據技術發展迅猛,不斷推陳出新抵抗新時代的海量數據處理挑戰。但隨着技術的更迭,每次演進都需要耗費大量的人力物力,傳統的數據管理模式已搖搖欲墜,此時DataOps應運而生。 9月11日 Gdevops全球敏捷運維峯會北京站 一起看看聯通大數據背後的DataOps體系建設:

  • 《數據智能時代: 構建能力開放的運營商大數據DataOps體系》 中國聯通大數據基礎平臺負責人/資深架構師 尹正軍

此議題將講述聯通大數據背後的DataOps平臺整體架構演進,包括數據採集交換加工過程、數據治理體系、數據安全管控、能力開放平臺運營和大規模集羣治理等核心實踐內容。

相關文章