在非高峰时段缩减 GKE 集群以减少费用

Last reviewed 2022-11-24 UTC

本教程介绍如何在 Google Kubernetes Engine (GKE) 上部署计划的自动扩缩器来降低费用。这种自动扩缩器会根据基于按一天中的时间或星期几的时间表来扩缩集群。如果您的流量具有可预测的 ebb 和流(例如,如果您是地区零售商,或者您的软件面向工作时间限制在一天中的特定时段的员工),则计划的自动扩缩器非常有用。

本教程适用于想要实现以下目的开发者和运营商:在高峰期到来之前可靠地将集群纵向扩容,并在夜间、周末或在线用户数较少的任何其他时间再次缩减,以节省费用。本文假设您熟悉 Docker、Kubernetes、Kubernetes CronJobs、GKE 和 Linux。

简介

许多应用都会遇到不均匀的流量模式。例如,组织中的员工可能仅在白天与应用交互。因此,该应用的数据中心服务器在夜间保持闲置状态。

除了其他好处之外,Google Cloud 还可以根据流量负载动态分配基础架构,从而帮助您节省费用。在某些情况下,简单的自动扩缩配置可以克服不均匀流量的分配难题。如果您遇到了此类难题,请使用简单的自动扩缩配置。但是,在其他情况下,流量模式的急剧变化需要更精细调整的自动扩缩配置,以避免在纵向扩容期间系统不稳定,以及避免超额预配集群。

本教程重点介绍了充分了解流量模式急剧变化的场景,您需要向自动扩缩器提供一条提示,告知基础架构将迎来高峰期。本文档展示了如何在早晨将 GKE 集群纵向扩容,在夜间进行缩减,但您可以使用类似的方法来针对任何已知事件(例如高峰期扩缩事件、广告系列、周末数据流量等等)增加和降低容量。

在具有承诺使用折扣的情况下缩减集群

本教程介绍如何在非高峰时段将 GKE 集群缩减至最低,从而降低费用。但是,如果您购买了承诺使用折扣,请务必了解如何将这些折扣与自动扩缩结合使用。

当您承诺购买一定数量的资源(vCPU、内存等)时,承诺使用折扣可给予您大幅度的折扣价格。但是,为了确定需要承诺的资源数量,您需要事先了解工作负载在一段时间内使用的资源数量。为了帮助您降低费用,下图说明了哪些资源应不应该包含在计划中。

资源分布:显示始终分配的承诺资源基数以及可根据需要(峰值)自动扩缩的资源数。

如图所示,承诺使用合同中的资源分配是固定的。必须在大部分时间使用合同涵盖的资源,以实现承诺的价值。因此,在计算承诺资源时,不应该纳入在高峰期使用的资源。对于在高峰期使用的资源,建议您使用 GKE 自动扩缩器选项。这些选项包含了本文中介绍的计划的自动扩缩器,或在 GKE 上运行费用经过优化的 Kubernetes 应用的最佳做法中所述的其他代管式选项。

如果您已有给定数量的资源的承诺使用合同,则不能通过将集群缩减到低于该最小值来降低费用。在此类情况下,建议您尝试计划一些作业以在计算需求较少的时段弥补空隙。

架构

下图显示了您在本教程中部署的基础架构和计划的自动扩缩器的架构。计划的自动扩缩器由一组组件组成,这些组件一起工作,以根据时间表管理扩缩。

该架构显示一起组成计划的自动扩缩器的组件。

在此架构中,一组 Kubernetes CronJobs 将有关流量模式的已知信息导出到 Cloud Monitoring 自定义指标。然后,Kubernetes Pod 横向自动扩缩器 (HPA) 会读取这些数据,作为确定 HPA 何时应扩缩工作负载的输入。结合其他负载指标(如目标 CPU 利用率),HPA 会确定如何扩缩给定部署的副本。

目标

  • 创建 GKE 集群。
  • 部署使用 Kubernetes HPA 的示例应用。
  • 为计划的自动扩缩器设置组件,并更新 HPA 以从计划的自定义指标中读取数据。
  • 设置提醒,以在计划的自动扩缩器无法正常运行时触发。
  • 生成应用的负载。
  • 检查 HPA 如何响应流量的正常增长以及您配置的计划的自定义指标。

本教程的代码位于 GitHub 代码库中。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 GKE, Artifact Registry and the Cloud Monitoring API。

    启用 API

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 GKE, Artifact Registry and the Cloud Monitoring API。

    启用 API

