Knative 系列(三):Serving篇

前一篇文章已經介紹了Build的使用方式和原理,本文將緊接上文介紹Serving。

簡而言之,Serving 提供了Serverless應用或函數(Function)的部署能力,並通過 istio 實現服務管理,提供容器擴縮容能力。接管應用的部署和運維,節省開發者在應用部署和運維上消耗的精力。同時,在應用運維方面,Serving提供了根據應用訪問量自動擴縮容的能力,在沒有訪問的時候能把應用實例縮減到0,本文通過將Serving部署到K8s平臺之上試用,以講解這一組件的原理。

Serving部署

安裝istio

安裝Serving之前,我們需要先安裝istio,這裏使用Knative提供的簡易方式安裝。

kubectl apply --filename https://raw.githubusercontent.com/knative/serving/release-0.6/third_party/istio-1.1.3/istio-crds.yaml \   
--filename https://raw.githubusercontent.com/knative/serving/release-0.6/third_party/istio-1.1.3/istio.yaml   

安裝Serving

Serving可以單獨部署,但是也可以和Build一起部署,我們先來看Serving單獨部署模式:

kubectl apply --selector   knative.dev/crd-install=true \   
--filename https://github.com/knative/serving/releases/download/v0.6.0/serving.yaml  --selector   networking.knative.dev/certificate-provider!=cert-manager  

執行成功以後,可以通過以下命令查看:

kubectl get pods   --namespace knative-serving 

當pod全部正常執行後,我們就可以開始使用Serving。

Serving概念和試用

概念

Knative把應用裏的所有能力全都放到統一的CRD資源中管理—Service。這裏的Service與K8s原生用戶訪問的Service不同,這是Knative的自定義資源,管理Knative應用的整個生命週期。

  • Service:service.serving.knative.dev資源管理着工作負載的整個生命週期。它控制其他對象(Route、Configration、Revison)的創建,並確保每次對Service的更新都作用到其他對象。

  • Route: route.serving.knative.dev資源將網絡端點映射到一個或多個Revision。可以通過配置Route實現多種流量管理方式,包括部分流量和命名路由。

  • Configuration:configuration.serving.knative.dev資源保持部署所需的狀態。它提供了代碼和配置之間的清晰分離,並遵循十二要素應用程序方法。修改Configuration將創建新的Revision。

  • Revision:revision.serving.knative.dev資源是對工作負荷所做的每個修改的代碼和配置的時間點快照。修訂是不變的對象,只要有用就可以保留。Revision可以根據進入的流量自動擴縮容。

樣例

現在讓我們來看一個最簡單的Knative Service樣例:

apiVersion:   serving.knative.dev/v1alpha1   
kind: Service   
metadata:     
name: autoscale-go     
namespace: default   
spec:     
template:       
metadata:         
annotations:           
# Target 10 in-flight-requests per   pod.           
autoscaling.knative.dev/target:   "10"       
spec:         
containers:         
- image:   gcr.io/knative-samples/autoscale-go:0.1

可以發現,一個Service相當簡潔,在最簡單的模式下只需要填寫一個鏡像即可,其他都會默認填充。現在把這個樣例創建到集羣中,並查看它自動創建的資源。

kubectl apply --filename https://raw.githubusercontent.com/knative/docs/release-0.6/docs/serving/samples/autoscale-go/service.yaml   
kubectl get serving.knative.dev 

創建Service之後,自動創建Configuration、Route、Revision、Deployment等資源。

自動擴縮容

接下來測試Service的自動擴縮容功能,在上文例子中,annotations裏面設置了每個Pod的請求併發數爲10。

INGRESSGATEWAY=istio-ingressgateway   
export IP_ADDRESS=`kubectl get svc   $INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*].ip}"`      
hey -z 30s -c 50 \      
 -host "autoscale-go.default.example.com" \      
 "http://${IP_ADDRESS?}?sleep=100&prime=10000&bloat=5"   \       
&& kubectl get pods   
Summary:       
Total:        30.3379 secs       
Slowest:      0.7433 secs       
Fastest:      0.1672 secs       
Average:      0.2778 secs       
Requests/sec: 178.7861          
Total data:   542038 bytes       
Size/request: 99 bytes      
Response time histogram:      
0.167 [1]     \|       
0.225 [1462]    \|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■       
0.282 [1303]  \|■■■■■■■■■■■■■■■■■■■■■■■■■■■■       0.340 [1894]    \|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■      
 0.398 [471]   \|■■■■■■■■■■       
0.455 [159]   \|■■■       
0.513 [68]    \|■      
0.570 [18]    \|       
0.628 [14]    \|       
0.686 [21]    \|       
0.743 [13]    \|      
Latency distribution:       
10% in 0.1805 secs       
25% in 0.2197 secs       
50% in 0.2801 secs       
75% in 0.3129 secs       
90% in 0.3596 secs       
95% in 0.4020 secs       
99% in 0.5457 secs      
Details (average, fastest, slowest):       
DNS+dialup:   0.0007 secs,   0.1672 secs, 0.7433 secs       
DNS-lookup:   0.0000 secs,   0.0000 secs, 0.0000 secs       
req write:    0.0001 secs,   0.0000 secs, 0.0045 secs       
resp wait:    0.2766 secs,   0.1669 secs, 0.6633 secs       
resp read:    0.0002 secs,   0.0000 secs, 0.0065 secs      
Status code distribution:       
[200] 5424 responses   NAME                                             READY   STATUS      
RESTARTS   AGE   
autoscale-go-00001-deployment-78cdc67bf4-2w4sk   3/3       Running   0          26s   
autoscale-go-00001-deployment-78cdc67bf4-dd2zb   3/3       Running   0          24s   
autoscale-go-00001-deployment-78cdc67bf4-pg55p   3/3       Running   0          18s   
autoscale-go-00001-deployment-78cdc67bf4-q8bf9   3/3       Running   0          1m   
autoscale-go-00001-deployment-78cdc67bf4-thjbq   3/3       Running   0          26s 

