PHP `Kubernetes` `Horizontal Pod Autoscaler` (HPA) 与 `Custom Metrics`

大家好!今天咱们来聊聊 PHP 应用在 Kubernetes 里如何借助 Horizontal Pod Autoscaler (HPA) 和 Custom Metrics 实现真正的弹性伸缩。别害怕,虽然听起来高大上,其实原理很简单,咱们一起一步一步把它拿下。

第一章:HPA 基础 – 伸缩,就是要恰到好处!

HPA,Horizontal Pod Autoscaler,水平 Pod 自动伸缩器。它的作用是根据你的应用负载情况,自动调整 Pod 的数量。想象一下,你开了一家面馆,中午人山人海,晚上门可罗雀。HPA 就像一个聪明的店长,自动增加或减少面馆的座位(Pod),让顾客始终有地方坐,又不会浪费资源。

HPA 默认支持根据 CPU 和内存的使用率进行伸缩。简单来说,就是当你的 Pod 的 CPU 或内存使用率超过了你设定的阈值,HPA 就会自动增加 Pod 的数量;反之,如果使用率过低,就会减少 Pod 的数量。

配置一个基于 CPU 使用率的 HPA

假设你已经有一个部署好的 PHP 应用,并且有一个名为 my-php-app 的 Deployment。现在,我们来创建一个 HPA,让它根据 CPU 使用率自动伸缩。

首先,创建一个 YAML 文件,比如 hpa.yaml

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: my-php-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-php-app
  minReplicas: 1  # 最小 Pod 数量
  maxReplicas: 10 # 最大 Pod 数量
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70 # 目标 CPU 使用率,70%

解释一下:

  • apiVersion: API 版本,autoscaling/v2beta2 是推荐的版本。
  • kind: 资源类型,这里是 HorizontalPodAutoscaler
  • metadata.name: HPA 的名称,随便起,但要有意义。
  • spec.scaleTargetRef: 指向要伸缩的 Deployment。
    • apiVersion: Deployment 的 API 版本。
    • kind: 资源类型,这里是 Deployment
    • name: Deployment 的名称。
  • spec.minReplicas: 最小 Pod 数量,至少要有一个 Pod 运行。
  • spec.maxReplicas: 最大 Pod 数量,防止 Pod 数量过多,浪费资源。
  • spec.metrics: 伸缩的指标。
    • type: 指标类型,这里是 Resource,表示 CPU 或内存等资源。
    • resource: 资源指标的详细信息。
      • name: 资源名称,这里是 cpu
      • target: 目标值。
        • type: 目标类型,Utilization 表示平均使用率。
        • averageUtilization: 目标 CPU 使用率,这里是 70%。

保存好 hpa.yaml 文件后,使用 kubectl 命令创建 HPA:

kubectl apply -f hpa.yaml

查看 HPA 的状态:

kubectl get hpa my-php-app-hpa

如果一切顺利,你应该能看到类似这样的输出:

NAME             REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
my-php-app-hpa   Deployment/my-php-app   0%/70%    1         10        1          1m

TARGETS 列显示的是当前的 CPU 使用率和目标 CPU 使用率。REPLICAS 列显示的是当前的 Pod 数量。

测试 HPA

为了验证 HPA 是否正常工作,我们可以模拟高 CPU 负载。可以使用 stress 命令:

kubectl exec -it <pod-name> -- stress --cpu 8 --timeout 60s

其中 <pod-name> 是你的 PHP 应用 Pod 的名称。这条命令会在 Pod 中启动 8 个 CPU 密集型进程,持续 60 秒。

观察 HPA 的状态,你应该能看到 TARGETS 列的 CPU 使用率逐渐升高,REPLICAS 列的 Pod 数量也随之增加。

第二章:Custom Metrics – HPA 的超能力!

默认的 CPU 和内存指标对于某些应用来说可能不够用。例如,你的 PHP 应用可能需要根据请求队列的长度、活跃用户数或者自定义的业务指标进行伸缩。这时,就需要用到 Custom Metrics(自定义指标)。

Custom Metrics 允许你将应用内部的指标暴露给 Kubernetes,然后 HPA 就可以根据这些指标进行伸缩。

Custom Metrics 的架构

Custom Metrics 的实现通常需要以下几个组件:

  1. 你的 PHP 应用: 负责收集和暴露自定义指标。
  2. Metrics Server 或 Prometheus: 负责从你的应用收集指标数据。
  3. Custom Metrics API Server: 负责将 Metrics Server 或 Prometheus 收集到的指标数据暴露给 Kubernetes API。
  4. HPA: 从 Custom Metrics API Server 获取指标数据,并根据指标值进行伸缩。

第一步:暴露自定义指标 (PHP)

首先,你需要修改你的 PHP 应用,将自定义指标暴露出来。有很多方法可以实现,最常见的是使用 HTTP endpoint。

例如,你可以创建一个名为 /metrics 的 endpoint,返回一个 JSON 格式的指标数据:

<?php

// metrics.php

// 假设你有一个请求队列的长度指标
$queueLength = getQueueLength();

header('Content-Type: application/json');
echo json_encode([
    'queue_length' => $queueLength,
]);

