【編者的話】隨着Kubernetes的遍地開花,Kubernetes的優點能夠說是深刻人心,因此,咱們也掀起了一場改革,目的就是改變咱們以往的運維模式,利用Kubernetes,來實現更高效的交付和更好地提升咱們的資源使用率,推進標準化,適應雲原生。本次內容主要是:基於團隊實踐的Kubernetes落地實戰經驗分享。前端
Bravokids(百思童年)是上海百思童年母嬰用品有限公司旗下的嬰童新零售品牌公司。node
近幾年教育機器人這個概念一直炒得比較火,市場上各類產品層出不窮,可是十年樹木百年樹人,教育類產品最爲難作,要思考的東西更多。科技的不斷髮展,孩子的玩具愈來愈智能,支持編程,支持對戰,支持雲臺智能設計,手柄操控,從小玩具變成大玩具。你們都知道大疆(DJI)發佈了自家的教育機器人「機甲大師」,Bravokids也發佈了旗下的教育機器人「爆風主義遙控互動機甲 X1」,目前在小米有品App衆籌。編程
爲了更好的支撐業務的高速迭代,咱們在2018年末上線了基於Kubernetes和Docker的容器雲平臺。截止到目前,已經超過有430多個應用採用了容器部署,總實例超過4000,總共維護了8套Kubernetes集羣。本文主要介紹Kubernetes在百思落地的一些經驗和思考。後端
對接Kubernetes集羣的部署,最麻煩的地方是一堆yaml文件的編寫和管理。在這件事情的處理上咱們當時有兩個方案,一個是本身開發一個Operator來簡化配置,並作一個配置管理中心作版本管理;另外一個是尋找外部的開源方案。最終,咱們選擇了開源的Helm。由於Helm已經作好了yaml配置的簡化和版本管理,是一個極好的包管理工具。緩存
這裏大概介紹一下咱們改造後的持續交付流程,首先是GitLab收到一個push event,自動觸發Jenkins Job的Webhook進行構建。Jenkins Job中,集成了咱們的應用構建和部署相關的腳本,包括先後端代碼的build——>單元測試、代碼掃描等——>基於Dockerfile的鏡像構建——>從chart museum中拉取已寫好的helm chart template到本地進行修改,而後再推送至chartmuseum——>使用Kubeconfig與目標集羣進行交互,經過Helm Upgrade將應用部署至Kubernetes集羣。服務器
在這裏尤爲要提到,持續交付不止於提高業務交付的效率。由於曾經管理過一個應用一個Jenkins Job,深知這裏邊的痛苦。因此咱們對整個持續交付流程,作了進一步的抽象化。把構建腳本、鏡像構建、Helm Chart配置這幾個地方進行模塊化後,把全部應用的部署交付統一成一致的腳本進行部署,實現經過幾個簡單配置就能夠把一個應用對接到咱們的持續交付平臺中。這在效率提高上,相比之前真的實現了一次質的飛越。網絡
最後提一下如何對接多集羣的部署。最直接的方式,確定是經過命令行切換Context,但這種方式會相對原始一些,並且在Jenkins Slave動態生成的狀況下,還要作一些定製化配置。咱們選擇了Jenkins的Kubernetes Cli Plugin,結合Jenkins的憑證管理,實如今任何Slave上均可以一鍵進行容器編排。架構
最先咱們實際上是嘗試過自建Kubernetes集羣的,基於開源的方案基本上能知足絕大部分需求,可是若是涉及到集羣外、跨集羣的服務間調用,咱們就必須從新開發CNI插件而且在私有網絡中添加到Pod的相關路由,來打通Pod與集羣外的網絡。基於人力等方面的考慮,咱們最終選擇了TKE,Pod已實現與Node節點在同一網絡層面,促進了咱們後面的快速落地。框架
Kubernetes服務暴露的方式有三種,分別是Service的NodePort、LoadBalancer,和Ingress。咱們用的是Ingress。這個主要是由於Ingress更符合咱們利用Nginx作路由的現狀。運維
監控主要有三大塊,分別是事件監控、資源監控和調用狀況監控。前二者咱們目前尚未本身作,暫時用的是騰訊雲的監控,資源監控上加了metrics-server作加強。調用狀況監控方面沿用了之前的監控方案,在容器中集成了pinpoint-agent作APM監控。
由於本來咱們的應用日誌就有固定的目錄,固然,這得益於咱們的標準化。因此咱們的方案是使用Pod反親和性來讓同一應用部署在不一樣的Node節點上,並經過日誌落盤,在集羣中部署Filebeat DaemonSet,給日誌打上相關fields,利用Logstash切割後收集至ES集羣中,經過Kibana進行展現。
變化仍是挺多的,包括資源利用率的提升,部署上效率的提高,多環境一致性,秒級擴縮容、Jenkins Slave動態生成等等。另外,利用Kubernetes在部署上的優點,咱們在持續交付上作了相對深刻的挖掘,實現了泳道環境、平滑發佈和灰度發佈。下面分別簡單介紹下實現方式。
泳道環境,其實也叫需求環境,主要是服務於開發和測試同窗,容許他們爲某個需求建立一個相對獨立的環境。它的原理是,咱們會有一個相對穩定的環境,裏面包含了全部的服務,這個稱爲主泳道。當某個需求提出時,改動只涉及到服務A和服務B,這個時候,咱們會基於這個需求分支建立服務A和服務B,做爲泳道-01,而後結合主泳道其餘泳道-01沒有的服務,聯動起來行成一個獨立環境。
作泳道環境主要兩個難點,一個是如何實現快速部署一堆的服務,另外一個是由於咱們的業務是基於Dubbo框架的,因此須要另外實現底層Dubbo服務按需路由。第一個點在有了Kubernetes以後,快速部署已經不是難事了,結合持續交付平臺能夠快速把咱們須要的全部服務一次性deploy到集羣中。Dubbo服務路由方面,咱們利用了Dubbo的分組來實現的。最終實現後的效果以下:
平滑發佈咱們利用了deployment的的滾動更新配合Pod的Liveness和Readness探針實現的。這裏除了滾動更新的控制還須要注意兩個點,一個是舊版本Pod必須確保收到SIGTERM信號後優先關閉監聽端口從Endpoint列表中刪除,另外一個是新版本Pod加入Endpoints列表前須要通過Liveness和Readness的檢測。
之前要實現灰度發佈,通常都要手動在發佈的時候控制發佈的節點,或者經過寫一堆腳原本實現固定比例的灰度。這裏,由於咱們的服務暴露方式用的是Ingress,因此直接利用Kubernetes的Service服務發現的能力來實現灰度發佈。
總有部分應用在高峯期對CPU的要求比較高,可是CPU頻繁的上下文切換會使當前應用的CPU使用沒法獲得保障,沒法及時處理外部請求,致使客戶端出現超時。而若是集羣內服務調用沒有加熔斷機制的話,就有可能引起大量客戶端線程池打滿,進而引起雪崩效應。
這個時候,能夠對應用進行橫向擴容來緩解這種現象,但更好的方式,是使用CPUset。具體的使用方法就請你們自行查看Kubernetes相關文檔啦。
注意:內存和CPU的limits和requests都必須相等。
由於Ingress Controller是整個集羣的流量入口,使用nodeSelector把Ingress Controller進行獨立調度,只對外暴露這幾臺服務器做爲流量入口。這裏要特別注意客戶端的短鏈接問題,由於短鏈接到達service所在服務器後,會再次向後端發起一次流量轉發,不管是使用iptables實現的仍是IPVS的都同樣,向後傳遞短鏈接後,外部一個短鏈接,到集羣裏就變成兩個短鏈接了。因此要麼增大nf_conntrack相關參數的容量,要麼把短鏈接變成長鏈接,避免出現連接跟蹤表溢出的問題。
使用podAntiAffinity主要是爲了不單點故障。由於即便在集羣中部署了多個實例,若是全部實例都在一臺服務器上,由於服務器故障或者某些緣由觸發驅逐策略的時候,依舊會引起短時間的服務不可用。
兩個方向吧,一個是平臺化,另外一個是資源進行精細化調配。
先說平臺化,由於目前絕大部分業務都已經容器化了,內部已經有了多個線上集羣,急需一個集中的平臺來把多個集羣管起來、各個流程串起來。平臺化的內容主要是監控、日誌、發佈和集羣管理這些。資源的精細化調配方面,是由於目前咱們的調度策略主要仍是利用原生的調度策略,小部分利用CPUset作綁核操做。可是整個集羣的內存利用率和CPU使用率並非在一個水平線上,這方面還有比較大的可壓縮空間。
Q:請問LNMP網站架構容器化上Kubernetes、Nginx和PHP,是各設Pod吧?MySQL採用一主多從架構?用什麼作存儲?
A:LNMP建議是Nginx和PHP放在同一個Pod中,而後外層再加一個Nginx,作Upstream。MySQL應用上Kubernetes要用StatefulSet。不過咱們目前內部這一塊是尚未遷移到Kubernetes集羣中的。
Q:Pod的滾動更新(優雅重啓)怎麼作的?
A:滾動更新Kubernetes的deployment中有相關的rollingUpdate策略,優雅停機有兩個注意的點,一個是咱們要確保應用發的SIGTERM信號,另外一個是代碼要確保收到SIGTERM信號後優先關閉端口或者取消服務註冊。
Q:Harbor的使用版本?鏡像的後端存儲是什麼?Harbor的部署形態?
A:Harbor使用版本這裏不方便說。很差意思哈。鏡像後端存儲咱們目前用的是騰訊雲的CFS,性能上目前夠用。Harbor部署形態,我大概描述一下:ng/lb反向代理到後端Harbor,Harbor存儲用騰訊雲的CFS。
Q:除開Kubernetes自身的監控,容器內部服務監控是如何作的?pinpoint-agent嵌入到Container裏面有沒有須要優化的地方?
A:容器內部服務監控咱們是用Pinpoint作APM監控。pp-agent嵌入到Container裏邊有沒有須要優化的地方,這個還好,由於咱們目前這一塊都是作在基礎鏡像裏邊的,啓動的時候加啓動參數就好,步驟也挺簡單的。
Q:請問前端是怎麼暴露在外面的,SSL證書怎麼才能作到自動簽發?
A:前端靜態資源暴露咱們有兩種吧。一種是直接放在ng靜態資源目錄裏邊而後加上CDN,另一種是放在Kubernetes集羣中,前面Nginx作反向代理,配上靜態資源相關的緩存策略。SSL證書自動簽發,Kubernetes集羣內咱們目前用的是託管類型的,因此這一塊未涉及。集羣外其餘SSL證書未作自動簽發的證書。
Q:GitLab接收一個push event觸發構建,這個是監控全部的分支嗎,分支模型是怎麼樣的?
A:不是的,按需。咱們內部分支模型大概有四種,dev——>test——>release——>master。master之外的爲了效率都會作自動觸發。
Q:請問規模是?大概多少Node,會跨不少集羣嗎?
A:咱們內部的集羣規模,生產集羣數量是4個,不過是有大有小,是按業務來劃分的。最大的一個集羣是2700G內存,Node節點將近50個。Node節點數量要根據每一個節點配置來看,配置高,節點數量就少。
Q:爲何不直接用GitLab-Runner而接Jenkins?
A:GitLab-Runner須要每一個倉庫都配置構建信息,當須要統一修改構建的時候很麻煩。
Q:「Pod已實現與Node節點在同一網絡層面,促進了咱們後面的快速落地。」這個是什麼需求?
A:原生的Kubernetes集羣跨集羣調用網絡上默認是不通的。
Q:請問Dubbo在轉向Kubernetes或Istio網格化改造過程當中,傳統環境與容器化環境共存互相調用時,是否遇到什麼坑?如何化解的?
A:網段衝突吧。咱們曾經作過一段時間的Docker單機,可是當時沒有配置Docker的網段,致使後面衝突的時候出現網絡不通。解決方案:指定Docker單機的網段。
Q:在CD的過程當中 ,版本管理是怎麼作的 ?是基於鏡像的tag仍是Helm的版本?包括回滾的策略與方式?
A:用的是Helm的版本管理,回滾策略和方式都是用Helm的。
Q:HPA具體是咋作的,根據什麼指標擴縮容的?集羣升級咋作的?
A:HPA是根據CPU作的。集羣升級是先升級Master再升級Node節點,這個仍是按照TKE的來作。
Q:Ingress Controller節點上的短鏈接問題,短鏈接變長鏈接這個是怎麼處理的?能提示一下嗎? A:這個不是指通Ingress Controller去作短鏈接變長鏈接,是說客戶端發起的鏈接要用長鏈接的意思。