knative学习-01

knative学习-01

随着 IT 技术的不断演进,从 物理机 -> 虚拟化 -> 云平台 -> 容器 -> Serverless,整个演进的方向主要包括以下几个特点:

  • 资源利用率越来越高
  • 高可扩展性,具有弹性伸缩能力
  • 从集中式向分布式演进,提倡应用架构微服务化
  • 开发人员不关心基础架构,更多关注在业务代码上
  • 提倡自动化,尽可能减少人工干预
  • 运维工作不断简化,减少宕机时间

而无服务框架(Serverless)是近年来迅速兴起的一个技术概念,它主要具有以下特点:

  • 实现了细粒度的计算资源分配。
  • 不需要预先分配资源。
  • 具备真正意义上的高度扩容和弹性。
  • 按需使用,按需计费。

但是由于 Serverless 一直缺乏统一认知以及相应的标准,Serverless 应用无法适应所有的云平台,选用了某个厂商的平台,就必须使用该厂商提供的配套服务。通常我们认为Serverless包含两个部分,FaaS和BaaS,随着Kubernetes的兴起,当前流行的开源FaaS平台有OpenFaas、Kuberless、Fission、openWhisk,Knative。

Knative 是一个基于 Kubernetes 的,用于构建、部署和管理现代 serverless 应用的平台,是由IBM、Red Hat、谷歌等行业领导企业的工程师共同开发的。就目前来说,随着无服务器架构(serverless)普及率的持续增长,Knative 最有可能成为其标准。Knative 把路由(routing)和事件(eventing)的复杂性抽象出来,通过整合容器(或函数)构建、工作负载管理以及事件模型这三者来实现的这一 Serverless 标准。

Knative 由三个核心组件组成:

  • Build:主要负责从代码仓库获取源码并编译成镜像和推送到镜像仓库,并且所有这些操作都是在 Kubernetes Pod 中进行的。
  • Eventing:提供了事件的接入、触发等一整套事件管理的能力,包括外部事件源的接入、事件注册和订阅、以及对事件的过滤等功能。事件模型可以有效的解耦生产者和消费者的依赖关系。生产者可以在消费者启动之前产生事件,消费者也可以在生产者启动之前监听事件。
  • Serving:管理 Serverless 工作负载以对外提供服务,可以和事件很好的结合并且提供了基于请求驱动的自动扩缩的能力,而且在没有服务需要处理的时候可以缩容到零个实例,扩容边界可以支持到无限大,而且支持灰度发布。

后面会基于实验逐个来讲解。首先我们要来安装一套环境,本文默认你已经安装了 Kubernetes 集群,所以从 istio 自定义安装开始讲,然后安装 knative 最后部署测试应用,并演示自动启动和回收。

1. 安装 istio

1) 下载 Istio 并解压

1
2
3
export ISTIO_VERSION=1.1.7
curl -L https://git.io/getLatestIstio | sh -
cd istio-${ISTIO_VERSION}

2) 运行以下命令安装 Istio CRDs

1
for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done

3) 创建 istio-system 命名空间,并不启用自动注入 sidecar

1
2
3
4
5
6
7
8
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: istio-system
labels:
istio-injection: disabled
EOF

4) 刚开始接触 Knative 建议不要启用 Istio 自动注入 sidecar 功能,所以这里演示用最小化安装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# A lighter template, with just pilot/gateway.
# Based on install/kubernetes/helm/istio/values-istio-minimal.yaml
helm template --namespace=istio-system \
--set prometheus.enabled=false \
--set mixer.enabled=false \
--set mixer.policy.enabled=false \
--set mixer.telemetry.enabled=false \
`# Pilot doesn't need a sidecar.` \
--set pilot.sidecar=false \
--set pilot.resources.requests.memory=128Mi \
`# Disable galley (and things requiring galley).` \
--set galley.enabled=false \
--set global.useMCP=false \
`# Disable security / policy.` \
--set security.enabled=false \
--set global.disablePolicyChecks=true \
`# Disable sidecar injection.` \
--set sidecarInjectorWebhook.enabled=false \
--set global.proxy.autoInject=disabled \
--set global.omitSidecarInjectorConfigMap=true \
`# Set gateway pods to 1 to sidestep eventual consistency / readiness problems.` \
--set gateways.istio-ingressgateway.autoscaleMin=1 \
--set gateways.istio-ingressgateway.autoscaleMax=1 \
`# Set pilot trace sampling to 100%` \
--set pilot.traceSampling=100 \
install/kubernetes/helm/istio \
> ./istio-lean.yaml

kubectl apply -f istio-lean.yaml

5) 验证 istio 部署完成

1
2
3
4
[root@master01 ~]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-767cb44c84-j7m69 1/1 Running 0 127m
istio-pilot-67cb784b59-plc9p 1/1 Running 0 127m

2. 安装 Knative

1) 首先使用 knative.dev/crd-install=true 标签安装 CRDs

1
2
3
4
kubectl apply --selector knative.dev/crd-install=true \
--filename https://github.com/knative/serving/releases/download/v0.9.0/serving.yaml \
--filename https://github.com/knative/eventing/releases/download/v0.9.0/release.yaml \
--filename https://github.com/knative/serving/releases/download/v0.9.0/monitoring.yaml

2) 安装 Knative 和所需要的依赖

1
2
3
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.9.0/serving.yaml \
--filename https://github.com/knative/eventing/releases/download/v0.9.0/release.yaml \
--filename https://github.com/knative/serving/releases/download/v0.9.0/monitoring.yaml