function getQueueLength() {
  //  从你的消息队列(例如 Redis, RabbitMQ)获取队列长度
  //  这里只是一个示例
  return rand(0, 100);
}

第二步:部署 Metrics Server 或 Prometheus

Metrics Server 比较轻量级,适合简单的场景。Prometheus 功能更强大,适合复杂的监控需求。这里我们以 Prometheus 为例。

  1. 安装 Prometheus: 可以使用 Helm 安装 Prometheus。

    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update
    helm install my-prometheus prometheus-community/kube-prometheus-stack
  2. 配置 Prometheus 抓取 PHP 应用的指标: 你需要创建一个 ServiceMonitor 对象,告诉 Prometheus 如何找到你的 PHP 应用的 /metrics endpoint。

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      name: my-php-app-metrics
      labels:
        release: my-prometheus # 与你的 Prometheus Helm Release 名称匹配
    spec:
      selector:
        matchLabels:
          app: my-php-app # 与你的 PHP 应用 Pod 的 labels 匹配
      endpoints:
      - port: http # 你的 PHP 应用监听的端口名称
        path: /metrics #  metrics endpoint 路径
        interval: 30s #  抓取指标的间隔时间

    解释一下:

    • apiVersion: ServiceMonitor 的 API 版本。
    • kind: 资源类型,这里是 ServiceMonitor
    • metadata.name: ServiceMonitor 的名称。
    • metadata.labels.release: 必须与你的 Prometheus Helm Release 名称匹配。
    • spec.selector.matchLabels: 用于选择要监控的 Service,通常与你的 PHP 应用 Pod 的 labels 匹配。
    • spec.endpoints: 定义 Prometheus 如何抓取指标。
      • port: 你的 PHP 应用监听的端口名称。确保你的 Service 定义中包含这个端口。
      • path: /metrics endpoint 路径。
      • interval: 抓取指标的间隔时间。

    创建 ServiceMonitor:

    kubectl apply -f servicemonitor.yaml

第三步:部署 Custom Metrics API Server

Custom Metrics API Server 负责将 Prometheus 收集到的指标数据暴露给 Kubernetes API。

  1. 安装 kube-prometheus-adapter: kube-prometheus-adapter 是一个常用的 Custom Metrics API Server,它可以从 Prometheus 获取指标数据。

    helm repo add k8s-prometheus-adapter https://kubernetes-sigs.github.io/prometheus-adapter
    helm repo update
    helm install my-prometheus-adapter k8s-prometheus-adapter/prometheus-adapter 
    --set prometheus.url="http://my-prometheus-kube-prometheus-prometheus.default.svc" 
    --set prometheus.port=9090 
    --set mapping.config.name=adapter-config

    其中 prometheus.urlprometheus.port 需要根据你的 Prometheus Service 的地址和端口进行调整。 my-prometheus-kube-prometheus-prometheus.default.svc 是我的 prometheus service 的 name。 你要替换成你自己的。

  2. 配置 kube-prometheus-adapter: 你需要创建一个 ConfigMap,告诉 kube-prometheus-adapter 如何从 Prometheus 获取你的自定义指标。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: adapter-config
      namespace: default #  确保与你的 prometheus-adapter 部署的 namespace 相同
    data:
      config.yaml: |
        rules:
        - seriesQuery: 'queue_length'  # Prometheus 查询语句,用于获取指标数据
          resources:
            overrides:
              k8s.io/pod.name:
                resource: pod
          name:
            asMatch: "queue_length" # 指标名称,用于 HPA 配置
          metricsQuery: sum(queue_length) by (<<.GroupBy>>)

    解释一下:

    • rules.seriesQuery: Prometheus 查询语句,用于获取指标数据。这里假设你的指标名称是 queue_length
    • rules.resources.overrides: 定义如何将指标与 Kubernetes 资源关联起来。这里我们将指标与 Pod 关联起来。
    • rules.name.asMatch: 指标名称,用于 HPA 配置。

    创建 ConfigMap:

    kubectl apply -f adapter-config.yaml

第四步:创建基于 Custom Metrics 的 HPA

现在,你可以创建一个 HPA,让它根据你的自定义指标进行伸缩。

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: my-php-app-hpa-custom
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-php-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: External
    external:
      metric:
        name: queue_length #  Custom Metrics 的名称,与 adapter-config.yaml 中定义的 name.asMatch 匹配
        selector:
          matchLabels:
            app: my-php-app #  与你的 PHP 应用 Pod 的 labels 匹配
      target:
        type: AverageValue
        averageValue: 20  # 目标队列长度,20

解释一下:

  • spec.metrics.type: 指标类型,这里是 External,表示 Custom Metrics。
  • spec.metrics.external: Custom Metrics 的详细信息。
    • metric.name: Custom Metrics 的名称,必须与 adapter-config.yaml 中定义的 name.asMatch 匹配
    • metric.selector.matchLabels: 用于选择要监控的资源,通常与你的 PHP 应用 Pod 的 labels 匹配。
    • target.type: 目标类型,AverageValue 表示平均值。
    • target.averageValue: 目标队列长度,这里是 20。

