本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
Kubernetes 中的自动缩放
编者注:本文是 Kubernetes 1.3 新功能系列深度文章的一部分。
使用 Kubernetes 的客户可以快速响应最终用户请求,并以前所未有的速度交付软件。但是,如果您构建的服务比您计划的更受欢迎,并且计算资源耗尽,会发生什么?在Kubernetes 1.3中,我们自豪地宣布我们有一个解决方案:自动扩缩容。在Google Compute Engine (GCE) 和Google Container Engine (GKE) 上(即将在AWS上推出),Kubernetes 会在您需要时自动扩展您的集群,并在您不需要时将其缩减以节省您的资金。
自动扩缩容的优势
为了更好地理解自动扩缩容在哪些方面能够提供最大的价值,让我们从一个例子开始。假设您有一个 24/7 全天候生产服务,其负载随时间变化,在美国白天非常繁忙,而在晚上相对较低。理想情况下,我们希望集群中的节点数量和部署中的 Pod 数量能够动态调整以适应负载,以满足最终用户的需求。新的集群自动扩缩容功能与 Horizontal Pod Autoscaler 可以自动为您处理这个问题。
在 GCE 上设置自动扩缩容
以下说明适用于 GCE。对于 GKE,请查看此处提供的集群操作手册中的自动扩缩容部分。
在开始之前,我们需要一个启用了 Google Cloud Monitoring、Google Cloud Logging 和 Stackdriver 的活动 GCE 项目。有关项目创建的更多信息,请阅读我们的入门指南。我们还需要下载最新版本的 Kubernetes 项目(v1.3.0或更高版本)。
首先,我们设置一个启用了集群自动扩缩容的集群。集群中的节点数量将从 2 个开始,并自动扩展到最多 5 个。要实现这一点,我们将导出以下环境变量
export NUM\_NODES=2
export KUBE\_AUTOSCALER\_MIN\_NODES=2
export KUBE\_AUTOSCALER\_MAX\_NODES=5
export KUBE\_ENABLE\_CLUSTER\_AUTOSCALER=true
并通过运行以下命令启动集群
./cluster/kube-up.sh
kube-up.sh 脚本会创建一个带有集群自动扩缩容插件的集群。如果存在可以在新节点上调度的待处理 Pod,则自动扩缩容器将尝试向集群添加新节点。
让我们看看我们的集群,它应该有两个节点
$ kubectl get nodes
NAME STATUS AGE
kubernetes-master Ready,SchedulingDisabled 2m
kubernetes-minion-group-de5q Ready 2m
kubernetes-minion-group-yhdx Ready 1m
运行并公开 PHP-Apache 服务器
为了演示自动扩缩容,我们将使用一个基于 php-apache 服务器的自定义 Docker 镜像。该镜像可以在此处找到。它定义了index.php页面,该页面执行一些 CPU 密集型计算。
首先,我们将启动一个运行该镜像的部署,并将其公开为服务
$ kubectl run php-apache \
--image=gcr.io/google\_containers/hpa-example \
--requests=cpu=500m,memory=500M --expose --port=80
service "php-apache" createddeployment "php-apache" created
现在,我们将等待一段时间,并验证部署和服务是否已正确创建并正在运行
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
php-apache 1 1 1 1 49s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
php-apache-2046965998-z65jn 1/1 Running 0 30s
我们现在可以通过使用服务的地址调用 wget 来检查 php-apache 服务器是否正常工作
$ kubectl run -i --tty service-test --image=busybox /bin/sh
Hit enter for command prompt
$ wget -q -O- http://php-apache.default.svc.cluster.local
OK!
启动 Horizontal Pod Autoscaler
现在部署正在运行,我们将为其创建一个 Horizontal Pod Autoscaler。要创建它,我们将使用 kubectl autoscale 命令,如下所示
$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
这定义了一个 Horizontal Pod Autoscaler,它维护我们在这些说明的第一步中创建的 php-apache 部署所控制的 Pod 的副本数量在 1 到 10 个之间。粗略地说,水平自动扩缩容器将增加和减少副本数量(通过部署),以便在所有 Pod 中保持平均 CPU 利用率为 50%(由于每个 Pod 通过kubectl run请求 500 毫核,这意味着平均 CPU 使用率为 250 毫核)。有关该算法的更多详细信息,请参阅此处。
我们可以通过运行以下命令来检查自动扩缩容器的当前状态
$ kubectl get hpa
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
php-apache Deployment/php-apache/scale 50% 0% 1 20 14s
请注意,当前 CPU 消耗为 0%,因为我们没有向服务器发送任何请求(CURRENT 列显示相应副本控制器控制的所有 Pod 的平均值)。
提高负载
现在,我们将看到我们的自动扩缩容器(集群自动扩缩容器和 Horizontal Pod Autoscaler)如何对服务器负载的增加做出反应。我们将启动两个向我们服务器发送查询的无限循环(请在不同的终端中运行它们)
$ kubectl run -i --tty load-generator --image=busybox /bin/sh
Hit enter for command prompt
$ while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
我们需要等待片刻(大约一分钟)才能传播统计信息。之后,我们将检查 Horizontal Pod Autoscaler 的状态
$ kubectl get hpa
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
php-apache Deployment/php-apache/scale 50% 310% 1 20 2m
$ kubectl get deployment php-apache
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
php-apache 7 7 7 3 4m
Horizontal Pod Autoscaler 已将我们部署中的 Pod 数量增加到 7 个。现在让我们检查一下,是否所有 Pod 都在运行
jsz@jsz-desk2:~/k8s-src$ kubectl get pods
php-apache-2046965998-3ewo6 0/1 Pending 0 1m
php-apache-2046965998-8m03k 1/1 Running 0 1m
php-apache-2046965998-ddpgp 1/1 Running 0 5m
php-apache-2046965998-lrik6 1/1 Running 0 1m
php-apache-2046965998-nj465 0/1 Pending 0 1m
php-apache-2046965998-tmwg1 1/1 Running 0 1m
php-apache-2046965998-xkbw1 0/1 Pending 0 1m
我们可以看到,一些 Pod 处于待处理状态。让我们描述其中一个待处理的 Pod,以了解其待处理状态的原因
$ kubectl describe pod php-apache-2046965998-3ewo6
Name: php-apache-2046965998-3ewo6
Namespace: default
...
Events:
FirstSeen From SubobjectPath Type Reason Message
1m {default-scheduler } Warning FailedScheduling pod (php-apache-2046965998-3ewo6) failed to fit in any node
fit failure on node (kubernetes-minion-group-yhdx): Insufficient CPU
fit failure on node (kubernetes-minion-group-de5q): Insufficient CPU
1m {cluster-autoscaler } Normal TriggeredScaleUp pod triggered scale-up, mig: kubernetes-minion-group, sizes (current/new): 2/3
该 Pod 处于待处理状态,因为系统中没有 CPU 可供它使用。我们看到有一个与 Pod 关联的 TriggeredScaleUp 事件。这意味着该 Pod 触发了集群自动扩缩容器的反应,并且将向集群添加一个新节点。现在我们将等待反应(大约 3 分钟)并列出所有节点
$ kubectl get nodes
NAME STATUS AGE
kubernetes-master Ready,SchedulingDisabled 9m
kubernetes-minion-group-6z5i Ready 43s
kubernetes-minion-group-de5q Ready 9m
kubernetes-minion-group-yhdx Ready 9m
正如我们所见,集群自动扩缩容器添加了一个新节点 kubernetes-minion-group-6z5i。让我们验证所有 Pod 现在是否都在运行
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
php-apache-2046965998-3ewo6 1/1 Running 0 3m
php-apache-2046965998-8m03k 1/1 Running 0 3m
php-apache-2046965998-ddpgp 1/1 Running 0 7m
php-apache-2046965998-lrik6 1/1 Running 0 3m
php-apache-2046965998-nj465 1/1 Running 0 3m
php-apache-2046965998-tmwg1 1/1 Running 0 3m
php-apache-2046965998-xkbw1 1/1 Running 0 3m
添加节点后,所有 php-apache Pod 都在运行!
停止负载
我们将通过停止用户负载来完成我们的示例。我们将终止向服务器发送请求的两个无限 while 循环,并验证结果状态
$ kubectl get hpa
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
php-apache Deployment/php-apache/scale 50% 0% 1 10 16m
$ kubectl get deployment php-apache
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
php-apache 1 1 1 1 14m
正如我们所见,在本例中,CPU 利用率下降到 0,副本数量下降到 1。
删除 Pod 后,大多数集群资源都未使用。缩减集群可能比扩展集群花费更多时间,因为集群自动扩缩容器会确保该节点确实不需要,这样短时间的 inactivate(由于 Pod 升级等)就不会触发节点删除(请参阅集群自动扩缩容器文档)。大约 10-12 分钟后,您可以验证集群中的节点数量是否已减少
$ kubectl get nodes
NAME STATUS AGE
kubernetes-master Ready,SchedulingDisabled 37m
kubernetes-minion-group-de5q Ready 36m
kubernetes-minion-group-yhdx Ready 36m
我们集群中的节点数量现在又回到了两个,因为集群自动扩缩容器删除了节点 kubernetes-minion-group-6z5i。
其他用例
正如我们所展示的,使用 Horizontal Pod Autoscaler 和集群自动扩缩容器的组合可以很容易地动态调整 Pod 的数量以适应负载。
然而,当集群负载出现不规则情况时,单独使用集群自动扩缩容器也可能非常有帮助。例如,与开发或持续集成测试相关的集群在周末或晚上可能不需要那么多。批处理集群可能有段时间所有作业都已结束,新的作业只会在几个小时后开始。拥有闲置的机器是浪费金钱。
在所有这些情况下,集群自动扩缩容器可以减少未使用的节点数量,并节省大量成本,因为您只需为实际需要运行 Pod 的节点付费。它还可以确保您始终拥有足够的计算能力来运行您的任务。