本章结束时,您将能够:
- 利用 Knative 的概念和组件来部署应用
- 在 GKE 集群上设置集群
- 在 Knative 上部署应用并配置自动缩放
- 在谷歌云上部署应用
- 在 Azure 上设置虚拟库布雷
- 使用虚拟库元素部署应用
本章涵盖了 Knative、Google Cloud Run 和 Virtual Kubelet,它们在 Kubernetes 集群的基础上提供了无服务器的优势。
在前一章中,我们广泛研究了 Kubernetes 中使用的各种设置选项和平台。我们还介绍了 Kubernetes 的自动缩放功能,并在部署在集群上的应用中实现了它。
Kubernetes 和 serverless 是 IT 行业的两个热门话题,但这两个话题往往是相互独立讨论的。Kubernetes 是一个管理容器化应用的平台,而无服务器是一个抽象基础设施的执行模型,这样软件开发人员就可以专注于他们的应用逻辑。然而,这两个概念的结合将实现相同的目标,即让软件开发人员的生活更加轻松。
最近出现了一些平台,通过抽象出管理容器和任何底层基础设施的复杂性,为容器带来了无服务器特性。这些平台在 Kubernetes 集群上运行无服务器工作负载,并提供许多优势,包括自动缩放、缩放至零、每次使用计费、事件驱动功能、集成监控和集成日志功能。
在本章中,我们将讨论在 Kubernetes 集群上提供无服务器优势的三种技术:
- 当地的
- 谷歌云运行
- 虚拟库布雷
Knative 是由谷歌发起的一个开源项目,由 50 多家其他公司贡献,包括 Pivotal、红帽、IBM 和思爱普。Knative 通过引入一组组件在其上构建和运行无服务器应用来扩展 Kubernetes。这个框架对于已经在使用 Kubernetes 的应用开发人员来说非常棒。Knative 为他们提供了专注于代码的工具,而不用担心 Kubernetes 的底层架构。它引入了自动容器构建、自动缩放、缩放到零以及事件框架等功能,允许开发人员在 Kubernetes 之上获得无服务器的好处。
Knative 框架被描述为基于 Kubernetes 的平台,用于在 Knative 网站上部署和管理现代无服务器工作负载。该框架通过引入无服务器功能(如自动缩放和缩放到 Kubernetes 平台的零)来帮助弥合容器化应用和无服务器应用之间的差距。
Knative 由三个主要组件组成:
-
建设
-
服务
-
Eventing
在最新版本的 Knative 中,构建组件已被弃用,转而使用 Tekton 管道。Knative Build 组件的最终版本在 0.7 版本中提供。
构建是从源代码构建容器映像并在 Kubernetes 集群上运行它们的过程。知识服务组件允许部署无服务器应用和功能。这使得能够向容器提供流量,并根据请求的数量自动缩放。每当对代码和配置进行更改时,服务组件还负责拍摄它们的快照。Knative Eventing 组件帮助我们构建事件驱动的应用。该组件允许应用为事件流生成事件和使用事件流中的事件。
下图说明了一个 Knative 框架及其依赖项和每个组件的利益相关者:
最底层代表 Kubernetes 框架,它被 Knative 框架用作容器编排层。Kubernetes 可以部署在任何基础设施上,如谷歌云平台或内部系统。接下来,我们有 Istio 服务网格层,它管理集群内的网络路由。这一层提供了许多好处,包括流量管理、可观察性和安全性。在顶层,Knative 运行在一个 Kubernetes 集群的顶部,拥有 Istio 。在 Knative 层,一端我们可以看到通过 GitHub 项目向 Knative 框架贡献代码的贡献者,另一端我们可以看到在 Knative 框架之上构建和部署应用的应用开发人员。
更多关于 Istio 的信息,请参考https://istio.io/。
现在我们已经对 Knative 有了这样的理解,接下来让我们看看如何在 Kubernetes 集群上安装 Knative。
在本节中,我们将带您完成在 Kubernetes 集群上安装 Knative 的过程。我们将使用谷歌 Kubernetes 引擎(GKE)来建立一个 Kubernetes 集群。GKE 是谷歌云中受管理的 Kubernetes 集群服务。它允许我们运行 Kubernetes 集群,而无需安装、管理和操作我们自己的集群。
我们需要安装并配置以下先决条件才能继续本节:
- 谷歌云账户
- 绿色命令行界面
- kubectl 命令行界面(1.10 版或更高版本)
首先,我们需要设置一些环境变量,我们将使用 gcloud CLI。您应该用您的 gcp 项目的名称更新您的-GCP-项目名称> 。我们将使用美国中部 T4 作为 GCP 区。在终端窗口中执行以下命令来设置所需的环境变量:
$ export GCP_PROJECT=<your-gcp-project-name>
$ export GCP_ZONE=us-central1-a
$ export GKE_CLUSTER=knative-cluster
输出应如下所示:
将我们的 GCP 项目设置为 gcloud 命令行界面命令使用的默认项目:
$ gcloud config set core/project $GCP_PROJECT
输出应如下所示:
现在我们可以使用 gcloud 命令创建 GKE 集群。Knative 需要 1.11 版或更高版本的 Kubernetes 集群。我们将使用 GKE 为这个集群提供的 Istio 插件。以下是运行 Knative 组件的 Kubernetes 集群的建议配置:
- Kubernetes 版或更高版本
- 带四个虚电路的 Kubernetes 节点(n1-标准-4)
- 最多为 10 个节点启用节点自动缩放
- 云平台的应用编程接口范围
执行以下命令创建符合这些要求的 GKE 集群:
$ gcloud beta container clusters create $GKE_CLUSTER \
--zone=$GCP_ZONE \
--machine-type=n1-standard-4 \
--cluster-version=latest \
--addons=HorizontalPodAutoscaling,HttpLoadBalancing,Istio \
--enable-stackdriver-kubernetes \
--enable-ip-alias \
--enable-autoscaling --min-nodes=1 --max-nodes=10 \
--enable-autorepair \
--scopes cloud-platform
输出应如下所示:
设置 Kubernetes 集群可能需要几分钟时间。一旦集群准备就绪,我们将使用命令 gcloud 容器集群 get-credentials 来获取新集群的凭据,并配置 kubectl CLI,如以下代码片段所示:
$ gcloud container clusters get-credentials $GKE_CLUSTER --zone $GCP_ZONE --project $GCP_PROJECT
输出应如下所示:
现在,您已经使用 Istio 成功创建了 GKE 集群,并配置了 kubectl 来访问新创建的集群。我们现在可以继续下一步安装 Knative 了。我们将安装 Knative 版本 0.8,这是在撰写本书时可用的最新版本。
我们将使用 kubectl 命令行界面将知识组件应用于 Kubernetes 集群。首先,使用**-l knative.dev/crd-install=true**标志运行 kubectl apply 命令,以防止安装过程中出现争用情况:
$ kubectl apply --selector knative.dev/crd-install=true \
-f https://github.com/knative/serving/releases/download/v0.8.0/serving.yaml \
-f https://github.com/knative/eventing/releases/download/v0.8.0/release.yaml \
-f https://github.com/knative/serving/releases/download/v0.8.0/monitoring.yaml
接下来,在没有**-l knative.dev/crd-install=true**标志的情况下再次运行命令,完成安装:
$ kubectl apply -f https://github.com/knative/serving/releases/download/v0.8.0/serving.yaml \
-f https://github.com/knative/eventing/releases/download/v0.8.0/release.yaml \
-f https://github.com/knative/serving/releases/download/v0.8.0/monitoring.yaml
命令完成后,执行以下命令检查安装状态。确保所有 POD 都处于运行状态:
$ kubectl get pods --namespace knative-serving
$ kubectl get pods --namespace knative-eventing
$ kubectl get pods --namespace knative-monitoring
输出应如下所示:
在这个阶段,您已经在 GKE 建立了一个 Kubernetes 集群并安装了 Knative。现在,我们准备在 Knative 上部署我们的第一个应用。
在前面的部分中,我们成功地在 Kubernetes 和 Istio 之上部署了 Knative。在本练习中,我们将在 Knative 框架上部署我们的第一个应用。对于这个部署,我们将使用一个用 Node.js 编写的示例 web 应用。这些步骤可以适用于在 Docker Hub 或任何其他容器注册表上部署我们自己的 Docker 映像。
这个示例“hello world”应用将读取名为 TARGET 的环境变量,并打印 Hello < VALUE_OF_TARGET >!为输出。如果没有为目标环境变量定义值,它将打印未指定作为输出。
让我们从为应用创建服务定义文件开始。该文件定义了应用相关信息,包括应用名称和应用 Docker 映像:
Knative 服务对象和 Kubernetes 服务对象是两种不同的类型。
-
创建一个名为 hello-world.yaml 的文件,内容如下。这个 knactivity 服务对象定义了一些值,例如部署这个服务的名称空间、用于容器的 Docker 映像以及任何环境变量:
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: helloworld-nodejs namespace: default spec: runLatest: configuration: revisionTemplate: spec: container: image: gcr.io/knative-samples/helloworld-nodejs env: - name: TARGET value: "Knative NodeJS App"
-
Once the hello-world.yaml file is ready, we can deploy our application with the kubectl apply command:
$ kubectl apply -f hello-world.yaml
输出应如下所示:
-
The previous command will create multiple objects, including the Knative service, configuration, revision, route, and Kubernetes Deployment. We can verify the application by listing the newly created objects as in the following commands:
$ kubectl get ksvc $ kubectl get configuration $ kubectl get revision $ kubectl get route $ kubectl get deployments
输出应如下所示:
-
Once our application is deployed successfully, we can invoke this application using an HTTP request. For this, we need to identify the external IP address of the Kubernetes cluster. Execute the following command to export the value of EXTERNAL-IP into an environment variable named EXTERNAL_IP:
$ export EXTERNAL_IP=$(kubectl get svc istio-ingressgateway --namespace istio-system --output 'jsonpath={.status.loadBalancer.ingress[0].ip}')
输出应如下所示:
接下来,我们需要找到 helloworld-nodejs 应用的主机 URL。执行以下命令,记下网址列的值。该网址采用 http:// <应用名称>的形式。<命名空间>
$ kubectl get route helloworld-nodejs
输出应如下所示:
-
Now we can invoke our application using the EXTERNAL_IP and URL values that we noted in the earlier steps. Let's make a curl request with the following command:
$ curl -H "Host: helloworld-nodejs.default.example.com" http://${EXTERNAL_IP}
输出应如下所示:
你应该会收到预期的输出你好 Knative NodeJS App!。这表明我们已经成功地在 Knative 平台上部署并调用了第一个应用。
在前一节中,我们使用服务类型的 YAML 文件部署了我们的第一个 Knative 应用。部署服务时,它创建了多个其他对象,包括配置、修订和路由对象。在本节中,让我们讨论这些对象:
知识服务组件中有四种资源类型:
- 配置:定义应用的期望状态
- 修订版:跟踪配置变化的只读快照
- 路线:为修订版提供交通路线
- 服务:路线和配置的顶级容器
下图说明了这些组件之间的关系:
配置用于定义应用的期望状态。这将定义应用使用的容器映像以及所需的任何其他配置参数。每次更新配置时,都会创建一个新的版本。修订版是指代码和配置的快照。用于记录配置变化的历史。一条路由用于定义应用的流量路由策略,为应用提供一个 HTTP 端点。默认情况下,路线会将流量发送到由配置创建的最新版本。路线也可以配置为更高级的场景,包括将流量发送到特定的版本或根据定义的百分比将流量拆分到不同的版本。服务对象用于管理应用的整个生命周期。部署新应用时,需要手动创建配置和路由对象,但是服务可以通过自动创建和管理配置和路由对象来简化这一点。
在下一节中,我们将使用 canary 部署来部署带有 Knative 的应用。让我们首先了解金丝雀部署到底是什么。
Canary 部署是向生产环境推出新版本代码时使用的一种部署策略。这是一个将新版本的代码部署到生产环境中并将一小部分流量切换到新版本的防故障过程。这样,开发和部署团队可以在对生产流量影响最小的情况下验证新版本的代码。一旦验证完成,所有流量将切换到新版本。除了 canary 部署之外,还有其他几种部署类型,例如大爆炸部署、滚动部署和蓝绿色部署。
在我们在练习 16 、中部署的 helloworld-nodejs 应用中,我们使用了带有 spec.runLatest 字段的服务对象,该字段将所有流量定向到最新的可用版本。在下面的练习中,我们将使用单独的配置和路由对象,而不是服务对象。
有关 canary 部署技术的更多信息,请参考https://dev . to/mostly Jason/部署策略介绍-蓝-绿-canary-and-more-3a3 。
在本练习中,我们将实施一个加那利部署策略来使用 Knative 部署应用。首先,我们将部署应用的初始版本(版本 1),并将 100%的流量路由到该版本。接下来,我们将创建应用的版本 2,并将 50%的流量路由到版本 1,剩余的 50%路由到版本 2。最后,我们将更新路由,将 100%的流量发送到版本 2。
以下步骤将帮助您完成练习:
-
首先,从创建应用的初始版本( v1 )开始。创建一个名为的文件,包含以下内容。该应用使用了与我们之前使用的相同的 Docker 映像(gcr.io/knative-samples/helloworld-nodejs)并将 TARGET 环境变量设置为这是第一个版本- v1** :
apiVersion: serving.knative.dev/v1alpha1 kind: Configuration metadata: name: canary-deployment namespace: default spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-nodejs env: - name: TARGET value: "This is the first version - v1" ```**
-
Deploy the first version of the application with the kubectl apply command using the YAML file created in the previous step:
$ kubectl apply -f canary-deployment.yaml
输出应如下所示:
-
Let's get the revision name created by this configuration as we need this value in the next step. Execute the kubectl get configurations command and retrieve the value of the latestCreatedRevisionName field:
$ kubectl get configurations canary-deployment -o=jsonpath='{.status.latestCreatedRevisionName}'
输出应如下所示:
对我来说,从前面的命令返回的值是 canary-deployment-xgvl8 。请注意,您的价值会有所不同。
-
下一步是创建路线对象。让我们用以下内容创建一个名为canary-deployment-route . YAML的文件(请记住用您在上一步中注意到的修订名称替换 canary-deployment-xgvl8 )。在规范流量部分,您可以看到 100%的流量被路由到我们之前创建的版本:
apiVersion: serving.knative.dev/v1alpha1 kind: Route metadata: name: canary-deployment namespace: default spec: traffic: - revisionName: canary-deployment-xgvl8 percent: 100
-
Create the route object with the kubectl apply command:
$ kubectl apply -f canary-deployment-route.yaml
输出应如下所示:
-
Make a request to the application and observe the expected output of Hello This is the first version - v1!:
$ curl -H "Host: canary-deployment.default.example.com" "http://${EXTERNAL_IP}"
输出应如下所示:
-
一旦应用被成功调用,我们就可以部署应用的版本 2。用以下内容更新 canary-deployment.yaml 。在应用的版本 2 中,我们只需要将 TARGET 环境变量的值从更新,这是第一个版本- v1 到这是第二个版本-v2:T0
-
Apply the updated configuration with kubectl apply:
$ kubectl apply -f canary-deployment.yaml
输出应如下所示:
-
Now we can check the revisions created, while updating the configuration, using the kubectl get revisions command:
$ kubectl get revisions
输出应如下所示:
-
Let's get the latest revision created by the canary-deployment configuration:
```
$ kubectl get configurations canary-deployment -o=jsonpath='{.status.latestCreatedRevisionName}'
```
输出应如下所示:

###### 图 6.19:获取加那利部署配置的最新版本
- 现在是时候给我们新版本的应用发送一些流量了。更新加那利-部署-路线. yaml 的规范流量部分,将 50%的流量发送到旧版本,50%的流量发送到新版本:
```
apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
name: canary-deployment
namespace: default
spec:
traffic:
- revisionName: canary-deployment-xgvl8
percent: 50
- revisionName: canary-deployment-8pp4s
percent: 50
```
- Apply changes to the route using the following command:
```
$ kubectl apply -f canary-deployment-route.yaml
```
输出应如下所示:

###### 图 6.20:更新加那利部署路线
- 现在,我们可以多次调用该应用来观察流量如何在两个版本之间分割:
```
$ curl -H "Host: canary-deployment.default.example.com" "http://${EXTERNAL_IP}"
```
- 一旦我们成功验证了应用的版本 2,我们就可以更新canary-deployment-route . YAML将 100%的流量路由到最新版本:
```
apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
name: canary-deployment
namespace: default
spec:
traffic:
- revisionName: canary-deployment-xgvl8
percent: 0
- revisionName: canary-deployment-8pp4s
percent: 100
```
- Apply the changes to the route using the following command:
```
$ kubectl apply -f canary-deployment-route.yaml
```
输出应如下所示:

###### 图 6.21:更新加那利部署路线
- 现在多次调用应用,以验证所有流量都流向应用的版本 2:
```
$ curl -H "Host: blue-green-deployment.default.example.com" "http://${EXTERNAL_IP}"
```
在本练习中,我们成功地使用了配置和路由对象来执行 Knative 的 canary 部署。
Knative 预装了 Grafana,这是一个开源的度量分析和可视化工具。Grafana pod 在活动监控名称空间中可用,可通过以下命令列出:
$ kubectl get pods -l app=grafana -n knative-monitoring
输出应如下所示:
我们可以用 kubectl port-forward 命令暴露 Grafana UI,该命令将本地端口 3000 转发到 Grafana POD 的端口 3000 。打开新终端并执行以下命令:
$ kubectl port-forward $(kubectl get pod -n knative-monitoring -l app=grafana -o jsonpath='{.items[0].metadata.name}') -n knative-monitoring 3000:3000
输出应如下所示:
现在我们可以在 http://127.0.0.1:3000 上从我们的网页浏览器导航到 Grafana UI。
输出应如下所示:
Knative 的 Grafana 仪表板配备了多个仪表板,包括以下内容:
Knative 有一个内置的自动缩放功能,可以根据接收到的 HTTP 请求的数量自动缩放应用盒。这将在需求增加时增加料盒数量,在需求减少时减少料盒数量。当 POD 空闲且没有传入请求时,POD 计数将缩放至零。
Knative 使用自动缩放器和激活器两个组件来实现前面提到的功能。这些组件被部署为命名空间中的荚,正如您在下面的代码片段中看到的:
NAME READY STATUS RESTARTS AGE
activator-7c8b59d78-9kgk5 2/2 Running 0 15h
autoscaler-666c9bfcc6-vwrj6 2/2 Running 0 15h
controller-799cd5c6dc-p47qn 1/1 Running 0 15h
webhook-5b66fdf6b9-cbllh 1/1 Running 0 15h
activator 组件负责收集关于某个修订的并发请求数量的信息,并将这些值报告给 autoscaler。自动缩放组件将根据激活器报告的指标增加或减少 pods 的数量。默认情况下,自动缩放器将尝试通过向上或向下扩展 pod 来维持每个 pod 100 个并发请求。所有与可耐特自动缩放器相关的配置都存储在可耐特服务命名空间中名为配置-自动缩放器的配置映射中。Knative 也可以配置为使用由 Kubernetes 提供的水平 POD 自动缩放器 ( HPA )。HPA 将根据 CPU 使用情况自动缩放 POD。
在本练习中,我们将通过部署一个示例应用来执行 knactivity pod 自动缩放:
-
创建一个包含以下内容的自动缩放-app.yaml 服务定义文件。该文件定义了一个名为自动缩放应用的服务,该服务将使用gcr.io/knative-samples/autoscale-go:0.1Docker 示例映像。autoscaling.knative.dev/target用于配置每个 pod 并发请求的目标数量:
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: autoscale-app spec: runLatest: configuration: revisionTemplate: metadata: annotations: autoscaling.knative.dev/target: "10" spec: container: image: "gcr.io/knative-samples/autoscale-go:0.1"
-
Apply the service definition with the kubectl apply command:
$ kubectl apply -f autoscale-app.yaml
输出应如下所示:
-
Once the application is ready, we can generate a load to the autoscale-app application to observe the autoscaling. For this, we will use a load generator named hey. Download the hey binary using the following curl command.
$ curl -Lo hey https://storage.googleapis.com/hey-release/hey_linux_amd64
输出应如下所示:
-
Add execution permission to the hey binary and move it into the /usr/local/bin/ path:
$ chmod +x hey $ sudo mv hey /usr/local/bin/
输出应如下所示:
-
现在我们准备使用嘿工具生成负载。嘿工具在生成负载时支持多个选项。对于这个场景,我们将使用并发 50 的负载(带有 -c 标志)持续 60 秒(带有 -z 标志 ):
$ hey -z 60s -c 50 \ -host "autoscale-app.default.example.com" \ "http://${EXTERNAL_IP?}?sleep=1000"
-
In a separate terminal, watch for the number of pods created during the load:
$ kubectl get pods --watch
您将看到类似如下的输出:
NAME READY STATUS RESTARTS AGE autoscale-app-7jt29-deployment-9c9c4b474-4ttl2 3/3 Running 0 58s autoscale-app-7jt29-deployment-9c9c4b474-6pmjs 3/3 Running 0 60s autoscale-app-7jt29-deployment-9c9c4b474-7j52p 3/3 Running 0 63s autoscale-app-7jt29-deployment-9c9c4b474-dvcs6 3/3 Running 0 56s autoscale-app-7jt29-deployment-9c9c4b474-hmkzf 3/3 Running 0 62s
-
从 Grafana 打开Knative Serving-Scaling debug仪表盘,观察装载过程中自动缩放如何增加料盒计数,以及装载停止后如何将料盒计数减少回零,如下图截图所示:
我们已经成功配置了 Knative 的自动缩放器,并使用 Grafana 仪表板观察到自动缩放。
在前几节中,我们讨论了 Knative。我们学习了如何在 Kubernetes 集群上安装 Istio 和 Knative,以及如何使用 Knative 运行 Docker 映像。但是 Knative 平台的优势来自于使用 Istio 管理底层 Kubernetes 集群的操作开销。GKE 是来自谷歌云的受管 Kubernetes 服务,它将帮助我们管理 Kubernetes 主组件,但我们仍然必须自己管理所有的 Kubernetes 节点。
为了从开发人员那里抽象出所有的基础设施管理任务,谷歌引入了一项名为“云运行”的新服务。这是一个完全托管的平台,构建在 Knative 项目上,用于运行无状态的 HTTP 驱动的容器。云运行提供了与 Knative 相同的功能集,包括自动缩放、缩放到零、版本控制和事件。云运行作为谷歌云无服务器计算堆栈的最新成员,在谷歌云 Next '19 大会上推出。在撰写本书时,云运行服务仍处于测试阶段,仅在有限的几个地区可用。
现在让我们执行一个在谷歌云上部署容器的练习。
在本练习中,我们将在谷歌云运行平台上部署一个预构建的 Docker 映像。
以下步骤将帮助您完成练习:
-
Navigate to your GCP console from your browser and select Cloud Run from the menu (in the Compute category) as shown in the following figure:
-
点击创建服务按钮创建新服务。
-
Fill the create service form with the following values:
容器图片网址:gcr.io/knative-samples/helloworld-nodejs
部署平台:云运行(全托管)
位置:从选项中选择您喜欢的任何地区
服务名称: hello-world
认证:允许未经认证的调用
-
点击创建按钮。
-
Now we will be redirected to the deployed service page, which includes details about the newly deployed hello-world service. We can see that a revision has been created called hello-world-00001, as shown in the following figure:
-
Click on the URL link displayed to run the container. Note that the URL will be different for every new instance:
-
接下来,我们将通过更新 TARGET 环境变量来部署应用的新版本。导航回 GCP 控制台,点击部署新版本按钮。
-
From the Deploy revision to hello-world (us-central1) form, click on the SHOW OPTIONAL REVISION SETTINGS link, which will point us to the additional setting section:
-
Under the environment variables section, create a new environment variable named TARGET with the value Cloud Run Deployment:
-
点击部署按钮。
-
Now we can see the new revision of the hello-world application called hello-world-00002 with 100% of traffic being routed to the latest revision:

###### 图 6.37:hello-world 应用的新版本
- 再次单击网址运行更新的版本:
我们已经在谷歌云运行平台上成功部署了一个预构建的 Docker 映像。
Virtual Kubelet 是 Kubernetes 的 Kubelet 的开源实现,它充当一个 kubelet。这是来自云原生计算基金会 ( CNCF )的沙盒项目,2019 年 7 月 8 日发布了 Virtual Kubelet 的第一个主版本(v 1.0)。
在深入探讨虚拟库贝莱之前,让我们回顾一下库贝莱在库贝内特斯架构中是什么。kubelet 是运行在 Kubernetes 集群中每个节点上的代理,负责管理节点内的 pods。kubelet 从 Kubernetes API 获取指令,以识别要在节点上调度的 pods,并与节点的底层容器运行时(例如,Docker)交互,以确保所需数量的 pods 正在运行,并且它们是健康的。
除了管理 POD,kubelet 还执行其他几项任务:
- 用 POD 的当前状态更新 Kubernetes 应用编程接口
- 监控并向 Kubernetes 主节点报告节点运行状况指标,如 CPU、内存和磁盘利用率
- 从指定 POD 的 Docker 注册表中提取 Docker 映像
- 为 POD 创建和安装卷
- 为 API 服务器提供一个接口来执行命令,例如用于 POD 的 kubectl 日志、 kubectl exec 和 kubectl attach
下图显示了一个具有标准和虚拟 Kubernetes 的 Kubernetes 集群:
从 Kubernetes API 的角度来看,虚拟 Kubelet 将作为传统的 kubelet 出现。这将在现有的 Kubernetes 集群中运行,并将自己注册为 Kubernetes API 中的一个节点。虚拟库贝莱将以与库贝莱相同的方式运行和管理 POD。但与在节点内运行 pods 的 kubelet 相反,Virtual Kubelet 将利用外部服务来运行 pods。这将 Kubernetes 集群连接到其他服务,如无服务器容器平台。Virtual Kubelet 支持越来越多的提供商,包括:
- 阿里巴巴云弹性容器实例 ( ECI )
- AWS Fargate
- 天青批次
- 蔚蓝色容器实例 ( ACI )
- 立方〔t0〕容器运行时接口〔t1〕(〔T2〕喊〔T3〕
- 华为云容器实例 ( CCI )
- HashiCorp Nomad
- OpenStack Zun
在这些平台上运行豆荚带来了无服务器世界的好处。我们不必担心基础设施,因为它由云提供商管理。Pods 将根据收到的请求数量自动上下扩展。此外,我们只需为已利用的资源付费。
在本练习中,我们将与 ACI 提供商一起在 Azure Kubernetes 服务 ( AKS )上配置虚拟 Kubelet。在本练习中,我们将使用 Azure 中提供的以下服务。
- AKS: AKS 是 Azure 上托管的 Kubernetes 服务。
- ACI: ACI 为在 Azure 上运行容器提供托管服务。
- Azure Cloud Shell:一个交互式的、基于浏览器的 Shell,同时支持 Bash 和 PowerShell。
本练习需要具备以下先决条件:
- 微软 Azure 帐户
- 蓝色命令行界面
- Kubernetes CLI
- 舵
我们将使用 Azure Cloud Shell,它预装了前面提到的所有 CLIs:
-
Navigate to https://shell.azure.com/ to open Cloud Shell in a browser window. Select Bash from the Welcome to Azure Cloud Shell window:
-
Click on the Create storage button to create a storage account for Cloud Shell. Note that this is a one-time task purely for when we are using Cloud Shell for the first time:
“云壳”窗口将如下所示:
-
Once Cloud Shell is ready, we can start creating the AKS cluster.
首先,我们需要创建一个 Azure 资源组,允许我们对相关的 Azure 资源进行逻辑分组。执行以下命令,在美国西部(西部地区创建一个名为的无服务器 Kubernetes 资源组:
$ az group create --name serverless-kubernetes-group --location westus
输出应如下所示:
-
Register your subscription to use the Microsoft.Network namespace:
$ az provider register --namespace Microsoft.Networks
输出应如下所示:
-
Next, we will create an Azure Kubernetes cluster. The following command will create an AKS cluster named virtual-kubelet-cluster with one node. This command will take a few minutes to execute:
$ az aks create --resource-group serverless-kubernetes-group --name virtual-kubelet-cluster --node-count 1 --node-vm-size Standard_D2 --network-plugin azure --generate-ssh-keys
一旦 AKS 集群创建成功,前面的命令将返回一些包含集群详细信息的 JSON 输出:
-
Next, we need to configure the kubectl CLI to communicate with the newly created AKS cluster. Execute the az aks get-credentials command to download the credentials and configure the kubectl CLI to work with the virtual-kubelet-cluster cluster with the following command:
我们不需要安装 kubectl 命令行界面,因为 Cloud Shell 预装了 kubectl。
$ az aks get-credentials --resource-group serverless-kubernetes-group --name virtual-kubelet-cluster
输出应如下所示:
-
Now we can verify the connection to the cluster from Cloud Shell by executing the kubectl get nodes command, which will list the nodes available in the AKS cluster:
$ kubectl get nodes
输出应如下所示:
-
If this is the first time you are using the ACI service, you need to register the Microsoft.ContainerInstance provider with your subscription. We can check the registration state of the Microsoft.ContainerInstance provider with the following command:
$ az provider list --query "[?contains(namespace,'Microsoft.ContainerInstance')]" -o table
输出应如下所示:
-
If the RegistrationStatus column contains a value of NotRegistered, execute the az provider register command to register the Microsoft.ContainerInstance provider. If the RegistrationStatus column contains a value of Registered, you can continue to the next step:
$ az provider register --namespace Microsoft.ContainerInstance
输出应如下所示:
-
下一步是为舵柄创建必要的服务帐户和服务帐户对象。创建一个名为 tiller-rbac.yaml 的文件,代码如下:
```
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
```
- Then execute the kubectl apply command to create the necessary ServiceAccount and ClusterRoleBinding objects:
```
$ kubectl apply -f tiller-rbac.yaml
```
输出应如下所示:

###### 图 6.50:创建服务帐户和集群角色绑定对象
- Now we can configure Helm to use the tiller service account that we created in the previous step:
```
$ helm init --service-account tiller
```
输出应如下所示:

###### 图 6.51:配置舵杆
- Once all configurations are done, we can install Virtual Kubelet using the az aks install-connector command. We will be deploying both Linux and Windows connectors with the following command:
```
$ az aks install-connector \
--resource-group serverless-kubernetes-group \
--name virtual-kubelet-cluster \
--connector-name virtual-kubelet \
--os-type Both
```
输出应如下所示:

###### 图 6.52:安装虚拟库贝莱
- Once the installation is complete, we can verify it by listing the Kubernetes nodes. There will be two new nodes, one for Windows and one for Linux:
```
$ kubectl get nodes
```
输出应如下所示:

###### 图 6.53:列出 Kubernetes 节点
- Now we have Virtual Kubelet installed in the AKS cluster. We can deploy an application to a new node introduced by Virtual Kubelet. We will be creating a Kubernetes Deployment named hello-world with the microsoft/aci-helloworld Docker image.
我们需要添加一个**节点选择器**来将这个 pod 专门分配给虚拟库元素节点。请注意,默认情况下,Virtual Kubelet 节点会被污染,以防止在其上运行意外的 pods。我们需要给豆荚增加容忍度,以便为这些节点安排它们。
让我们创建一个名为 **hello-world.yaml** 的文件,内容如下:
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: microsoft/aci-helloworld
ports:
- containerPort: 80
nodeSelector:
kubernetes.io/role: agent
type: virtual-kubelet
beta.kubernetes.io/os: linux
tolerations:
- key: virtual-kubelet.io/provider
operator: Equal
value: azure
effect: NoSchedule
```
- Deploy the hello-world application with the kubectl apply command:
```
$ kubectl apply -f hello-world.yaml
```
输出应如下所示:

###### 图 6.54:创建 hello-world 部署
- Execute the kubectl get pods command with the -o wide flag to output a list of pods and their respective nodes. Note that the hello-world-57f597bc59-q9w9k pod has been scheduled on the virtual-kubelet-virtual-kubelet-linux-westus node:
```
$ kubectl get pods -o wide
```
输出应如下所示:
因此,我们已经成功地在带有 ACI 的 AKS 上配置了 Virtual Kubelet,并在 Virtual Kubelet 节点中部署了一个 pod。
现在,让我们完成一项活动,在无服务器环境中部署容器化应用。
假设您在一家初创公司工作,您的经理希望您创建一个应用,可以返回给定时区的当前日期和时间。该应用预计在初始阶段只接收几个请求,但从长远来看将接收数百万个请求。应用应该能够根据收到的请求数量自动扩展,无需任何修改。此外,您的经理不想承担管理基础架构的负担,希望该应用以尽可能低的成本运行。
执行以下步骤完成本活动:
-
Create an application (in any language you want) that can provide the current date and time based on the given timezone value.
以下是一些用 PHP 编写的示例应用代码:
<?php if ( !isset ( $_GET['timezone'] ) ) { // Returns error if the timezone parameter is not provided $output_message = "Error: Timezone not provided"; } else if ( empty ( $_GET['timezone'] ) ) { // Returns error if the timezone parameter value is empty $output_message = "Error: Timezone cannot be empty"; } else { // Save the timezone parameter value to a variable $timezone = $_GET['timezone']; try { // Generates the current time for the provided timezone $date = new DateTime("now", new DateTimeZone($timezone) ); $formatted_date_time = $date->format('Y-m-d H:i:s'); $output_message = "Current date and time for $timezone is $formatted_date_time"; } catch(Exception $e) { // Returns error if the timezone is invalid $output_message = "Error: Invalid timezone value"; } } // Return the output message echo $output_message;
-
Containerize the application according to the guidelines provided by Google Cloud Run.
以下是示例 Dockerfile 的内容:
# Use official PHP 7.3 image as base image FROM php:7.3-apache # Copy index.php file to the docker image COPY index.php /var/www/html/ # Replace port 80 with the value from PORT environment variable in apache2 configuration files RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf # Use the default production configuration file RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
-
将坞站映像推送到坞站注册表。
-
Run the application with Cloud Run.
输出应如下所示:
活动的解决方案可以在第 417 页找到。
在本章中,我们讨论了在 Kubernetes 上使用无服务器的优势。我们讨论了在 Kubernetes 集群上提供无服务器优势的三种技术。这些是 Knative、谷歌云运行和虚拟库布雷。
首先,我们用 Istio 创建了一个 GKE 集群,并在其上部署了 Knative。然后我们学习了如何在 Knative 上部署应用。接下来,我们讨论了 Knative 的服务组件,以及如何使用配置和路由对象执行 canary 部署。然后,我们讨论了对 Knative 的监控,并观察了 Knative 如何根据接收到的请求数量进行自动缩放。
我们还讨论了谷歌云运行,这是一个完全托管的平台,建立在 Knative 项目上,运行无状态的 HTTP 驱动的容器。然后,我们学习了如何使用云运行服务部署应用。
在最后一节,我们研究了 Virtual Kubelet,它是 Kubernetes 的 Kubelet 的开源实现。我们了解了正常库波莱和虚拟库波莱的区别。最后,我们在 AKS 集群上部署了 Virtual Kubelet,并在 Virtual Kubelet 节点上部署了一个应用。
在接下来的三章中,我们将重点介绍三种不同的 Kubernetes 无服务器框架,即 Kubeless、OpenWhisk 和 OpenFaaS。