3) 为集群所有节点添加标签以在各主机上放置 fluentd

1
kubectl label nodes --all beta.kubernetes.io/fluentd-ds-ready="true"

4) 验证 knative 部署完成,并且你会发现默认会在 istio-system 里面安装 zipkin 作为 tracing,当然可以换用 jaeger

1
2
3
kubectl get pods --namespace knative-serving
kubectl get pods --namespace knative-eventing
kubectl get pods --namespace knative-monitoring

5) 下载两个客户端工具

1
2
3
4
5
6
7
8
9
10
wget https://github.com/ahmetb/kubectx/archive/v0.7.0.tar.gz
tar -xzvf v0.7.0.tar.gz
cd kubectx-0.7.0/
# 用于切换进入 namespace,对比 oc project
mv kubens /usr/local/bin/

wget https://github.com/knative/client/releases/download/v0.2.0/kn-linux-amd64
# kn 是 Knative 的客户端命令行项目,仍在开发过程中。
mv kn-linux-amd64 /usr/local/bin/kn
chmod +x /usr/local/bin/kn

3. 创建第一个服务

1) 创建命名空间 knativetutorial 以部署测试应用

1
kubectl create namespace knativetutorial

2) 使用 kn 创建第一个 knative 服务。这个服务是一个产生连续斐波纳契数列的应用。它部署后将暴露出一个端口(endpoint),向这个端口发送GET请求,就会得到斐波纳契数列的前n个数字。其中n通过/之后的参数传入。

1
2
3
4
5
6
7
[root@master01 ~]#  kn service create --image docker.io/ibmcom/fib-knative fib-knative
Service 'fib-knative' successfully created in namespace 'knativetutorial'.
Waiting for service 'fib-knative' to become ready ...
timeout: service 'fib-knative' not ready after 60 seconds
[root@master01 ~]# kubectl get ksvc/fib-knative
NAME URL LATESTCREATED LATESTREADY READY REASON
fib-knative http://fib-knative.knativetutorial.example.com fib-knative-xvvg9 fib-knative-xvvg9 True

3) 现在状态 ready 了,我们看下服务列表

1
2
3
4
[root@master01 ~]#  kn service list -n knativetutorial
NAME URL GENERATION AGE CONDITIONS READY REASON
fib-knative http://fib-knative.knativetutorial.example.com 1 30m 3 OK / 3 True
helloworld-go http://helloworld-go.knativetutorial.example.com 1 28m 3 OK / 3 True

此时,我们可以看到,第一个 knative 服务已经部署完成。

4) 首先我们要知道 knative 是使用 istio 的 ingressgateway 作为服务网关的,由 ingressgateway 承接 knative 的南北流量,把用户的流量引入进来。用户发起的请求首先会打到 ingressgateway 上面,然后 Istio 通过 VirtualService 再把请求转发到具体的 Revision 上面。当然用户的流量还会经过 Knative 的 queue 容器才能真正转发到业务容器。

查看 istio-ingressgateway 的 service 类型默认是 LoadBalancer, 我们这里没有,得修改为 NodePort

获取 istio-ingressgateway 的 nodeport。

1
2
3
4
5
[root@master01 ~]#  INGRESSGATEWAY=istio-ingressgateway
[root@master01 ~]# kubectl get svc $INGRESSGATEWAY --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway NodePort 10.104.40.148 <none> 15020:31407/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32682/TCP,15030:31368/TCP,15031:31573/TCP,15032:32449/TCP,15443:31895/TCP 80m
[root@master01 ~]# export IP_ADDRESS=$(kubectl get node --output 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc $INGRESSGATEWAY --namespace istio-system --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')

5) 查找 service 对应的 URL

1
2
3
4
5
6
[root@master01 ~]#  kubectl get route helloworld-go  --output=custom-columns=NAME:.metadata.name,URL:.status.url
NAME URL
helloworld-go http://helloworld-go.knativetutorial.example.com
[root@master01 ~]# kubectl get route fib-knative --output=custom-columns=NAME:.metadata.name,URL:.status.url
NAME URL
fib-knative http://fib-knative.knativetutorial.example.com

6) 访问测试,观察Pod的自动回收和启动

Knative服务,具体是由Kubernetes的Pod来实现的。作为Serverless的服务,当该服务在一定时间(大约为90秒钟)内不被调用时,Pod资源应该被回收;而再次调用时,Pod应该会自动启动。

我们先来观察一个 Pod 的启动过程,使用 curl 命令来向 Knative 服务发送 HTTP GET 请求。有时第一次调用需要等上几十秒钟才能获得返回,这是因为承载该服务的Kubernetes Pod需要冷启动,耗费时间。可以重复调用第二次,观察结果不到一秒钟就能返回,这是因为Pod已经是活跃状态,不需要冷启动了。

1
2
3
4
[root@master01 ~]# curl -H "Host: helloworld-go.knativetutorial.example.com" http://${IP_ADDRESS}
Hello Go Sample v1!
[root@master01 ~]# curl -H "Host: fib-knative.knativetutorial.example.com" http://${IP_ADDRESS}/5
[1,1,2,3,5]

运行 kubectl get pods --watch 观察 pod 初始化及状态变化过程,可以看到一个全新的Pod被启动并运行了

现在我们来观察Pod的结束,请求成功并返回后,不再发送请求,直到Pod进入Terminating状态并消失。大约需要等90秒钟。但 knative 服务依然存在。

时间差不多了,后续如何,长假再分解。