當前位置:
首頁 > 最新 > AI獨角獸商湯科技的內部服務容器化歷程

AI獨角獸商湯科技的內部服務容器化歷程

內容目錄

● 背景

● 需求分析與技術選型

● 容器鏡像

● 監控報警

● 可靠性保障

● 總結

背 景

商湯科技是一家計算機視覺領域的AI創業公司,公司內會有一些業務需要雲端API支持,一些客戶也會通過公網調用這些所謂SaaS服務。總體來講,雲API的架構比較簡單,另外由於公司成立不久,歷史包袱要輕許多,很多業務在設計之初就有類似微服務的架構,比較適合通過容器化來適配其部署較繁複的問題。

公司各個業務線相對獨立,在組織上,體現在人員,績效及彙報關係的差異;在技術上體現在編程語言,框架及技術架構的獨自演進,而服務的部署上線和後續維護的工作,則劃歸於運維部門。這種獨立性、差異性所加大的運維複雜度需要得到收斂。

我們遇到的問題不是新問題,業界也是有不少應對的工具和方法論,但在早期,我們對運維工具的複雜性增長還是保持了一定的剋制:ssh + bash script扛過了早期的一段時光,ansible也得到過數月的應用,但現實所迫,我們最終還是投向了Docker的懷抱。

Docker是革命性的,乾淨利落的UX俘獲了技術人員的芳心,我們當時所處的時期,容器編排的大戰則正處於Docker Swarm mode發布的階段,而我們需要尋找那種工具,要既能應對日益增長的運維複雜度,也能把運維工程師從單調、重複、壓力大的發布中解放出來。

Rancher是我們在HackerNews上的評論上看到的,其簡單易用性讓我們看到了生產環境部署容器化應用的曙光,但是要真正能放心地在生產環境使用容器,不「翻車」,還是有不少工作要做。由於篇幅的原因,事無巨細的描述是不現實的。我接下來首先介紹我們當時的需求分析和技術選型,再談談幾個重要的組成部分如容器鏡像、監控報警和可靠性保障。

需求分析與技術選型

暫時拋開容器/容器編排/微服務這些時髦的詞在一邊,對於我們當時的情況,這套新的運維工具需要三個特性才能算成功:開發友好、操作可控及易運維。

開發友好

能把應用打包的工作推給開發來做,來消滅自己打包/編譯如java/ruby/python代碼的工作,但又要保證開發打出的包在生產環境至少要能運行,所以怎麼能讓開發人員方便正確地打出發布包,後者又能自動流轉到生產環境是關鍵。長話短說,我們採取的是Docker + Harbor的方式,由開發人員構建容器鏡像,通過LDAP認證推送到公司內部基於Harbor的容器鏡像站,再通過Harbor的replication機制,自動將內部鏡像同步到生產環境的鏡像站,具體實現可參考接下來的容器鏡像一節。

操作可控

能讓開發人員參與到服務發布的工作中來,由於業務線迥異的業務場景/技術棧/架構,使得只靠運維人員來解決發布時出現的代碼相關問題是勉為其難的,所以需要能夠讓開發人員在受控的情境下,參與到服務日常的發布工作中來,而這就需要像其提供一些受限可審計且易用的介面,WebUI+Webhook就是比較靈活的方案。這方面,Rancher提供的功能符合需求。

易運維

運維複雜度實話說是我們關注的核心,畢竟容器化是運維部門為適應複雜度與日俱增而發起的,屁股決定腦袋。考慮到本身容器的黑盒性和穩定性欠佳的問題,再加上真正把容器技術搞明白的人寥寥無幾,能平穩落地的容器化運維在我們這裡體現為三個需求:多租戶支持,穩定且出了事能知道,故障切換成本低。多租戶是支持多個並行業務線的必要項;容器出問題的情況太多,線上環境以操作系統鏡像的方式限定每台機器Docker和內核版本;由於傳統監控報警工具在容器化環境捉襟見肘,需要一整套新的監控報警解決方案;沒人有把握能現場調試所有容器問題(如跨主機容器網路不通/掛載點泄漏/dockerd卡死/基礎組件容器起不來),需要藍綠部署的出故障後能立刻切換,維護可靠與可控感對於一個新系統至關重要。

技術架構圖

