Knative first experience: Serving Hello World

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:

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.
image

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.
image

Kubernetes selected clusters and pages in a group of containers in the container left the service istio-systemnamespace confirm the operating state, as shown below.
image

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:
image

Click the Create button to deploy content required Knative initialization, including the deployment of CRD and so on.

Deployment Knative Serving

登录容器服务管理控制台,点击左侧的应用目录,在右侧选中 ack-knative-serving,如下:
image

点击参数, 可以通过修改参数配置进行定制化,默认参数提供了使用 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 容器才能真正转发到业务容器,关于这方面的细节我在后续的文章再进行详细的介绍。
image

所以想要访问 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.

Guess you like

Origin yq.aliyun.com/articles/704764