AI獨角獸商湯科技的內部服務容器化歷程
搜索微信號RancherLabsChina,或文末掃碼,添加Rancher小助手為好友,可加入官方技術交流群,實時參加下一次分享~
內容目錄
● 背景 ● 需求分析與技術選型 ● 容器鏡像 ● 監控報警 ● 可靠性保障 ● 總結 背 景 商湯科技是一家計算機視覺領域的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,但這種方案的用戶體驗就是像最終幻想裏的踩雷式遇敵,普通用戶不知道為什麽應用起不了,即使知道了是因為鏡像拉取慢,鏡像有時能拉有時又不能拉,他的機器能拉,我的機器不能拉,得搞明白哪裏去配默認鏡像地址,而且還得想辦法把鏡像從國外拉回來,上傳到公司,整個過程繁瑣耗時低智,把時間浪費在這種事情上,實在是浪費生命。 我們采取的方案是,用mirror.example.com的域名來mirror DockerHub,同時公司nameserver劫持quay,gcr,這樣用戶只需要配置一次docker daemon就可以無痛拉取所有常用鏡像,也不用擔心是否哪裏需要override拉取鏡像的位置,而且每個辦公區都做類似的部署,這樣用戶都是在辦公區本地拉取鏡像,速度快並且節約寶貴的辦公區間帶寬。 值得一提的是,由於對gcr.io等域名在辦公區內網做了劫持,但我們手裏肯定沒有這些域名的key,所以必須用http來拉取鏡像,於是需要配置docker daemon的--insecure-registry這個項 用戶體驗 配置docker daemon(以Ubuntu 16.04為例) 測試sudo -s
cat << EOF > /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定義編輯好看的流程圖。
AI獨角獸商湯科技的內部服務容器化歷程