總結一下,Rancher, Harbor, Prometheus/Alertmanager為主的開源系統組合可以基本滿足容器管理的大部分需求,總體架構如下圖

容器鏡像

容器鏡像服務是公司級別的IT基礎設施,在各個辦公區互聯帶寬有限的物理限制下,需要給分散在多個地理位置的用戶以一致、方便、快速的使用體驗。我們主要使用了Vmware開源的Harbor工具來搭建容器鏡像服務,雖然Harbor解決了如認證、同步等問題,但Harbor不是這個問題的銀色子彈,還是需要做一些工作來使鏡像服務有比較好的用戶體驗。這種體驗我們以Google Container Registry為例來展現。

作為Google的開放容器鏡像服務,全球各地的用戶都會以同一個域名gcr.io推拉鏡像docker push gcr.io/my_repo/my_image:my_tag,但其實用戶推拉鏡像的請求,由於來源地理位置不同,可能會被GeoDNS分發在不同的Google數據中心上,這些數據中心之間有高速網路連接,各種應用包括GCR會通過網路同步數據。這樣的方法既給用戶一致的使用體驗,即所有人都是通過gcr.io的域名推拉鏡像,又因為每個人都是同自己地理位置近的數據中心交互而不會太「卡」,並且由於Google Container Registry底層存儲的跨數據中心在不斷高速同步鏡像(得益於Google優異的IT基礎設施),異國他鄉的別人也能感覺很快地拉取我們推送的鏡像(鏡像「推」和「拉」的非同步性是前提條件)。

花篇幅介紹Google Container Registry的目的是,用戶體驗對用戶接受度至關重要,而後者往往是一個新服務存活的關鍵,即在公司內部提供類似GCR一般的體驗,是我們容器鏡像服務為了成功落地而想接近的產品觀感。為了達到這種觀感,需要介紹兩個核心的功能,開發/生產鏡像自動同步,鏡像跨辦公區同步。另外,雖然有點超出鏡像服務本身,但由於特殊的國情和使用關聯性,國外鏡像(DockerHub, GCR, Quay)拉取慢也是影響容器鏡像服務使用體驗的關鍵一環,鏡像加速服務也是需要的。

開發/生產鏡像自動同步

由於開發環境(公司私網),生產環境(公網)的安全性和使用場景的差異,我們部署了兩套鏡像服務,內網的為了方便開發人員使用是基於LDAP認證,而公網的則做了多種安全措施來限制訪問。但這帶來的問題是如何方便地向生產環境傳遞鏡像,即開發人員在內網打出的鏡像需要能自動地同步到生產環境。

我們利用了Harbor的replication功能,只對生產環境需要的項目才手動啟用了replication,通過這種方式只需初次上線時候的配置,後續開發的鏡像推送就會有內網Harbor自動同步到公網的Harbor上,不需要人工操作。

鏡像跨辦公區同步

由於公司在多地有辦公區,同一個team的成員也會有地理位置的分布。為了使他們能方便地協作開發,鏡像需要跨地同步,這我們就依靠了公司已有的swift存儲,這一塊兒沒有太多可說的,帶寬越大,同步的速度就越快。值得一提的是,由於Harbor的UI需要從MySQL提取數據,所以如果需要各地看到一樣的界面,是需要同步Harbor MySQL數據的。

鏡像加速

很多開源鏡像都託管在DockerHub、Google Container Registry和Quay上,由於受制於GFW及公司網路帶寬,直接pull這些鏡像,速度如龜爬,極大影響工作心情和效率。

一種可行方案是將這些鏡像通過代理下載下來,docker tag後上傳到公司鏡像站,再更改相應manifest yaml,但這種方案的用戶體驗就是像最終幻想里的踩雷式遇敵,普通用戶不知道為什麼應用起不了,即使知道了是因為鏡像拉取慢,鏡像有時能拉有時又不能拉,他的機器能拉,我的機器不能拉,得搞明白哪裡去配默認鏡像地址,而且還得想辦法把鏡像從國外拉回來,上傳到公司,整個過程繁瑣耗時低智,把時間浪費在這種事情上,實在是浪費生命。

值得一提的是,由於對gcr.io等域名在辦公區內網做了劫持,但我們手裡肯定沒有這些域名的key,所以必須用http來拉取鏡像,於是需要配置docker daemon的--insecure-registry這個項

