经过前面两章的学习你已经掌握了不少 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 有了更深入的理解。可是你可能也会产生不少疑问:
全部这些疑问我会在后续的一系列文章中都会一一讲解到,敬请期待后续的文章。
原文连接 本文为云栖社区原创内容,未经容许不得转载。