經過前面兩章的學習你已經掌握了不少 Knative 的理論知識,基於這些知識你應該對 Knative 是誰、它來自哪裏以及它要作什麼有了必定的認識。但是即使如此你可能仍是會有一種猶抱琵琶半遮面,看不清真容的感受,這就比如紅娘拿姑娘的 100 張生活照給你看也不如你親自去見一面。按常理出牌,通常到這個階段就該 Hello World 出場了。本篇文章就經過一個 Hello World 和 Knative 來一個「約會」,讓你一睹 Knative 這位白富美的真容。html
Knative 社區提供的安裝步驟見這裏,整個流程大概包含以下三個部分:git
雖然看起來只有三步,可是每一步其實都須要手動作大量的工做,執行一堆命令。另外社區文檔提供的 yaml 文件默認使用了大量的 gcr.io 鏡像,目前國內沒法拉取 gcr.io 鏡像。因此這些 yaml 文件在國內不能直接使用,至少須要手動同步 30 多個鏡像才行。github
不過彆着急,阿里雲容器服務的應用目錄已經有 Knative 的安裝包,如今只須要在阿里雲容器服務上面點擊幾下鼠標就能輕輕鬆鬆搭建一個 Knative 集羣 O ^ ~ ^ O O ^ ~ ^ O O ^ ~ ^ Ojson
阿里雲容器服務能夠經過管理控制檯很是方便地建立 Kubernetes 集羣。具體過程能夠參考建立Kubernetes集羣。
容器服務提供了專有集羣和託管集羣兩種類型,若是不知道該怎麼選擇建議你直接選擇託管版的 Kubernetes 集羣。託管版無需你本身承擔 Kubernetes Master 組件的管理和運維,你只須要提供 Node 節點便可。api
Knative Serving 運行須要基於 Istio,目前阿里雲容器服務 Kubernetes 已提供了一鍵部署的方式來安裝配置 Istio。具體過程能夠參考部署Istio
登陸 容器服務管理控制檯,單擊左側導航欄中的集羣,進入集羣列表頁面。選擇所需的集羣並單擊操做列更多 > 部署 Istio。緩存
根據須要進行配置,而後點擊部署按鈕。稍等十幾秒鐘以後,Istio 環境就能夠部署完畢。bash
在容器服務管理控制檯的應用目錄中找到 ack-istio-ingressgateway 組件。點擊參數
標籤能夠看到默認參數提供了 Istio IngressGateway 的配置項,若是須要定製化參數能夠在此進行修改。選擇好目標 Kubernetes 集羣
而後點擊建立
按鈕便可完成 Ingressgateway 的建立。併發
在容器服務左側的容器組頁面中選擇 Kubernetes 集羣和 istio-system
namespace 確認運行狀態,以下所示。app
登陸容器服務管理控制檯,點擊左側的應用目錄,在右側選中 ack-knative-init,以下:less
點擊建立按鈕部署 Knative 初始化所需的內容,包括部署 CRD 等。
登陸容器服務管理控制檯,點擊左側的應用目錄,在右側選中 ack-knative-serving,以下:
點擊參數, 能夠經過修改參數配置進行定製化,默認參數提供了使用 Istio IngressGateway 的配置項,而後點擊建立按鈕。
Serverless 一個核心思想就是按需分配,那麼 Knative 是如何實現按需分配的呢?另外在前面的文章中你已經瞭解到 Knative Serving 在沒有流量的時候是能夠把 Pod 縮容到零的。接下來就經過一些例子體驗一下 Knative 縮容到零和按需自動擴縮容的能力。
Knative 官方給出了好幾種語言的 Helloworld 示例,這些不一樣的語言其實只是編譯鏡像的 Dockerfile 有所不一樣,作好鏡像以後的使用方式沒什麼差別。本例以 go 的 Hello World 爲例進行演示。官方給出的例子都是源碼,須要編譯長鏡像才能使用。爲了你驗證方便我已經提早編譯好了一份鏡像 registry.cn-hangzhou.aliyuncs.com/knative-sample/simple-app:07 , 你能夠直接使用。
首先編寫一個 Knative Service 的 yaml 文件 helloworld-go.yaml
, 內容以下:
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: labels: app: helloworld-go annotations: autoscaling.knative.dev/target: "10" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/simple-app:07 env: - name: SIMPLE_MSG value: "helloworld-go-07"
注意其中 autoscaling.knative.dev/target: "10"
這個 Annotation 是設置每個 Pod 的可處理併發請求數 10 ,Knative KPA 自動伸縮的時候會根據當前總請求的併發數和 autoscaling.knative.dev/target
自動調整 Pod 的數量,從而達到自動擴縮的目的。更多的策略信息我會在後續的文章中一一介紹。
如今使用 kubectl 命令把 yaml 提交到 Kubernetes 中:
└─# kubectl apply -f helloworld-go.yaml service.serving.knative.dev/helloworld-go created
└─# kubectl get pod NAME READY STATUS RESTARTS AGE helloworld-go-lq6ns-deployment-869cbcc75d-qrln7 2/2 Running 0 6s
到此 helloworld-go 已經運行起來了,接下來訪問一下 helloworld-go 這個服務吧。
在訪問 helloworld-go 以前我要先來介紹一下在 Knative 模型中流量是怎麼進來的。Knative Service 和 Kubernetes 原生的 Deployment 不同,Knative 不會建立 Loadbalance 的 Service,也不能建立 NodePort 類型的 Service,因此不能經過 SLB 或者 NodePort 訪問。只能經過 ClusterIP 訪問。而 ClusterIP 是不能直接對外暴露的,因此必須通過 Gateway 才能把用戶的流量接入進來。本例就是使用 Istio 的 Gateway 承接 Knative 的南北流量(進和出)。以下圖所示是 Knative 模型中流量的轉發路徑。用戶發起的請求首先會打到 Gateway 上面,而後 Istio 經過 VirtualService 再把請求轉發到具體的 Revision 上面。固然用戶的流量還會通過 Knative 的 queue 容器才能真正轉發到業務容器,關於這方面的細節我在後續的文章再進行詳細的介紹。
因此想要訪問 Knative 的服務首先要獲取 Gateway 的 IP 地址,能夠經過以下方式獲取 Gateway 的 IP:
└─# kubectl get svc istio-ingressgateway --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*].ip}" 39.97.31. 219
前面也介紹了 Gateway 是經過 VirtualService 來進行流量轉發的,這就要求訪問者要知道目標服務的名字才行(域名),因此要先獲取 helloworld-go 的域名, 注意下面這條命令中的 ${SVC_NAME}
須要替換成 helloworld-go
,這個名字必需要和 Knative Service 的名字一致,由於每個 Service 都有一個惟一的名字。
└─# kubectl get route ${SVC_NAME} --output jsonpath="{.status.domain}" helloworld-go.default.example.com
至此你已經拿到 IP 地址和 Hostname,能夠經過 curl 直接發起請求:
└─# curl -H "Host: helloworld-go.default.example.com" "http://39.97.31\. 219" <h1>helloworld-go-07-v3</h1>
爲了方便你進行測試,我提供了一個腳本 run-test.sh
,你可使用此腳本測試你本身的 Service , 你本身在測試的時候把 SVC_NAME 換成本身的 Service Name 就好了。
#!/bin/bash SVC_NAME="helloworld-go" export INGRESSGATEWAY=istio-ingressgateway export IP_ADDRESS=$(kubectl get svc $INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*]['ip']}") echo "IP_ADDRESS: ${IP_ADDRESS}" export GATEWAY_IP=`kubectl get svc $INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*]['ip']}"` export DOMAIN_NAME=`kubectl get route ${SVC_NAME} --output jsonpath="{.status.domain}"` kubectl get ksvc ${SVC_NAME} --output=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain time curl -H "Host: ${DOMAIN_NAME}" http://${IP_ADDRESS} -v
剛剛部署完 Service 的時候 Knative 默認會建立出一個 Pod 提供服務,若是你超過即便秒沒有訪問 helloworld-go 這個服務那麼這個 Pod 就會自動刪除,此時就是縮容到零了。如今看一下 Pod 狀況, 你可能會發現沒有 Pod
└─# kubectl get pod -o wide No resources found.
如今執行一下 run-test.sh
發起一個請求到 Knative Service
└─# ./run-test.sh IP_ADDRESS: 39.97.31\. 219 NAME DOMAIN helloworld-go helloworld-go.default.example.com * Rebuilt URL to: http://39.97.31\. 219/ * Trying 39.97.31\. 219... * TCP_NODELAY set * Connected to 39.97.31\. 219 (39.97.31\. 219) port 80 (#0) > GET / HTTP/1.1 > Host: helloworld-go.default.example.com > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < content-length: 28 < content-type: text/html; charset=utf-8 < date: Mon, 03 Jun 2019 03:47:58 GMT < server: istio-envoy < x-envoy-upstream-service-time: 2681 < * Connection #0 to host 39.97.31. 219 left intact <h1>helloworld-go-07-v3</h1> real 0m2.775s user 0m0.007s sys 0m0.007s
注意 run-test.sh
結果中,這面這一段:
real 0m2.775s user 0m0.007s sys 0m0.007s
real 0m2.775s
意思意思是 curl
請求執行一共消耗了 2.775s
, 也就是說 Knative 從零到 1 擴容 + 啓動容器再到服務響應請求總共消耗了 2.775s
(我以前的測試致使在 Node 上面緩存了鏡像,因此沒有拉鏡像的時間)。能夠看出來這個速度仍是很快的。
再看一下 pod 數量, 你會發現此時 Pod 自動擴容出來了。而且 Pod 數量爲零時發起的請求並無拒絕連接。
└─# kubectl get pod NAME READY STATUS RESTARTS AGE helloworld-go-p9w6c-deployment-5dfdb6bccb-gjfxj 2/2 Running 0 31s
helloworld-go 自動擴容測試
接下來再測試一下 Knative 按需擴容的功能。使用社區提供的 hey 進行測試。hey 有 Windows、Linux 和 Mac 的二進制能夠在這裏下載。
使用這個命令測試以前須要在本機進行 Host 綁定,對於 helloworld-go 來講要把 helloworld-go 的域名綁定到 Istio Gateway 的 IP 上,/etc/hosts 添加以下配置
39.97.31. 219 helloworld-go.default.example.com
以下所示 這條命令的意思是:
-z 30s
持續測試 30s-c 50
保持每秒 50 個請求測試結果以下:
└─# hey -z 30s -c 50 "http://helloworld-go.default.example.com/" && kubectl get pods Summary: Total: 30.0407 secs Slowest: 0.1453 secs Fastest: 0.0266 secs Average: 0.0378 secs Requests/sec: 1323.2700 Total data: 1113056 bytes Size/request: 28 bytes Response time histogram: 0.027 [1] | 0.038 [23584] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.050 [15839] |■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.062 [255] | 0.074 [30] | 0.086 [28] | 0.098 [14] | 0.110 [0] | 0.122 [0] | 0.133 [0] | 0.145 [1] | Latency distribution: 10% in 0.0330 secs 25% in 0.0351 secs 50% in 0.0371 secs 75% in 0.0407 secs 90% in 0.0428 secs 95% in 0.0442 secs 99% in 0.0495 secs Details (average, fastest, slowest): DNS+dialup: 0.0001 secs, 0.0266 secs, 0.1453 secs DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0036 secs req write: 0.0000 secs, 0.0000 secs, 0.0009 secs resp wait: 0.0376 secs, 0.0266 secs, 0.1453 secs resp read: 0.0001 secs, 0.0000 secs, 0.0100 secs Status code distribution: [200] 39752 responses NAME READY STATUS RESTARTS AGE helloworld-go-lq42n-deployment-68ddd64944-nkwpn 2/2 Running 0 77s
回想一下剛纔 helloworld-go.yaml 文件配置,已經設置了 autoscaling.knative.dev/target: "10"
這個 Annotation。這表示每個 Pod 可以接受併發 10 個請求,而剛纔併發請求數設置的是 50 因此理論上應該會建立出來 5 個 Pod?,
上面結果中最後一部分,是 kubectl get pods
的結果,以下所示:
NAME READY STATUS RESTARTS AGE helloworld-go-lq42n-deployment-68ddd64944-nkwpn 2/2 Running 0 77s
能夠看到實際只有一個 Pod,爲何呢?這是由於雖然併發 50 ,可是每個請求很快就結束了。看一下剛纔測試的結果, 截取核心的一部分展現以下。能夠看到最慢的一個請求 0.1453
秒就處理完了。並且 99% 的請求 RT 都沒超過 0.0495
秒。
... ... Total: 30.0407 secs Slowest: 0.1453 secs Fastest: 0.0266 secs Average: 0.0378 secs Requests/sec: 1323.2700 ... ... Latency distribution: 10% in 0.0330 secs 25% in 0.0351 secs 50% in 0.0371 secs 75% in 0.0407 secs 90% in 0.0428 secs 95% in 0.0442 secs 99% in 0.0495 secs ... ...
因此一秒內是能夠完整的處理完 50 個請求的,也就不須要擴容了。
再換一個例子,讓每個請求處理的時間拉長一些看看效果。
autoscale-go 自動擴縮測試
若是單個請求處理的太快就不太好展現自動擴縮的效果,那麼就讓單條請求處理的時間稍微長一些。Knative 官方有一個 Autoscaler 的例子 , 這個例子中每個請求會進行一些計算,把請求時間拉長,這樣就能更容易的測試。你能夠直接使用 registry.cn-hangzhou.aliyuncs.com/knative-sample/autoscale-go:0.1 這個鏡像進行測試。
└─# cat autoscale-go.yaml apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: autoscale-go namespace: default spec: template: metadata: labels: app: autoscale-go annotations: autoscaling.knative.dev/target: "10" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/autoscale-go:0.1
└─# kubectl apply -f autoscale-go.yaml service.serving.knative.dev/autoscale-go created
run-test.sh 中 SVC_NAME
改爲 autoscale-go
而後執行 run-test.sh ,以下:
└─# ./run-test.sh IP_ADDRESS: 39.97.31\. 219 NAME DOMAIN autoscale-go autoscale-go.default.example.com * Rebuilt URL to: http://39.97.31\. 219/ * Trying 39.97.31\. 219... * TCP_NODELAY set * Connected to 39.97.31\. 219 (39.97.31\. 219) port 80 (#0) > GET / HTTP/1.1 > Host: autoscale-go.default.example.com > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < content-length: 0 < date: Mon, 03 Jun 2019 05:05:38 GMT < server: istio-envoy < x-envoy-upstream-service-time: 2912 < * Connection #0 to host 39.97.31. 219 left intact real 0m2.999s user 0m0.007s sys 0m0.008s
能夠看到 autoscale-go 已經能夠提供服務了。
使用 hey 命令測試以前須要在本機進行 Host 綁定,對於 autoscale-go 來講要把 autoscale-go 的域名綁定到 Istio Gateway 的 IP 上,/etc/hosts 添加以下配置
39.97.31. 219 autoscale-go.default.example.com
└─# hey -z 30s -c 50 "http://autoscale-go.default.example.com?sleep=100&prime=10000&bloat=5" && kubectl get pods Summary: Total: 30.1443 secs Slowest: 6.0173 secs Fastest: 0.1285 secs Average: 0.1717 secs Requests/sec: 290.4364 Total data: 875284 bytes Size/request: 99 bytes Response time histogram: 0.128 [1] | 0.717 [8704] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 1.306 [0] | 1.895 [0] | 2.484 [0] | 3.073 [0] | 3.662 [0] | 4.251 [0] | 4.840 [0] | 5.428 [0] | 6.017 [50] | Latency distribution: 10% in 0.1329 secs 25% in 0.1356 secs 50% in 0.1383 secs 75% in 0.1413 secs 90% in 0.1435 secs 95% in 0.1450 secs 99% in 0.1574 secs Details (average, fastest, slowest): DNS+dialup: 0.0002 secs, 0.1285 secs, 6.0173 secs DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0036 secs req write: 0.0000 secs, 0.0000 secs, 0.0011 secs resp wait: 0.1713 secs, 0.1283 secs, 5.9780 secs resp read: 0.0001 secs, 0.0000 secs, 0.0066 secs Status code distribution: [200] 8755 responses NAME READY STATUS RESTARTS AGE autoscale-go-zqcm2-deployment-6cf67b4545-2f2ck 2/2 Running 0 28s autoscale-go-zqcm2-deployment-6cf67b4545-4xc9s 2/2 Running 0 26s autoscale-go-zqcm2-deployment-6cf67b4545-6wt8r 2/2 Running 0 28s autoscale-go-zqcm2-deployment-6cf67b4545-hdbnc 2/2 Running 0 30s autoscale-go-zqcm2-deployment-6cf67b4545-w9pm7 2/2 Running 0 28s
能夠看到此時 Knative 自動擴容出來了 5 個 Pod 處理請求。
至此你已經完成了和 Knative Serving 的首次約會,也看到了這位白富美的真容。經過本篇文章你應該掌握
如下幾點:
經過前面的例子相信你已經對 Knative Serving 有了更深入的理解。可是你可能也會產生不少疑問:
全部這些疑問我會在後續的一系列文章中都會一一講解到,敬請期待後續的文章。
本文爲雲棲社區原創內容,未經容許不得轉載。