用戶體驗

配置docker daemon(以Ubuntu 16.04為例)

sudo -s

cat /etc/docker/daemon.json

{

"insecure-registries": ["quay.io", "gcr.io","k8s.gcr.io],

"registry-mirrors": ["https://mirror.example.com"]

}

EOF

systemctl restart docker.service

測試

# 測試解析,應解析到一個內網IP地址(private IP address)

# 拉取dockerhub鏡像

docker pull ubuntu:xenial

# 拉取google鏡像

docker pull gcr.io/google_containers/kube-apiserver:v1.10.0

# 拉取quay鏡像

docker pull quay.io/coreos/etcd:v3.2

# minikube

minikube start --insecure-registry gcr.io,quay.io,k8s.gcr.io --registry-mirror https://mirror.example.com

技術架構圖

監控報警

由於zabbix等傳統監控報警工具容器化環境中捉襟見肘,我們需要重新建立一套監控報警系統,幸虧prometheus/alertmanager使用還算比較方便,並且已有的zabbix由於使用不善,導致已有監控系統的用戶體驗很差(誤報/漏報/報警風暴/命名不規範/操作複雜等等),不然在有限的時間和人員條件下,只是為了kick start而什麼都得另起爐灶,還是很麻煩的。

其實分散式系統的監控報警系統,不論在是否用容器,都需要解決這些問題:能感知機器/容器(進程)/應用/三個層面的指標,分散在各個機器的日誌要能儘快收集起來供查詢檢索及報警低信噪比、不誤報不漏報、能「望文生義」等。

而這些問題就像之前提到的,prometheus/alertmanager已經解決得比較好了:通過exporter pattern,插件化的解決靈活適配不同監控目標(node-exporter, cAdvisor, mysql-exporter, elasticsearch-exporter等等);利用prometheus和rancher dns服務配合,可以動態發現新加入的exporter/agent;alertmanager則是一款很優秀的報警工具,能實現alerts的路由/聚合/正則匹配,配合已有的郵件和我們自己添加的微信(現已官方支持)/電話(集成阿里雲語音服務),每天報警數量和頻次達到了oncall人員能接受的狀態。

至於日誌收集,我們還是遵從了社區的推薦,使用了Elasticsearch + fluentd + Kibana的組合,fluentd作為Rancher的Global Serivce(對應於Kubernetes的daemon set),收集每台機器的系統日誌,dockerd日誌,通過docker_metadata這個插件來收集容器標準輸出(log_driver: json_file)的日誌,rancher基礎服務日誌,既本地文件系統壓縮存檔也及時地發往相應的elasticsearch服務(並未用容器方式啟動),通過Kibana可視化供產品售後使用。基於的日誌報警使用的是Yelp開源的elastalert工具。

為每個環境手動創建監控報警stack還是蠻繁瑣的,於是我們也自定義了一個Rancher Catalog來方便部署。

監控報警系統涉及的方面太多,而至於什麼是一個「好」的監控報警系統,不是我在這裡能闡述的話題,Google的Site Reliability Engineering的這本書有我認為比較好的詮釋,但一個拋磚引玉的觀點可以分享,即把監控報警系統也當成一個嚴肅的產品來設計和改進,需要有一個人(最好是核心oncall人員)承擔產品經理般的角色,來從人性地角度來衡量這個產品是否真的好用,是否有觀感上的問題,特別是要避免破窗效應,這樣對於建立oncall人員對監控報警系統的信賴和認可至關重要。

技術架構圖

可靠性保障

分散式系統在提升了並發性能的同時,也增大了局部故障的概率。健壯的程序設計和部署方案能夠提高系統的容錯性,提高系統的可用性。可靠性保障是運維部門發起的一系列目的在於保障業務穩定/可靠/魯棒的措施和方法,具體包括:

● 生產就緒性檢查

● 備份管理體系

● 故障分析與總結

● chaos monkey

主要談談chaos monkey,總體思路就是流水不腐,戶樞不蠹。通過模擬各種可能存在的故障,發現系統存在的可用性問題,提醒開發/運維人員進行各種層面的改進。

預期

大多數故障無需人立刻干預

業務異常(如HTTP 502/503)窗口在兩分鐘以內

報警系統應該保證

不漏報

沒有報警風暴

報警分級別(郵件/微信/電話)發到該接收報警的人

測試樣例

我們需要進行測試的case有:

service升級

業務容器隨機銷毀

主機遣散

網路抖動模擬

Rancher基礎服務升級

主機級別網路故障

單主機機器宕機

若干個主機機器宕機

可用區宕機

部署示例(單個租戶 & 單個地域)

總 結

1、體量較小公司也可以搭建相對可用的容器平台。

2、公司發展早期投入一些精力在基礎設施的建設上,從長遠來看還是有價值的,這種價值體現在很早就可以積累一批有能力有經驗有幹勁兒的團隊,來不斷對抗規模擴大後的複雜性猛增的問題。一個「讓人直觀感覺」,「看起來」混亂的基礎技術架構,會很大程度上影響開發人員編碼效率。甚至可以根據破窗原理揣測,開發人員可能會覺得將會運行在「臟」,「亂」,」差」平台的項目沒必要把質量看得太重。對於一個大的組織來講,秩序是一種可貴的資產,是有無法估量的價值的。

3、鏡像拉取慢問題也可以比較優雅地緩解。

4、國內訪問國外網路資源總體來講還是不方便的,即使沒有GFW,帶寬也是很大的問題。而我們的解決方案也很樸素,就是緩存加本地訪問,這樣用比較優雅高效地方法解決一個「蒼蠅」問題,改善了很多人的工作體驗,作為工程人員,心裡是很滿足的。

5、容器化也可以看作是一種對傳統運維體系的重構。

6、容器化本質上是當容器成為技術架構的所謂building blocks之後,對已有開發運維解決方案重新審視,設計與重構。微服務、雲原生催生了容器技術產生,而後者,特別是Docker工具本身美妙的UX,極大地鼓舞了技術人員與企業奔向運維「應許之地」的熱情。雖然大家都心知肚明銀色子彈並不存在,但Kubernetes ecosystem越來越看起來前途不可限量,給人以無限希望。而販賣希望本身被歷史不斷證明,倒真是穩賺不虧的商業模式。

致 謝

1、感謝Richard Stallman為代表的自由軟體運動的參與者、貢獻者們,讓小人物、小公司也能有大作為。

2、感謝Google Search讓搜索信息變得如此便利。

3、感謝Docker公司及Docker軟體的貢獻者們,催生了一個巨大的行業也改善了眾多開發/運維人員的生活。

4、感謝Rancher這個優秀的開源項目,提供了如Docker般的容器運維UX。

5、感謝GitHub讓軟體協作和代碼共享如此便利和普及。

6、感謝mermaid插件的作者們,可以方便地用markdown定義編輯好看的流程圖。

Q&A

Q: 你們線上是直接用的測試環境同步的鏡像嗎?

A: 是的,這也是社區推薦的實踐,同一個鏡像流轉開發/測試/預發布/生產環境,可以預先提供一些安全/小型的base image給開發人員,做好配置文件與代碼的隔離就好。

Q:如何解決不同環境的配置問題?

A:為了保證同一個鏡像流轉開發/測試/預發布/生產環境,所以需要首先把配置與代碼分離,配置可以通過環境變數,side-kick container或者rancher-secret的方式傳入代碼所在鏡像。

Q:作為一家AI公司,是否有使用容器來給開發者構建一個機器學習的平台?

A:商湯在比較早期就開始跑分散式的深度訓練集群,當時容器/編排還不是一個feasiable的solution,對於異構的架構支持也不太好,比如nvidia gpu的device plugin也是最近才發布,所以容器還不是我們生產訓練集群的基礎技術,但是我們迭代的方向。

Q:你好,關於拉取牆外的鏡像這個地方我有點不太清楚,最終肯定還是需要一個可以翻出去的節點去拉取鏡像吧?

A:對,有多種方法做到這一點。最簡單的方法就是利用http代理的方式,網路層的vpn也可以。

Q:資料庫你們也放docker里么?現在我看到有些人也把mysql放docker里,這種方案你們研究過么?可行性如何?

A:有狀態的應用跑在容器里本身就是一個複雜的問題,kubernetes也是引入了operator pattern才在幾個有狀態的應用(etcd/prometheus)上有比較好的效果,operator的代碼量也是相對龐大的,rancher/cattle作為輕量級的解決方案,還是適合web類型的應用跑在容器里。

Q:業務整體融合到Rancher中遇到過什麼問題嗎?

A:這個問題就太寬泛了,遇到的問題有很多,技術非技術都會有,我可以講一個例子,比如java應用跑在容器里,我們就會遇到類似https://developers.redhat.com/blog/2017/03/14/java-inside-docker/這樣的問題,可以問的更具體一些。

Q:普羅米修斯的catalog能否共享一下?

A:這個catalog我們就是按Rancher官方catalog里的Prometheus改的,增加了fluentd/額外的exporter,定製了鏡像之類的,沒有什麼magic。

Q:普羅米修斯和altermanger有沒有相關文檔?

A:prometheus/alertmanager說實話,是poorly documented,alertmanager我們是代碼好好看過的,prometheus的查詢語句也是不太好寫,這一點沒啥好辦法,多看多嘗試吧。

Q:harbor裡面的鏡像,貴公司是怎麼批量刪除的?

A:目前還沒有這個剛需,但確實是需要考慮的,我這裡還沒啥想法。

Q:介面監控是怎麼做的?網路抖動用什麼模擬的?

A:介面監控我們做的比較粗糙,用的blackbox-exporter,需要手動添加,目前監控報警系統我們在深度定製中,目標是做成向opsgenie這樣的體驗;網路抖動是用https://github.com/alexei-led/pumba 這個工具做的。

Q:你們的服務可用性達到了一個什麼樣的級別呢?有沒有出現過什麼比較大的事故?

A:目前各個服務上線都不久,談可用性就比較虛了;比較大的事故的話,我們曾經遇到rancher 的一個bug(https://github.com/rancher/rancher/issues/9118),還有應用沒有好好配健康檢查,服務進程PID不為1,大量503這樣的,我們每次大的事故都會做postmortem,早期還不少的,主要是經驗和測試不夠的問題。

Q:請問prometheus用的是什麼存儲,有沒有考慮數據高可用這塊?

A:prometheus我們就是用的普通的local storage,升級就會丟失,考慮過數據高可用,後續考慮remote storage。

Q:您在分享中提到了一個alertmanage,這個產品必須配合prometheus使用嗎?

A:這不一定的,我們還用alertmanager直接接受zabbix發出的報警,alertmanager提供HTTP的介面的https://prometheus.io/docs/alerting/clients/。

Q: 請問多租戶是如何實現的?

A: 我們是利用rancher的enviroments做多租戶的,每個環境一個租戶(其實為了可靈活切換/基礎組件升級,每個租戶會有兩個幾乎一樣的環境)。

Q:生產環境上k8s的話,採用哪種部署方式比較好?

A:我覺得rancher 2.0就是一個很好的方案,很適合企業需求,部署的話rke真的蠻好使的(之前我都不信),比kubespray好使多了。

Q:普羅米修斯裡面的nodeexporter和cadvicor都是overlay網路的地址吧。如何和宿主機對應上呢?每次找起來挺費勁的。

A:這個是好問題,這兩個直接用host network,然後勾選cattle的Enable Rancher DNS service discovery這個選項,來讓rancher dns服務應用到不使用managed network的服務就好。

Q:Prometheus remote storage 你們選擇的是什麼資料庫呢?

A:remote storage我們還沒有正式使用。

Q:Elastic kibana的安全你們是怎麼做的?ELK的企業版么?

A:一般來講這個可以先在nginx里disable delete方法,再配合basic auth來做,有的team使用了searchguard這個插件。

Q:請問你們的服務暴露用service做nodeport還是ingress?

A:我們生產還沒有使用kubernetes,rancher的話可以考慮使用Kong或者rancher loadbalancer直接綁主機埠。

Q:efk的日誌數據用的什麼存儲?貴司維護rancher的團隊有多少人?

A:fluentd會在本地文件系統壓一份,再往elasticsearch打一份(配置文件里用copy這個directive),我司維護rancher的團隊為4人,但這個團隊不僅僅維護rancher,還有不少內部系統開發類、研發類的工作。

下載福利


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 RancherLabs 的精彩文章:

在Kubernetes上運行高可用的WordPress和MySQL

TAG:RancherLabs |