准备环境

  1. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。

  2. 在 Cloud Shell 中,配置您的 Google Cloud 项目 ID、电子邮件地址以及计算可用区和区域:

    PROJECT_ID=YOUR_PROJECT_ID
    ALERT_EMAIL=YOUR_EMAIL_ADDRESS
    gcloud config set project $PROJECT_ID
    gcloud config set compute/region us-central1
    gcloud config set compute/zone us-central1-f
    

    请替换以下内容:

    • YOUR_PROJECT_ID:您要使用的项目的 Google Cloud 项目名称。
    • YOUR_EMAIL_ADDRESS:用于在计划的自动扩缩器无法正常运行时接收通知的电子邮件地址。

    您可以根据需要为本教程选择其他地区和区域

  3. 克隆 kubernetes-engine-samples GitHub 代码库:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/
    cd kubernetes-engine-samples/cost-optimization/gke-scheduled-autoscaler
    

    此代码库中的代码会构建到以下文件夹中:

    • Root:包含 CronJobs 用于将自定义指标导出到 Cloud Monitoring 的代码。
    • k8s/:包含具有 Kubernetes HPA 的部署示例。
    • k8s/scheduled-autoscaler/:包含导出自定义指标的 CronJobs 和更新的 HPA 版本以从自定义指标中读取。
    • k8s/load-generator/:包含一个 Kubernetes 部署,其中含有可模拟每小时使用量的应用。
    • monitoring/:包含在本教程中配置的 Cloud Monitoring 组件。

创建 GKE 集群

  1. 在 Cloud Shell 中,创建用于运行计划自动扩缩器的 GKE 集群:

    gcloud container clusters create scheduled-autoscaler \
        --enable-ip-alias \
        --release-channel=stable \
        --machine-type=e2-standard-2 \
        --enable-autoscaling --min-nodes=1 --max-nodes=10 \
        --num-nodes=1 \
        --autoscaling-profile=optimize-utilization
    

    输出内容类似如下:

    NAME                   LOCATION       MASTER_VERSION   MASTER_IP      MACHINE_TYPE   NODE_VERSION     NUM_NODES  STATUS
    scheduled-autoscaler   us-central1-f  1.22.15-gke.100  34.69.187.253  e2-standard-2  1.22.15-gke.100  1          RUNNING
    

    这不是生产配置,而是适合本教程的配置。在此设置中,您需配置集群自动扩缩器(最少 1 个节点,最多 10 个节点)。您还可以启用 optimize-utilization 配置文件以加快缩减过程。

部署示例应用

  1. 部署不含计划的自动扩缩器的示例应用:

    kubectl apply -f ./k8s
    
  2. 打开 k8s/hpa-example.yaml 文件。

    以下列表显示了该文件的内容。

    spec:
      maxReplicas: 20
      minReplicas: 10
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: php-apache
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 60

    请注意,最小副本数 (minReplicas) 设置为 10。此配置还会设置集群,以根据 CPU 利用率(name: cputype: Utilization 设置)进行扩缩。

  3. 等待应用变得可用:

    kubectl wait --for=condition=available --timeout=600s deployment/php-apache
    EXTERNAL_IP=''
    while [ -z $EXTERNAL_IP ]
    do
        EXTERNAL_IP=$(kubectl get svc php-apache -o jsonpath={.status.loadBalancer.ingress[0].ip})
        [ -z $EXTERNAL_IP ] && sleep 10
    done
    curl -w '\n' http://$EXTERNAL_IP
    

    当应用可用时,输出如下所示:

    OK!
    
  4. 验证设置:

    kubectl get hpa php-apache
    

    输出内容类似如下:

    NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    php-apache   Deployment/php-apache   9%/60%    10        20        10         6d19h
    

    REPLICAS 列会显示 10,它与 hpa-example.yaml 文件中 minReplicas 字段的值匹配。

  5. 检查节点数是否已增加到 4:

    kubectl get nodes
    

    输出内容类似如下:

    NAME                                                  STATUS   ROLES    AGE   VERSION
    gke-scheduled-autoscaler-default-pool-64c02c0b-9kbt   Ready    <none>   21S   v1.17.9-gke.1504
    gke-scheduled-autoscaler-default-pool-64c02c0b-ghfr   Ready    <none>   21s   v1.17.9-gke.1504
    gke-scheduled-autoscaler-default-pool-64c02c0b-gvl9   Ready    <none>   21s   v1.17.9-gke.1504
    gke-scheduled-autoscaler-default-pool-64c02c0b-t9sr   Ready    <none>   21s   v1.17.9-gke.1504
    

    创建集群时,您可以使用 min-nodes=1 标志设置最低配置。但是,您在此过程开始时部署的应用请求更多基础架构,因为 hpa-example.yaml 文件中的 minReplicas 设置为 10。

    一些公司(例如零售商)预计在工作日的前几个小时内流量会突然增加,因此将 minReplicas 设置为 10 之类的值是他们常用的策略。但是,为 HPA minReplicas 设置较高的值可能会增加费用,因为集群无法缩减,甚至在夜间应用流量较低时也是如此。

