SDMK(Smart Data Market)是TalkingData的數據智能市場,該平臺提供了多樣化的數據服務,包含API服務、SaaS服務以及Lookalike、預測引擎等人工智能算法模型服務,目地在於下降數據應用場景的難度,幫助更多的企業發現數據的深層價值。java
SDMK數據平臺是採用微服務架構來設計實現的,主要APP模塊近二十幾個,再加上第三方數據服務的適配器以及其它APP模塊近七十多個,提供的REST API近成百上千個。微服務架構的應用使得每一個服務均可以有專門的開發團隊(或我的)來開發,開發者能夠自由選擇開發技術,而且每一個微服務均可以獨立開發、升級、拓展。所以系統具有很高的穩定性和快速迭代能力,但同時也會遇到一些問題,如負載均衡、故障重啓、彈性伸縮、資源隔離等等。node
由於一個微服務背後可能有多個副本實例在支撐,如何作到自動負載均衡?當其中一個副本實例宕機了,是否須要人工重啓?當流量增長的時候,如何方便或者自動的增長節點,以知足相應的SLA?面對以上等等的這些問題,Kubernetes(K8s)可以很好解決,從而也使其成爲企業微服務容器化的首選解決方案。nginx
本文將簡單介紹K8s核心概念,並重點介紹TalkingData SDMK採用K8s的容器化部署實踐。redis
首先,Kubernetes(K8s)是自動化容器操做的開源平臺,這些操做包括部署、調度和節點集羣間擴展。若是你曾經用過Docker容器技術部署容器,那麼能夠將Docker當作Kubernetes內部使用的低級別組件。Kubernetes不只僅支持Docker,還支持另外一種容器技術Rocket。算法
使用Kubernetes能夠:docker
Master數據庫
集羣擁有一個K8s Master(上圖中紫色方框)。K8s Master提供集羣的獨特視角,而且擁有一系列組件,好比K8s API Server。API Server提供能夠用來和集羣交互的REST 接口。Master節點包括用來建立和複製Pod的Replication Controller。apache
Node後端
Node做爲集羣中的工做節點,運行真正的應用程序,在Node上K8s管理的最小運行單元是Pod。Node上運行着K8s的Kubelet、kube-proxy服務進程,這些服務進程負責Pod的建立、啓動、監控、重啓、銷燬、以及實現軟件模式的負載均衡。節點(上圖橘色方框)是物理或者虛擬機器,做爲K8s worker,一般稱爲Minion。每一個節點都運行以下K8s關鍵組件:api
Pod
Pod是K8s最基本的操做單元,包含一個或多個緊密相關的容器,一個Pod能夠被一個容器化的環境看做應用層的「邏輯宿主機」;一個Pod中的多個容器應用一般是緊密耦合的,Pod在Node上被建立、啓動或者銷燬;每一個Pod裏運行着一個特殊的被稱之爲Pause的容器,其餘容器則爲業務容器,這些業務容器共享Pause容器的網絡棧和Volume掛載卷,所以他們之間通訊和數據交換更爲高效,在設計時咱們能夠充分利用這一特性將一組密切相關的服務進程放入同一個Pod中。
Pod的生命週期經過Replication Controller來管理,經過模板進行定義,而後分配到一個Node上運行,在Pod所包含容器運行結束後,Pod結束。K8s爲Pod設計了一套獨特的網絡配置,包括:爲每一個Pod分配一個IP地址,使用Pod名做爲容器間通訊的主機名等。
RC(Replication Controller)
RC就是複製控制器,新一代的RC叫RS(Replication Set)其主要功能以下:
Labels
Labels以key/value的形式附加到各類對象上,如Pod、Service、RC、Node等,以識別這些對象,管理關聯關係等,如Service和Pod的關聯關係,有了這種關聯關係,就能夠經過選擇器(Selector)來進行篩選那個服務和那個Pod進行關聯。
Label selectors
經過label selectors,用戶能夠識別一些對象,它是K8s的核心Grouping Primitive。其選擇器主要有如下兩種:
Deployment
部署表示用戶對K8s集羣的一次更新操做。部署是一個比RS應用模式更廣的API對象,能夠是建立一個新的服務,更新一個新的服務,也能夠是滾動升級一個服務。滾動升級一個服務,實際是建立一個新的RS,而後逐漸將新RS中副本數增長到理想狀態,將舊RS中的副本數減少到0的複合操做;這樣一個複合操做用一個RS是不太好描述的,因此用一個更通用的Deployment來描述。以K8s的發展方向,將來對全部長期伺服型的的業務的管理,都會經過Deployment來管理。
Service
RC、RS和Deployment只是保證了支撐服務的Pod的數量,可是沒有解決如何訪問這些服務的問題。一個Pod只是一個運行服務的實例,隨時可能在一個節點上中止,在另外一個節點以一個新的IP啓動一個新的Pod,所以不能以肯定的IP和端口號來提供服務。要穩定地提供服務須要服務發現和負載均衡能力。服務發現完成的工做,是針對客戶端訪問的服務,找到對應的後端服務實例。在K8s集羣中,客戶端須要訪問的服務就是Service對象。每一個Service會對應一個集羣內部有效的虛擬IP,集羣內部經過虛擬IP訪問一個服務。在K8s集羣中服務的負載均衡是由Kube-proxy實現的。Kube-proxy是K8s集羣內部的負載均衡器。它是一個分佈式代理服務器,在K8s的每一個節點上都有一個;這一設計體現了它的伸縮性優點,須要訪問服務的節點越多,提供負載均衡能力的Kube-proxy就越多,高可用節點也隨之增多。
1、服務暴露實踐
上文概念中所說Service一般只是集羣內部有效,在K8s的世界裏,服務要對集羣外暴露,一般有這麼幾種方式:
1. Cluseter IP
集羣內的私有IP,這是默認值。
2. NodePort Service
其實質上是經過在集羣的每一個node上暴露一個端口,而後將這個端口映射到某個具體的service來實現的,雖然每一個node的端口不少,但因爲安全性和易用性(服務多了就亂了,易產生端口衝突),實際使用的並很少。
3. LoadBalancer Service
是K8s深度結合雲平臺的一個組件,當使用LoadBalancer service暴露服務時,其實是經過底層平臺申請建立一個負載均衡器來向外暴露服務的。這種方式多數應用於雲平臺上來使用。
4. Ingress Service
經過Ingress用戶能夠實現使用nginx等開源的反向代理負載均衡器實現對外暴露服務。它包含有三個組件:反向代理負載均衡器、Ingress Controller、Ingress。
SDMK部署就是採用的Ingress這種方式。在K8s集羣中,Ingress 是受權入站鏈接到達集羣服務的規則集合,爲其提供七層負載均衡能力,從而能夠經過 Ingress 配置提供外部可訪問的 URL、負載均衡、SSL、基於名稱的虛擬主機等。
SDMK在部署的時候主要考慮瞭如下兩種部署方式:
01共享Ingress
如上述部署架構圖,全部的服務共享一個Ingress實例,該實例做爲集羣全部服務的流量入口,但問題就是,一旦流量入口出現問題,例如性能問題、可用性問題等,就會影響集羣內全部服務的可用性。
02獨佔Ingress
如上述部署架構圖,由多個獨佔 Ingress 實例組成統一接入層承載集羣入口流量,每一個微服務模塊獨佔一個Ingress,同時也可依據後端業務流量水平擴縮容 Ingress 節點。固然若是前期的集羣規模並不大,也能夠採用將 Ingress 服務與業務應用混部的方式,但建議進行資源限制和隔離。
做爲集羣流量入口,Ingress的高可靠性顯得尤其重要,出於這樣的考慮,SDMK採用獨佔Ingress的同時,並將nginx-ingress-controller採用多副本部署的方式以及將其與後端service進行資源隔離,這樣能夠避免業務應用與 Ingress 服務發生資源爭搶,以及單點的問題。
2、彈性伸縮實踐
在K8s中,Pod是最基礎的調度單位,多個Pod 能夠組成一個集合,這個集合向外提供服務。這時候,有如下兩種情形須要關注:
若是人肉來實時監控實例的運行狀態,手動啓動新的Pod以替代fail的Pod,監控實例的負載狀況,手動建立或者刪除Pod,這個工做繁瑣且工做量大,好在K8s已經有相應的機制來應對這種變化,這個機制就是彈性伸縮。
彈性伸縮式一種根據資源使用狀況自動伸縮工做負載的方法。彈性伸縮在K8s中有兩個維度:Cluster Autoscaler 和 Horizontal Pod Autoscaler ,兩者一塊兒可用於動態調整計算能力以及並行性的水平擴展能力,從而知足系統的SLA。Cluster Autaoscaler 依賴於託管集羣的雲提供商的底層功能,HPA就能夠獨立於Iaas/Paas提供商進行操做了。
簡單的來說,就是HPA實現了一個控制環,能夠週期性的經過資源指標API查詢特定應用的CPU、MEM等信息,而Metrics server 負責收集各個應用Pod的指標信息,再經過控制器的計算,從而實現彈性伸縮。當前主要的指標分爲如下三種:
計算的算法:
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
例如:
currentMetricValue 爲 200m, desiredMetricValue 爲100m ,那麼副本的個數就會翻倍,前提是不超過你設置的最大值,若是超過,就把最大值做爲當前的目標副本數目。若是算出來的值爲0.5,就大於等於該數的最小整數。
在這裏要說明是注意你所採用的K8s版本:
在K8s v1.1中首次引入了HPA特性,其第一個版本基於觀察到的CPU利用率,後續版不斷髮展,也支持了基於內存使用。在K8s 1.6中引入了一個新的API自定義指標API,它容許HPA訪問任意指標。在K8s1.7引入了聚合層,容許第三方應用程序經過註冊爲API附加組件來擴展K8s API。自定義指標API以及聚合層使得像Prometheus這樣的監控系統能夠向HPA控制器公開特定於應用程序的指標。
實踐部分
須要在Deployment 的yaml文件中定義每一個APP使用的資源狀況,至於資源的限制大小須要根據實際的業務需求而定,並添加上對應探針策略。
1apiVersion: autoscaling/v2beta1 2kind: HorizontalPodAutoscaler 3metadata: 4 name: dm-sdmk-kafka-service 5 namespace: dm 6spec: 7 scaleTargetRef: 8 apiVersion: extensions/v1beta1 9 kind: Deployment 10 name: dm-sdmk-kafka-service 11 minReplicas: 3 12 maxReplicas: 5 13 metrics: 14 - type: Resource 15 resource: 16 name: cpu 17 targetAverageUtilization: 50 18 - type: Resource 19 resource: 20 name: memory 21 targetAverageValue: 1536Mi
HPA的實現須要在HorizontalPodAutoscaler 的Yaml文件的定義具體彈性伸縮條件以及閾值,即最少的Pod個數、最多的Pod個數,根據什麼條件來伸縮,例如CPU平均利用率達到50%,或者內存平均使用超過1536M等,當相應服務的監控條件達到對應的閾值時,就會伸縮Pod。具體的設置要根據相應業務模塊類型來進行設置。SDMK在部署的時候多數根據內存條件來進行伸縮的,由於多數的APP應用在流量上來的時候消耗內存比較多。
3、引流實踐
當K8s環境下的SDMK已經部署完畢,並通過簡單測試,處於可用狀態,如今想將特定用戶的流量引入到K8s環境下的SDMK,從而使其可以承擔起必定的業務流量,達到物理機環境下的SDMK與K8s環境下的SDMK混合部署效果,如上圖所示。
01物理機部署
如上圖所示,原理物理機上的部署,是經過物理機上nginx作負載均衡的,下面掛載多個物理機上Gateway(網關)節點,Gateway是SDMK的一個網關,用於接收並處理服務調用請求的。
01並行部署
並行部署就如上圖所示,將K8s環境的入口域名以Location的方式也掛載在nginx下,在nginx處來將流量區分開來,哪些用戶的流量打到K8s環境,哪些用戶的流量打到物理機環境。SDMK是經過在nginx中添加lua腳原本實現的,其部署狀況以下圖所示:
實現步驟:
實踐部分
Lua腳本實現腳本:
1local _M = {} 2_M._VERSION = ‘0.01’ 3local function tryExec(prod,gray) 4local redis = require ‘redis’ 5local red = redis.connect(‘172.20.33.5’, 6379, 0.2) 6token = ngx.req.get_headers()["userId"] 7if token == nil then 8 return prod 9end 10 11local temp , userId = token:match("([^,]+)-([^,]+)") 12local res = red:get(userId) 13if not res then 14 return prod 15end 16 17if res == ngx.null then 18 return prod 19else 20 return gray 21end 22end 23 24 25function _M.execByToken(prod,gray) 26local ok , msg = pcall(tryExec,prod,gray) 27if ok then 28ngx.exec(msg) 29else 30ngx.exec(prod) 31end 32end 33return _M
Nginx中添加配置:
1location /data { 2 set $target ''; 3 set $header_host $host; 4 access_by_lua ' 5 package.path = "/usr/local/nginx/conf/lua/?.lua" 6 local sdmk = require "sdmk" 7 ngx.var.target=sdmk.tryExec("dmkdataProd","dmkdataK8s") 8 if ngx.var.target == "dmkdataK8s" then 9 ngx.var.header_host = "nginx-dm-talkingdata-datamarket-gateway-k8s.dm.svc.sc.tendcloud.com" 10 end 11 '; 12 13 proxy_http_version 1.1; 14 proxy_set_header Connection ""; 15 proxy_set_header Host $header_host; 16 proxy_set_header X-Real-IP $remote_addr; 17 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 proxy_set_header X-Forwarded-Server $host; 19 proxy_pass http://$target; 20 }
這裏須要注意的是須要在header_host中將域名帶到K8s環境中。
4、注意事項
1.容器優雅關閉的問題
容器是否可以進行優雅的關閉,接收到SIGTERM信號,而非直接殺掉,從而使得應用程序中可以有效的處理數據、釋放資源等,不然就有可能出現數據丟失等現象。
2.數據庫訪問限制
生產環境的數據庫都有相應的訪問限制,當前SDMK的數據庫訪問限制,是經過受權IP段形式來實現的。
3.Nginx-ingress-Controller的性能問題
不管採用共享Ingress的方式,仍是採用獨佔Ingress方式,都須要在上生產環境以前進行壓測一番,看是否可以知足系統的要求。
4.資源限制問題
5.HPA的設置條件,應當根據應用程序特定需求,來設置彈性伸縮條件
6.特殊鏡像新需求
7.建議容器探針必定要加
8.Nginx引流訪問K8s環境域名
本文做者:TalkingData 楊雙亮