以50qps去訪問autoscale-go時,autoscale-go自動從1個實例擴展到5個實例, 剛好和我們設置的併發匹配。

當我們等待一段時間不訪問autoscale-go後再去獲取實例數量,可以看到實例數被縮減到0。

kubectl get pods   
NAME                                          READY   STATUS    RESTARTS     AGE 

多版本管理

這次,換個應用,我們先創建一個Service:

cat >   stock.yaml << EOF   
apiVersion: serving.knative.dev/v1alpha1   
kind: Service  
metadata:     
name: stock-service-example     
namespace: default   spec:     
template:       
metadata:         
name: stock-service-example-first       
spec:         
containers:         
- image: ${REPO}/rest-api-go          
env:             
- name: RESOURCE               
value: stock           
readinessProbe:             
httpGet:               
path: /             
initialDelaySeconds: 0             
periodSeconds: 3     
traffic:     
- tag: current       
revisionName: stock-service-example-first       
percent: 100     
- tag: latest       
latestRevision: true   	
percent: 0   
EOF   
kubectl create -f   stock.yaml 

這個Service配置了流量信息,但是第一次創建時,我們先把所有的流量都導到Revision:stock-service-example-first上。

之後修改Service,另起創建新的Revision,並將一半流量切換到新的Revision。

cat >   stock.yaml << EOF   
apiVersion:   serving.knative.dev/v1alpha1   
kind: Service   
metadata:     
name: stock-service-example     
namespace: default   
spec:     
template:       
metadata:         
name: stock-service-example-second       
spec:         
containers:         
- image: ${REPO}/rest-api-go           
env:             
- name: RESOURCE               
value: share           
readinessProbe:             
httpGet:               
path: /             
initialDelaySeconds: 0             
periodSeconds: 3     
traffic:     
- tag: current       
revisionName: stock-service-example-first       
percent: 50     
- tag: candidate       
revisionName:   stock-service-example-second       
percent: 50     
- tag: latest       
latestRevision: true       
percent: 0   
EOF   
kubectl create -f   stock.yaml   

接着,我們通過域名訪問Service,多次的結果分別爲Welcome to the share app! 或者 Welcome to the stock app!,比例大致爲各一半。

 curl   --header "Host: stock-service-example.default.example.com"  
 http://${INGRESS_IP}  

Serving原理

Serving總共有5個組件,其中4個在knative-serving這個namespace下面,是controller 、webhook 、autoscaler、activator這四個組件;還有一個queue, 運行在每個應用的pod裏,作爲pod的sidecar存在。

1.  Controller負載Service整個生命週期的管理,涉及、Configuration、Route、Revision等的CURD。
2.  Webhook主要負責創建和更新的參數校驗。
3.  Autoscaler根據應用的請求併發量對應用擴縮容。
4.  Activator 在應用縮容到0後,攔截用戶的請求,通知autoscaler啓動相應應用實例,等待啓動後將請求轉發。
5.  Queue負載攔截轉發給Pod的請求,用於統計Pod的請求併發量等,autoscaler會訪問queue獲取相應數據對應用擴縮容。

自動擴縮容
   
1->n: 任何訪問應用的請求在進入Pod後都會被Queue攔截,統計當前Pod的請求併發數,同時Queue會開放一個metric接口,autoscalor通過訪問該端口去獲取Pod的請求併發量並計算是否需要擴縮容。當需要擴縮容時,autoscalor會通過修改Revision下的deployment的實例個數達到擴縮容的效果。
   
0->1: 在應用長時間無請求訪問時,實例會縮減到0。這個時候,訪問應用的請求會被轉發到activator,並在請求在轉發到activator之前會被標記請求訪問的Revision信息(由controller修改VirtualService實現)。activator接收到請求後,會將改Revision的併發量加1,並將metric推送給autoscalor,啓動Pod。同時,activator監控Revision的啓動狀態,Revision正常啓動後,將請求轉發給相應的Pod。
   
當然,在Revision正常啓動後,應用的請求將不會再發送到activator,而且直接發送至應用的Pod(由controller修改VirtualService實現)。

Knative網絡模式

網絡模式分兩個部分,一個爲Service之間的訪問,一個爲外部訪問。

Service之間的訪問:

  • istio會解析Knative Service的VirtualService下發給各個Pod的Envoy,當應用通過域名相互訪問時,Envoy會攔截請求直接轉發給相應的Pod。

外部訪問:

  • 如果是在集羣外訪問,素喲有的請求入口爲ingressgateway,ingressgateway將請求根據訪問域名轉發到應用。

  • 如果是在集羣節點上訪問,每個Knative Service都對應一個k8s Service, 這個Service的後端都爲ingressgateway,ingressgateway會根據訪問域名轉發到應用。

總結

Knative的Serving在istio基礎上,實現應用的簡易部署和多版本管理,把開發人員從應用的部署和運維中真正的解放出來;同時動態擴縮容能力避免了資源冗餘造成的浪費,有效節省應用成本。

相關文章:

《Knative 系列(一):基本概念和原理解讀》
《Knative 系列(二):兵馬未動糧草先行之 Build 篇》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章