安装计划的自动扩缩器

  1. 在 Cloud Shell 中,在 GKE 集群中安装自定义指标 - Cloud Monitoring 适配器

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    kubectl wait --for=condition=available --timeout=600s deployment/custom-metrics-stackdriver-adapter -n custom-metrics
    

    此适配器根据 Cloud Monitoring 自定义指标启用 Pod 自动扩缩。

  2. 在 Artifact Registry 中创建代码库并授予读取权限:

    gcloud artifacts repositories create gke-scheduled-autoscaler \
      --repository-format=docker --location=us-central1
    gcloud auth configure-docker us-central1-docker.pkg.dev
    gcloud artifacts repositories add-iam-policy-binding gke-scheduled-autoscaler \
       --location=us-central1 --member=allUsers --role=roles/artifactregistry.reader
    
  3. 构建并推送自定义指标导出器代码:

    docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/gke-scheduled-autoscaler/custom-metric-exporter .
    docker push us-central1-docker.pkg.dev/$PROJECT_ID/gke-scheduled-autoscaler/custom-metric-exporter
    
  4. 部署 CronJobs,其会导出自定义指标,并部署更新的 HPA 版本以用于从以下自定义指标中读取数据:

    sed -i.bak s/PROJECT_ID/$PROJECT_ID/g ./k8s/scheduled-autoscaler/scheduled-autoscale-example.yaml
    kubectl apply -f ./k8s/scheduled-autoscaler
    
  5. 打开并检查 k8s/scheduled-autoscaler/scheduled-autoscale-example.yaml 文件。

    以下列表显示了该文件的内容。

    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: scale-up
    spec:
      schedule: "50-59/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: custom-metric-extporter
                image: us-central1-docker.pkg.dev/PROJECT_ID/gke-scheduled-autoscaler/custom-metric-exporter
                command:
                  - /export
                  - --name=scheduled_autoscaler_example
                  - --value=10
              restartPolicy: OnFailure
          backoffLimit: 1
    ---
    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: scale-down
    spec:
      schedule: "1-49/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: custom-metric-extporter
                image: us-central1-docker.pkg.dev/PROJECT_ID/gke-scheduled-autoscaler/custom-metric-exporter
                command:
                  - /export
                  - --name=scheduled_autoscaler_example
                  - --value=1
              restartPolicy: OnFailure
          backoffLimit: 1

    此配置指定 CronJobs 应该根据一天中的时间将建议的 Pod 副本数量导出到名为 custom.googleapis.com/scheduled_autoscaler_example 的自定义指标。为了方便本教程监控部分的工作,时间表字段配置定义了每小时纵向扩容和缩减。对于生产环境,您可以自定义此时间表以满足您的业务需求。

  6. 打开并检查 k8s/scheduled-autoscaler/hpa-example.yaml 文件。

    以下列表显示了该文件的内容。

    spec:
      maxReplicas: 20
      minReplicas: 1
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: php-apache
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 60
      - type: External
        external:
          metric:
            name: custom.googleapis.com|scheduled_autoscaler_example
          target:
              type: AverageValue
              averageValue: 1

    此配置指定 HPA 对象应取代之前部署的 HPA。请注意,该配置会将 minReplicas 中的值减小到 1。这意味着工作负载可以缩减到其最小值。该配置还会添加外部指标 (type: External)。此添加意味着自动扩缩现在由两个因素触发。

    在这种多指标情况下,HPA 会计算每个指标的建议副本数量,然后选择返回最高值的指标。请务必了解这一点 - 计划的自动扩缩器可能会建议在给定时间 Pod 数量应是 1。但是,如果单个 Pod 的实际 CPU 利用率高于预期,则 HPA 会创建更多副本。

  7. 再次运行以下每个命令,以再次检查节点数量和 HPA 副本数量:

    kubectl get nodes
    kubectl get hpa php-apache
    

    您看到的输出取决于计划的自动扩缩器最近执行的操作 - 具体来说,在扩缩周期内不同时间点,minReplicasnodes 的值有所不同。

    例如,在每小时的大约 51 到 60 分钟(代表流量高峰时段)期间,minReplicas 的 HPA 值为 10,nodes 的值为 4。

    相比之下,对于 1 到 50 分钟(表示流量较低时段),minReplicas 的 HPA 值将为 1,nodes 值将为 1 或 2,具体取决于已分配和已移除的 Pod 数量。对于较低的值(1 到 50 分钟),集群可能需要长达 10 分钟才能完成缩减。