创建 HPA:

kubectl apply -f hpa-custom.yaml

查看 HPA 的状态:

kubectl get hpa my-php-app-hpa-custom

如果一切顺利,你应该能看到类似这样的输出:

NAME                  REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
my-php-app-hpa-custom   Deployment/my-php-app   10/20     1         10        1          1m

TARGETS 列显示的是当前的队列长度和目标队列长度。REPLICAS 列显示的是当前的 Pod 数量。

测试 HPA (Custom Metrics)

为了验证 HPA 是否正常工作,你可以模拟增加队列长度。修改你的 getQueueLength() 函数,让它返回一个更大的值:

<?php

// metrics.php

$queueLength = getQueueLength();

header('Content-Type: application/json');
echo json_encode([
    'queue_length' => $queueLength,
]);

function getQueueLength() {
  //  模拟增加队列长度
  return rand(50, 150);
}

重新部署你的 PHP 应用,观察 HPA 的状态,你应该能看到 TARGETS 列的队列长度逐渐升高,REPLICAS 列的 Pod 数量也随之增加。

第三章:一些实用技巧和注意事项

  • 指标的稳定性: 选择稳定、可靠的指标。如果指标波动太大,HPA 可能会频繁地调整 Pod 数量,造成不必要的资源浪费。
  • 伸缩的步长: HPA 默认每次调整 Pod 数量的步长是 1。如果你的应用需要更大的伸缩力度,可以调整 HPA 的算法。
  • 冷却时间: HPA 在伸缩后会有一个冷却时间,防止频繁伸缩。可以根据你的应用特性调整冷却时间。
  • 监控和告警: 监控 HPA 的状态,并设置告警,以便及时发现问题。
  • 资源限制: 为你的 Pod 设置资源限制(CPU 和内存),防止 Pod 占用过多资源,影响其他应用。
  • 优雅关闭: 确保你的 PHP 应用能够优雅关闭,避免请求丢失。Kubernetes 会在删除 Pod 之前发送一个 SIGTERM 信号,你的应用应该监听这个信号,并在关闭之前处理完所有请求。
  • HPA 版本: autoscaling/v2beta2 提供了更多的功能和灵活性。

表格总结

步骤 描述 示例代码/配置
1. 暴露指标 PHP 应用暴露自定义指标,例如请求队列长度。 php <?php // metrics.php $queueLength = getQueueLength(); header('Content-Type: application/json'); echo json_encode([ 'queue_length' => $queueLength, ]); function getQueueLength() { // 模拟队列长度 return rand(0, 100); }
2. 安装 Prometheus 安装 Prometheus 并配置抓取 PHP 应用的指标。 bash helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm install my-prometheus prometheus-community/kube-prometheus-stack yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-php-app-metrics labels: release: my-prometheus # 与你的 Prometheus Helm Release 名称匹配 spec: selector: matchLabels: app: my-php-app # 与你的 PHP 应用 Pod 的 labels 匹配 endpoints: - port: http # 你的 PHP 应用监听的端口名称 path: /metrics # metrics endpoint 路径 interval: 30s # 抓取指标的间隔时间
3. 安装 Adapter 安装 kube-prometheus-adapter 并配置,使其能够从 Prometheus 获取自定义指标。 bash helm repo add k8s-prometheus-adapter https://kubernetes-sigs.github.io/prometheus-adapter helm repo update helm install my-prometheus-adapter k8s-prometheus-adapter/prometheus-adapter --set prometheus.url="http://my-prometheus-kube-prometheus-prometheus.default.svc" --set prometheus.port=9090 --set mapping.config.name=adapter-config yaml apiVersion: v1 kind: ConfigMap metadata: name: adapter-config namespace: default # 确保与你的 prometheus-adapter 部署的 namespace 相同 data: config.yaml: | rules: - seriesQuery: 'queue_length' # Prometheus 查询语句,用于获取指标数据 resources: overrides: k8s.io/pod.name: resource: pod name: asMatch: "queue_length" # 指标名称,用于 HPA 配置 metricsQuery: sum(queue_length) by (<<.GroupBy>>)
4. 创建 HPA 创建 HPA,并配置其根据 Custom Metrics 进行伸缩。 yaml apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: my-php-app-hpa-custom spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-php-app minReplicas: 1 maxReplicas: 10 metrics: - type: External external: metric: name: queue_length # Custom Metrics 的名称,与 adapter-config.yaml 中定义的 name.asMatch 匹配 selector: matchLabels: app: my-php-app # 与你的 PHP 应用 Pod 的 labels 匹配 target: type: AverageValue averageValue: 20 # 目标队列长度,20

总结

今天我们一起学习了如何在 Kubernetes 中使用 HPA 和 Custom Metrics 实现 PHP 应用的弹性伸缩。虽然过程有点复杂,但只要理解了原理,一步一步操作,就能轻松搞定。希望这些知识能帮助你更好地管理你的 PHP 应用,让它们在 Kubernetes 的世界里自由翱翔!

记住,实践是检验真理的唯一标准。多动手,多尝试,你就会发现,Kubernetes 并没有想象中那么可怕! 祝大家编码愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注