serverless knative实战
1、部署一個service應用
在部署第一個Knative Service之前,我們先了解一下它的部署模型和對應的Kubernetes資源。如圖6-2所示,在部署Knative Serving Service的過程中,Knative Serving控制器將創建configuration、Revision和Route三個資源對象。
配置(configuration):Knative configuration維護了部署的目標狀態,提供了一個干凈的代碼和配置分離、遵循12要素開發原則的機制。基于目標狀態,Knative configuration控制器為應用創建了一個新的Kubernetes部署應用。并且configuration的變更會體現在一個新的Kubernetes部署應用中。
修訂版(Revision):Knative configuration遵循12要素開發原則,每次應用的變更將會創建一個新的Knative Revision。Revision類似于版本控制中的標簽。Revision一旦創建,是不可改變的。每個Revision都有一個對應的Kubernetes Deployment。它允許將應用程序回滾到任何正確的最新配置。
路由(Route):Knative Route是訪問Knative Service的URL。
接下來分別以java和node為例創建一個簡單的web服務。該服務接收到HTTP GET請求時,會根據環境變量Target傳遞的內容向Response輸出Hello$TATGET!內容。
1.1、制作service鏡像
java
啟動訪問
./mvnw package && java -jar target/helloworld-0.0.1-SNAPSHOT.jarnodejs
制作鏡像和推送鏡像和java環境一樣。
注意應用程序和docker暴露端口必須是8080,否則會部署失敗。新版可以在service的yml中指定端口號。
1.2 部署應用
可以采用二種方式部署應用:
- yaml
- kn
創建service.yml,image指定為上一步制作的鏡像,文件如下:
apiVersion: serving.knative.dev/v1 kind: Service metadata:name: helloworld-java-springnamespace: default spec:template:spec:containers:- image: docker.io/{username}/helloworld-java-springenv:- name: TARGETvalue: "Java Spring Sample v1"利用kubectl部署
kubectl apply --filename service.yaml在創建服務期間,Knative 會執行以下步驟:
- 為此版本的應用程序創建一個新的不可變修訂版。
- 為您的應用程序創建路由、入口、服務和負載平衡。
- 自動向上和向下擴展您的 pod,包括縮小到零活動 pod。
1.3 驗證
可以采用二種方式驗證:
- kubectl
- kn
顯示
NAME URL helloworld-java-spring http://helloworld-java-spring.default.1.2.3.4.sslip.io顯示
http://helloworld-java-spring.default.1.2.3.4.sslip.io訪問:
curl http://helloworld-java-spring.default.1.2.3.4.sslip.io Hello Java Spring Sample v1! # Even easier with kn: curl $(kn service describe helloworld-java-spring -o url)1.4 刪除service
1.4 更新Knative Service configuration
在部署完一個Knative Service后,我們會因為應用版本的升級、配置的變更等需要更新現有服務的configuration。Knative服務還提供了一種機制實現回滾變更。
12要素應用設計原則規定,應用程序與配置的變更應被視為一個新的修訂版。修訂版是不可變更的應用和配置的狀態集合。它可以讓你回滾到任何一個有效的修訂版狀態。
應用的更新包括容器鏡像的更新、健康檢查探針的調整、環境變量的變更。這些變更會導致Knative生成新的修訂版。每一個新修訂版將創建一個新的Kubernetes Deployment對象。
接下來,我們通過一個更新服務配置的示例來演示配置的變更。
配置文件(service.yaml)的變更如下。
1)更新修訂版的名稱(.spec.template.metadata.name)為helloworld-go-v2,區別于上一個修訂版名稱helloworld-go-v1。
2)更新環境變量TARFET(.spec.template.spec.containers[0].env[0].value)的值為Go Sample v2。
將配置更新到Knative:
檢查部署結果:
# kubectl get ksvc helloworld-go NAME URL LATESTCREATED LATESTREADY READY REASON helloworld-go http://helloworld-go. helloworld-go-v2 helloworld-go-v2 Truedefault.example.com通過curl命令訪問helloworld-go服務:
##獲取集群任一節點的IP地址和nodePort端口 # IP_ADDRESS="$(kubectl get nodes-o 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc istio-ingressgateway--namespace istio-system --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')"# curl-H "Host:helloworld-go.default.example.com" http://$IP_ADDRESS Hello Go Sample v2!查看部署后生成的Kubernetes Deployment:
# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE helloworld-go-v1-deployment 0/0 0 0 2m52s helloworld-go-v2-deployment 1/1 1 1 2m19s查看部署后生成的Kubernetes Pod:
# kubectl get pods NAME READY STATUS RESTARTS AGE helloworld-go-v2-deployment-589c5f7ff9-czpj2 3/3 Running 0 12shelloworld-go對應的部署如果在擴縮容時間窗口期(默認60s)內沒有請求,Knative將自動將對應的部署縮容為零。
查看部署后生成的Revision:
我們可以看到helloworld-go的配置有兩個修訂版,分別是helloworld-go-v1和helloworld-go-v2。配置的變更產生了新的修訂版,然而并沒有產生新的路由、服務和配置對象。我們可以通過下面的命令來驗證這些資源對象的狀態。
- 獲取服務的路由信息的命令:kubectl get routes。
- 獲取Knative服務的狀態信息的命令:kubectl get ksvc。
- 獲取Knative服務的配置信息的命令:kubectl get configurations。
- Knative默認路由策略是將所有流量轉發給最新的修訂版。
1.5 流量分發到不同版本
在典型的微服務部署中,實現流量在不同版本中分發是實現金絲雀或藍綠部署方式的基礎。Knative提供了這種流量分發方式的支持。
在Knative Service的yaml文件配置中,traffic區塊描述了如何在多個版本之間進行流量分發。配置范例如下:
traffic區塊中可以有一個或多個條目。每個條目中帶有如下屬性。
- tag:流量分配的標識符。此標記將在路由中充當前綴,以便將流量分發到特定修訂版。
- revisionName:參與流量分配的Knative服務修訂版本的名稱。
- percent:對應修訂版被分配的流量百分比。這個值在0~100之間。在上述例子中,Knative分配給修訂版helloworld-go-v1和helloworld-go-v2各50%的流量。
- Knative Serving會為每個Tag創建獨特的URL。我們可以通過下面的命令查看:
通過訪問URL可以直接訪問到對應的修訂版。
1.6 藍綠部署與灰度發布
一般情況下,升級服務端應用需要先停掉老版本服務,再啟動新版服務。但是這種簡單的發布方式存在兩個問題,一方面在新版本升級過程中,服務是暫時中斷的;另一方面,如果新版本升級失敗,回滾起來非常麻煩,容易造成更長時間的服務不可用。
所謂藍綠部署,是指同時運行兩個版本的應用,即部署的時候,并不停掉老版本,而是直接部署一套新版本,等新版本運行起來后,再將流量切換到新版本上,如圖6-3所示。但是藍綠部署要求服務端在升級過程中同時運行兩套程序,對硬件資源的要求是日常所需的2倍。
Knative提供了一個簡單的切換流量的方法,可將流量快速從Revison1切換到Revision 2。如果Revision2發生錯誤,服務可以快速回滾變更到Revison1。
接下來,我們將通過helloworld-go這個Knative服務來應用藍綠色部署模式。上文擁有兩個修訂版的helloworld-go服務,名稱分別為helloworld-go-v1和helloworld-go-v2。通過部署helloworld-go-v2,我們可以看到Knative自動將100%的流量路由到helloworld-go-v2。現在,假設出于某些原因,我們需要將helloworld-go-v2回滾到helloworld-go-v1。
以下示例中Knative Service與先前部署的helloworld-go相同,只是添加了traffic部分以指示將100%的流量路由到helloworld-go-v1。
灰度發布也叫金絲雀發布。如圖所示,在灰度發布開始后,先啟動一個新版本應用,但是并不直接將流量切過來,而是測試人員對新版本進行線上測試。啟動的這個新版本應用,就是我們的金絲雀。如果測試沒有問題,我們可以將少量的流量導入新版本,然后再對新版本做運行狀態觀察,收集各種運行時數據。如果此時對新舊版本做數據對比,就是所謂的A/B測試。
當確認新版本運行良好后,再逐步將更多的流量導入新版本。在此期間,我們還可以不斷地調整新舊兩個版本運行的服務器副本數量,使得新版本能夠承受更大的流量壓力,直到將100%的流量切換到新版本上,最后關閉剩下的老版本服務,完成灰度發布。
如果我們在灰度發布過程中(灰度期)發現新版本有問題,應該立即將流量切回老版本,這樣就會將負面影響控制在最小范圍內。
以下示例通過不斷變更helloworld-go-v1和helloworld-go-v2的流量比例來實現helloworld-go服務新版本的灰度發布。
使用 Knative CLI 路由和管理流量
1.5和1.6的操作也可以通過cli命令設置。
kn service update <service-name> --traffic <revision-name>=<percent> 是您為其配置流量路由的 Knative 服務的名稱。
是要配置為接收一定百分比的流量的修訂名稱。
是要發送到 指定的修訂版的流量百分比。
例如,要拆分名為 example 的 Service 的流量,將 80% 的流量發送到 Revision 綠色,將 20% 的流量發送到 Revision blue,您可以運行以下命令:
kn service update example-service --traffic green=80 --traffic blue=20也可以將標簽添加到修訂版,然后根據您設置的標簽拆分流量:
kn service update example --tag green=revision-0001 --tag blue=@latest@latest 標簽表示藍色解析為服務的最新版本。 以下示例將 80% 的流量發送到最新版本,將 20% 的流量發送到名為 v1 的版本。
kn service update example-service --traffic @latest=80 --traffic v1=201.7 Knative Service的彈性伸縮配置
無服務器計算不僅能夠終止未使用的服務,還可以按需擴展計算規模。Knative Serving支持這種彈性伸縮能力。
為了讓Knative的Autoscaler更好地調度服務,我們需要根據實際情況在服務中添加相應的擴縮容配置項。下面以helloworld-go.yaml范例來演示擴縮容相關配置。
在上述配置中,revision中配置了修訂版的彈性伸縮策略。各個屬性代表的意義如下。
- autoscaling.knative.dev/class:表示Autoscaler的實現方式,這個屬性的可選值有kpa.autoscaling.knative.dev或hpa.autoscaling.knative.dev。KPA支持縮容到零,HPA支持基于CPU的擴展機制。
- autoscaling.knative.dev/metric:度量指標默認為并發數,該屬性還可以根據業務情況選擇每秒請求數或CPU使用率。
- autoscaling.knative.dev/target:自動縮放的目標值是Autoscaler維護應用的每個副本度量指標的目標值。
- autoscaling.knative.dev/minScale:表示每個修訂版副本需要保留的最小數量。在任何時間點,副本不會少于這個數量。通過該設置,我們可以有效地減少服務的冷啟動時間。
- autoscaling.knative.dev/maxScale:表示每個修訂版副本所能達到的最大數量。在任何時間點,副本都不會超過指定的最大值,從而避免資源被過度使用。
- containerConcurrency:限制容器在給定時間允許的并發請求的數量的硬性限制。只有當應用程序需要強制的并發約束時,才會使用到該屬性。
部署helloworld-go服務并配置到Knative集群:
# kubectl apply-f helloworld-go.yaml驗證部署結果:
#IP_ADDRESS="$(kubectl get nodes-o 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc istio-ingressgateway--namespace istio-system--output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')" # curl-H "Host:helloworld-go.default.example.com" $IP_ADDRESS Hello World!壓力測試:
# hey-c 50-z 30s-host "helloworld-go.default.knative.k8s.arch.dapp.com" "http://$IP_ADDRESS"通過hey工具發起50個并發請求,持續30秒對hellowrold-go服務進行壓測。
查看壓測期間Pod的副本數量:
通過上面的命令,我們可以看到集群中產生了6個Pod副本。那么問題來了,我們發起的并發請求數是50個,服務自動縮放的目標值是10,按照“副本數=并發數/目標值”算法,Pod副本數應該是5個才對呀。這是由于Knative Serving還有一個控制參數叫目標使用率,一旦并發數達到預設目標的70%(默認值),Autoscaler就會繼續擴容。引入目標使用率的主要目的是在擴容時減小由Pod啟動時間帶來的延遲,使負載到達前就將Pod實例啟動起來。
引用
Hello world apps - Python - 《Knative v0.23 Documentation》 - 書棧網 · BookStack
Knative實戰:基于Kubernetes的無服務器架構實踐 by 李志偉 游楊 (z-lib.org)
總結
以上是生活随笔為你收集整理的serverless knative实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 道理我都懂,但是这种列车为什么会自己摆动
- 下一篇: 语法俱乐部2:名词短语与冠词