Through the study of the previous two chapters you've mastered a lot of theoretical knowledge Knative based on this knowledge you should Knative who is, where it comes from and what it needs to do a certain understanding. But even so you may still have a kind still holds partly concealed, look no tolerance of Muslim feeling, which is like a matchmaker to take the girl's 100 life according to you personally if you do not see one side. Play by the rules, at this stage in relation to the general Hello World I played. This article on the adoption of a Hello World and Knative to a "date" so that you see the white Formica Knative the true capacity.
Installation Knative
Mounting step Knative community see here , probably the entire process comprising the following three parts:
- Ready kubernetes environment (you can aliyun container service to quickly create a cluster kubernetes )
- Installation istio
- Component installation Knative
Although it looks only three steps, but each step needs to actually do a lot of manual work, execute a bunch of commands. In addition yaml community file documents provided by default uses a lot of gcr.io mirror, currently unable to pull gcr.io mirror. Yaml so these files can not be used directly in the country, at least 30 more need to manually synchronize mirroring job.
But do not worry, the application directory Ali cloud container services have Knative installation package, now just a few mouse clicks Ali cloud services on top of the container can easily set up a cluster Knative O ^ ~ ^ OO ^ ~ ^ OO ^ ~ ^ O
Creating a cluster Kubernetes
Ali cloud service container can easily create Kubernetes cluster through the management console. Specific processes can refer to create Kubernetes cluster .
Container service provides proprietary clustering and cluster hosting are two types, if you do not know how I suggest you choose the Direct Selection hosted version of Kubernetes cluster. Hosted version you do not need to manage themselves Kubernetes Master assembly and operation and maintenance, you only need to provide Node node can be.
Installation Istio
Knative Serving run needs to be based Istio, currently Ali cloud container services Kubernetes has provided a key way to deploy the installation configuration Istio. Specific processes can refer to deploy Istio
Login container services management console, click the cluster on the left navigation bar, enter the cluster list page. Select the cluster and click More Actions column> deployment Istio.
Be configured as required, then click the Deploy button. Wait a few seconds, Istio environment can be deployed.
Deployment Istio IngressGateway
Find ack-istio-ingressgateway components in container services management console application directory. Click the 参数
tab to see the default parameters provide configuration items Istio IngressGateway, if required customization parameters can be modified here. Choose a good target Kubernetes 集群
and click the 创建
button to complete the creation of Ingressgateway.
Kubernetes selected clusters and pages in a group of containers in the container left the service istio-system
namespace confirm the operating state, as shown below.
Deployment Knative CRD
Log in container services management console, click Apply directory on the left side, the right side is selected ack-knative-init, as follows:
Click the Create button to deploy content required Knative initialization, including the deployment of CRD and so on.
Deployment Knative Serving
登录容器服务管理控制台,点击左侧的应用目录,在右侧选中 ack-knative-serving,如下:
点击参数, 可以通过修改参数配置进行定制化,默认参数提供了使用 Istio IngressGateway 的配置项,然后点击创建按钮。
Serving Hello World
Serverless 一个核心思想就是按需分配,那么 Knative 是如何实现按需分配的呢?另外在前面的文章中你已经了解到 Knative Serving 在没有流量的时候是可以把 Pod 缩容到零的。接下来就通过一些例子体验一下 Knative 缩容到零和按需自动扩缩容的能力。
部署 helloworld-go 示例
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 中:
- 部署 helloworld-go
└─# kubectl apply -f helloworld-go.yaml
service.serving.knative.dev/helloworld-go created
- 查看 helloworld-go pod
└─# 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 示例
在访问 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 这个镜像进行测试。
- 编写 Knative Service 文件 autoscale-go.yaml 如下:
└─# 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
- 部署 autoscale-go
└─# 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 进行测试:
└─# 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 集群的方法
- 理解 Knative 从零到一的含义,并且能够基于 helloworld-go 例子演示这个过程
- 理解 Knative 按需扩缩容的含义,并且能够基于 autoscale-go 例子演示这个过程
- 理解 Knative 按需扩容的原理,按需扩容不单单是用户发起 50 个并发、每一个 Pod 最多能够并发处理 10 个请求就一定需要创建 5 个 Pod 出来。如果请求的处理时间很短,一个 Pod 就能满足的情况下 Knative 是不会做无用的扩容的
Next
通过前面的例子相信你已经对 Knative Serving 有了更深刻的理解。但是你可能也会产生很多疑问:
- 这里面只是展示了 Serving 的 Hello World,Eventing、Build 能不能也来一些这样的例子?
- 为什么上面例子的域名都是 xx.example.com, 我能不能换成自己的域名?
- Knative 流量转发的细节是怎样的?queue 的作用是什么?
- 在前面的例子中,容器都是监听 8080 端口的,如果容器监听的不是 8080 端口那么需要怎么配置自定义的端口?
- Knative 默认扩缩容的策略是怎样的?
- hey Although this pressure measurement tool illustrates the process Knative automatic expansion, but also intuitive enough, there is no better tool to verify the number of concurrent, service response time and Knative automatic expansion of relations between the Pod?
- If the Service is updated, how traffic gray?
All these questions I will be 11 to explain in a subsequent series of articles, so stay tuned follow-up article.