配置当计划的自动扩缩器无法正常运行时的提醒

在生产环境中,您通常需要知道 CronJobs 何时不会填充自定义指标。为此,您可以创建一个提醒,该提醒会在任何 custom.googleapis.com/scheduled_autoscaler_example 流不存在达到五分钟时触发。

  1. 在 Cloud Shell 中,创建通知渠道:

    gcloud beta monitoring channels create \
        --display-name="Scheduled Autoscaler team (Primary)" \
        --description="Primary contact method for the Scheduled Autoscaler team lead"  \
        --type=email \
        --channel-labels=email_address=${ALERT_EMAIL}
    

    输出内容类似如下:

    Created notification channel NOTIFICATION_CHANNEL_ID.
    

    此命令会创建一个类型为 email通知渠道,以简化教程步骤。在生产环境中,建议您通过将通知渠道设置为 smspagerduty,使用同步程度较高的策略。

  2. 设置一个变量,其具有 NOTIFICATION_CHANNEL_ID 占位符中显示的值:

    NOTIFICATION_CHANNEL_ID=NOTIFICATION_CHANNEL_ID
    
  3. 部署提醒政策:

    gcloud alpha monitoring policies create \
        --policy-from-file=./monitoring/alert-policy.yaml \
        --notification-channels=$NOTIFICATION_CHANNEL_ID
    

    alert-policy.yaml 文件包含用于在指标在 5 分钟后不存在时发送提醒的指定内容。

  4. 转到 Cloud Monitoring 提醒页面以查看提醒政策。

    转到提醒

  5. 点击计划的自动扩缩器政策,并验证提醒政策的详细信息。

为示例应用生成负载

  • 在 Cloud Shell 中,部署负载生成器:

    kubectl apply -f ./k8s/load-generator
    

    以下列表显示了 load-generator 脚本:

    command: ["/bin/sh", "-c"]
    args:
    - while true; do
        RESP=$(wget -q -O- http://php-apache.default.svc.cluster.local);
        echo "$(date +%H)=$RESP";
        sleep $(date +%H | awk '{ print "s("$0"/3*a(1))*0.5+0.5" }' | bc -l);
      done;
    

    该脚本在集群中运行,直到您删除 load-generator 部署为止。它每隔几毫秒就会向您的 php-apache 服务发出请求。sleep 命令会模拟一天中的负载分布变化。通过使用以这种方式生成流量的脚本,您可以了解在 HPA 配置中结合使用 CPU 利用率和自定义指标时发生的情况。

直观呈现根据流量或计划指标扩缩

在本部分中,您将查看展示纵向扩容和缩减效果的直观呈现。

  1. 在 Cloud Shell 中,创建一个新的信息中心:

    gcloud monitoring dashboards create \
        --config-from-file=./monitoring/dashboard.yaml
    
  2. 转到 Cloud Monitoring 信息中心页面:

    转到“信息中心”

  3. 点击计划的自动扩缩器信息中心

    信息中心会显示三个图表。您至少需要等待 2 小时(理想情况下,否则是 24 小时或更长时间)才能看到纵向扩容和缩减的动态,以及看到一天中不同的负载分布如何影响自动扩缩。

    如需了解该图表显示的内容,您可以研究以下图表,它们显示了一整天的视图:

    • 计划的指标(需要的 Pod 数量)显示了自定义指标的时间序列;您通过在设置计划的自动扩缩器中配置的 CronJobs 将这些自定义指标导出到 Cloud Monitoring。

      Pod 需求图表,显示了每小时峰值。

    • CPU 利用率(请求与使用)显示请求的 CPU(红色)和实际 CPU 利用率(蓝色)的时间序列。当负载较低时,HPA 会遵循计划的自动扩缩器的利用率决策。但是,当数据流量增加时,HPA 会根据需要增加 Pod 的数量,如您在中午 12 点到下午 6 点之间可以看到的数据点。

      CPU 利用率图表,显示了一天内在下午 4 点前需求不断增长,然后下降。

    • Pod 数量(计划和实际)+ 平均 CPU 利用率显示与前面的视图类似的视图。Pod 数量(红色)增加到每小时的 10 个,如计划的(蓝色)一样。Pod 数量会随着时间的推移根据负载自然增加和减少(中午 12 点到下午 6 点)。平均 CPU 利用率(橙色)保持低于您设置的目标 (60%)。

      2 个图表。一个图表显示每小时的 Pod 需求及需求激增。另一个图表显示 CPU 利用率上下浮动,但不超过配置的最高值。

清除数据

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