Kubernetes 中 PHP 应用的伸缩策略:HPA 基于 CPU 与自定义指标的配置
各位同学,大家好!今天我们来深入探讨 Kubernetes 中 PHP 应用的伸缩策略,特别是如何使用 Horizontal Pod Autoscaler (HPA) 基于 CPU 和自定义指标进行弹性伸缩。 这对于构建高可用、高性能的 PHP 应用至关重要。
1. 伸缩的必要性与 HPA 简介
在生产环境中,PHP 应用的负载往往是动态变化的。 访问量可能会随着时间、促销活动或其他因素而波动。 如果应用始终以固定的资源配置运行,可能会面临以下问题:
- 资源浪费: 在低峰期,大量资源闲置,造成浪费。
- 性能瓶颈: 在高峰期,资源不足,导致响应延迟增加甚至服务中断。
为了解决这些问题,我们需要一种机制来根据负载动态调整应用的资源配置。 这就是 Kubernetes Horizontal Pod Autoscaler (HPA) 的作用。
HPA 会监控 Pod 的资源利用率(例如 CPU、内存)或其他自定义指标,并根据预定义的规则自动调整 Pod 的副本数量,从而实现应用的弹性伸缩。 简单来说,HPA 的核心目标是维持目标指标在期望的范围内。
2. 基于 CPU 的 HPA 配置
最简单的 HPA 配置是基于 CPU 利用率的。 Kubernetes 默认提供了 CPU 利用率的指标。 我们可以配置 HPA,使其根据 CPU 利用率自动调整 PHP 应用的 Pod 副本数量。
2.1 前提条件
- 已经部署好的 PHP 应用,且其 Deployment 已就绪。
- Metrics Server 或 Heapster 已安装并配置在 Kubernetes 集群中。 Metrics Server 是 Kubernetes 官方推荐的资源指标收集器,Heapster 已经逐渐被弃用。
2.2 编写 Deployment 和 Service 定义
首先,我们需要一个 Deployment 来管理 PHP 应用的 Pod 副本,以及一个 Service 来暴露应用。
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-app
spec:
replicas: 1
selector:
matchLabels:
app: php-app
template:
metadata:
labels:
app: php-app
spec:
containers:
- name: php-app
image: php:7.4-apache # 使用官方 PHP 镜像
ports:
- containerPort: 80
resources:
requests:
cpu: 100m # 初始 CPU 请求量
memory: 128Mi # 初始内存请求量
limits:
cpu: 500m # CPU 限制
memory: 256Mi # 内存限制
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: php-app-service
spec:
selector:
app: php-app
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
这个 Deployment 定义了一个名为 php-app 的应用,使用 php:7.4-apache 镜像。 resources 部分定义了 Pod 的资源请求和限制,这对于 HPA 的工作至关重要。 务必为 Pod 设置合理的资源请求,以便 Metrics Server 可以正确地收集资源利用率数据。 requests 是 Pod 启动时请求的资源量,limits 是 Pod 可以使用的最大资源量。
2.3 创建 HPA 定义
接下来,我们创建一个 HPA 对象来监控 CPU 利用率并自动调整 Pod 副本数量。
# hpa.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-app
minReplicas: 1 # 最小副本数量
maxReplicas: 5 # 最大副本数量
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # 目标 CPU 利用率
这个 HPA 定义指定了以下内容:
scaleTargetRef: HPA 监控的对象是名为php-app的 Deployment。minReplicas: Pod 的最小副本数量为 1。maxReplicas: Pod 的最大副本数量为 5。metrics: HPA 监控 CPU 利用率。target部分指定了目标 CPU 利用率为 50%。 这意味着 HPA 会尝试将所有 Pod 的平均 CPU 利用率维持在 50% 左右。
2.4 部署应用和 HPA
使用 kubectl apply 命令部署 Deployment、Service 和 HPA:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f hpa.yaml
2.5 验证 HPA
使用 kubectl get hpa 命令查看 HPA 的状态:
kubectl get hpa php-app-hpa
输出类似于:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-app-hpa Deployment/php-app 0%/50% 1 5 1 1m
TARGETS 列显示了当前的 CPU 利用率和目标 CPU 利用率。 REPLICAS 列显示了当前的 Pod 副本数量。
2.6 测试 HPA
要测试 HPA,我们需要模拟 CPU 负载。 可以使用 stress 工具来模拟 CPU 负载。 首先,进入到 php-app pod中:
kubectl exec -it $(kubectl get pods -l app=php-app -o jsonpath='{.items[0].metadata.name}') -- bash
然后在 pod 内部安装 stress 工具:
apt-get update && apt-get install -y stress
最后,运行 stress 命令来模拟 CPU 负载:
stress --cpu 2 --timeout 600 # 启动 2 个 CPU 密集型进程,持续 600 秒
持续观察 kubectl get hpa php-app-hpa 的输出。 随着 CPU 利用率的升高,HPA 会自动增加 Pod 副本数量。
3. 基于自定义指标的 HPA 配置
除了 CPU 和内存,我们还可以使用自定义指标来驱动 HPA。 自定义指标可以反映应用的特定业务逻辑,从而实现更精细的伸缩策略。
3.1 前提条件
- 已经部署好的 PHP 应用,且其 Deployment 已就绪。
- Metrics Server 或 Heapster 已安装并配置在 Kubernetes 集群中。
- Prometheus 或其他指标收集系统已安装并配置。
- Adapter (例如 Prometheus Adapter) 已安装并配置,用于将自定义指标暴露给 Kubernetes API。
3.2 暴露自定义指标
首先,我们需要在 PHP 应用中暴露自定义指标。 可以使用 Prometheus 客户端库来暴露指标。
例如,假设我们要根据每秒请求数 (RPS) 来伸缩应用。 可以在 PHP 代码中添加以下代码来暴露 RPS 指标:
<?php
use PrometheusCollectorRegistry;
use PrometheusRenderTextFormat;
// 初始化 Prometheus 客户端
$adapter = new PrometheusStorageAPC();
$registry = new CollectorRegistry($adapter);
// 创建一个 Counter 指标,用于记录请求总数
$counter = $registry->getOrRegisterCounter('http', 'requests_total', 'Total number of HTTP requests');
// 增加请求计数
$counter->inc();
// 获取 RPS 指标
function getRPS(CollectorRegistry $registry, int $interval = 5): float {
static $previousValue = 0;
static $previousTime = 0;
$currentValue = $registry->getCounter('http', 'requests_total')->get();
$currentTime = time();
if ($previousTime === 0) {
$previousValue = $currentValue;
$previousTime = $currentTime;
return 0;
}
$diffValue = $currentValue - $previousValue;
$diffTime = $currentTime - $previousTime;
if ($diffTime === 0) {
return 0;
}
$rps = $diffValue / $diffTime;
$previousValue = $currentValue;
$previousTime = $currentTime;
return $rps;
}
// 输出 RPS 指标
$rps = getRPS($registry);
echo "RPS: " . $rps . "n";
// 输出 Prometheus 指标
$renderer = new RenderTextFormat();
$result = $renderer->render($registry->getMetricFamilySamples());
header('Content-type: text/plain');
echo $result;
将以上代码保存为 metrics.php,并通过 Web 服务器暴露该文件。 这样,Prometheus 就可以抓取到 RPS 指标。 确保 Prometheus 可以访问到这个 endpoint。
3.3 配置 Prometheus Adapter
Prometheus Adapter 用于将 Prometheus 中的指标暴露给 Kubernetes API。 需要配置 Prometheus Adapter,使其能够从 Prometheus 中查询 RPS 指标。
创建一个 adapter-config.yaml 文件,配置 Prometheus Adapter:
# adapter-config.yaml
rules:
- seriesQuery: 'http_requests_total'
seriesFilters: []
resources:
overrides:
kubernetes.io/service-name: {resource: "service"}
name:
matches: ^(.*)
as: "rps"
metricsQuery: 'rate(http_requests_total[1m])'
这个配置定义了一个规则,将 Prometheus 中的 http_requests_total 指标转换为 Kubernetes API 中的 rps 指标。 metricsQuery 使用 PromQL 查询语句计算每分钟的请求速率。
使用 kubectl apply 命令部署 Prometheus Adapter 配置:
kubectl apply -f adapter-config.yaml
3.4 创建 HPA 定义
创建一个 HPA 对象,使用自定义指标 rps 来伸缩应用:
# hpa-custom.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-app-hpa-custom
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-app
minReplicas: 1
maxReplicas: 5
metrics:
- type: External
external:
metric:
name: rps
selector:
matchLabels:
service: php-app-service # 替换为你的 Service 名称
target:
type: AverageValue
averageValue: 10 # 目标 RPS
这个 HPA 定义指定了以下内容:
scaleTargetRef: HPA 监控的对象是名为php-app的 Deployment。minReplicas: Pod 的最小副本数量为 1。maxReplicas: Pod 的最大副本数量为 5。metrics: HPA 监控自定义指标rps。target部分指定了目标 RPS 为 10。 这意味着 HPA 会尝试将所有 Pod 的平均 RPS 维持在 10 左右。selector必须与 Service 的标签匹配。
3.5 部署 HPA
使用 kubectl apply 命令部署 HPA:
kubectl apply -f hpa-custom.yaml
3.6 验证 HPA
使用 kubectl get hpa php-app-hpa-custom 命令查看 HPA 的状态。
kubectl get hpa php-app-hpa-custom
输出类似于:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-app-hpa-custom Deployment/php-app 0/10 1 5 1 1m
TARGETS 列显示了当前的 RPS 和目标 RPS。 REPLICAS 列显示了当前的 Pod 副本数量。
3.7 测试 HPA
要测试 HPA,我们需要模拟请求负载。 可以使用 ab (Apache Benchmark) 工具来模拟请求负载。
ab -n 1000 -c 10 http://<service-ip>:<service-port>/metrics.php # 发送 1000 个请求,并发数为 10
持续观察 kubectl get hpa php-app-hpa-custom 的输出。 随着 RPS 的升高,HPA 会自动增加 Pod 副本数量。
4. HPA 配置的最佳实践
- 合理的资源请求和限制: 务必为 Pod 设置合理的资源请求和限制。 资源请求用于 HPA 计算资源利用率,资源限制用于防止 Pod 消耗过多的资源。
- 选择合适的指标: 选择能够反映应用负载的指标。 CPU 利用率适用于大多数应用,但对于某些应用,自定义指标可能更有效。
- 设置合理的伸缩阈值: 伸缩阈值决定了 HPA 何时进行伸缩。 设置过低的阈值会导致频繁伸缩,设置过高的阈值会导致响应延迟增加。
- 考虑延迟: HPA 的伸缩过程需要一定的时间。 在设置伸缩阈值时,需要考虑这个延迟。
- 监控 HPA: 定期监控 HPA 的状态,确保其正常工作。
- 使用冷却时间 (Cooldown Period): 避免 HPA 在短时间内频繁伸缩。 可以通过设置
--horizontal-pod-autoscaler-downscale-stabilization参数来设置冷却时间。 - 测试 HPA: 在生产环境中使用 HPA 之前,务必进行充分的测试。
5. 进阶:使用多种指标的 HPA
HPA 还可以同时使用多种指标进行伸缩。 例如,可以同时使用 CPU 利用率和 RPS 来驱动 HPA。
# hpa-multiple.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-app-hpa-multiple
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-app
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: External
external:
metric:
name: rps
selector:
matchLabels:
service: php-app-service
target:
type: AverageValue
averageValue: 10
这个 HPA 定义同时监控 CPU 利用率和 RPS。 HPA 会根据这两个指标来调整 Pod 副本数量。 HPA 会选择需要更多副本的指标来驱动伸缩。
6. 一些需要注意的点
- 指标数据的准确性: HPA 的伸缩决策依赖于准确的指标数据。 如果指标数据不准确,可能会导致 HPA 做出错误的决策。 确保 Metrics Server、Prometheus 和其他指标收集系统配置正确,并且能够收集到准确的指标数据。
- 资源争用: 在高负载情况下,Pod 可能会出现资源争用。 这可能会导致 HPA 做出错误的决策。 可以使用 Kubernetes 的资源 QoS (Quality of Service) 特性来缓解资源争用。
- 外部依赖: HPA 依赖于 Metrics Server、Prometheus 和其他外部系统。 如果这些系统出现故障,HPA 将无法正常工作。 确保这些系统具有高可用性。
- 版本兼容性: 不同的 Kubernetes 版本可能对 HPA 的配置方式有所不同。 确保 HPA 的配置与 Kubernetes 版本兼容。
7. 常见问题排查
- HPA 没有伸缩: 检查 HPA 的状态,查看
TARGETS列是否达到了目标值。 检查 Metrics Server 或 Prometheus 是否正常工作。 检查 Pod 的资源请求是否设置正确。 - HPA 频繁伸缩: 检查伸缩阈值是否设置过低。 考虑增加冷却时间。 检查指标数据是否波动过大。
- HPA 伸缩错误: 检查 HPA 的配置是否正确。 检查 Prometheus Adapter 的配置是否正确。 检查 Pod 的资源限制是否设置过低。
- 无法获取自定义指标: 检查 Prometheus 是否能够抓取到自定义指标。 检查 Prometheus Adapter 的配置是否正确。 检查 HPA 的指标名称和选择器是否与 Prometheus 中的指标匹配。
8. 表格:指标选择建议
| 应用类型 | 推荐指标 | 备注 |
|---|---|---|
| CPU 密集型 | CPU 利用率 | 适用于大多数应用 |
| 内存密集型 | 内存利用率 | 适用于需要大量内存的应用 |
| IO 密集型 | 磁盘 IOPS、网络流量 | 适用于需要大量 IO 操作的应用 |
| Web 应用 | RPS、延迟 | 适用于需要快速响应的 Web 应用 |
| 数据库应用 | 连接数、查询延迟 | 适用于需要高性能数据库的应用 |
| 消息队列应用 | 消息队列长度、消息处理延迟 | 适用于需要高吞吐量消息队列的应用 |
9. 总结
我们探讨了 Kubernetes 中 PHP 应用的伸缩策略,重点介绍了如何使用 HPA 基于 CPU 和自定义指标进行弹性伸缩。 基于 CPU 的 HPA 配置相对简单,适用于大多数应用。 基于自定义指标的 HPA 配置可以实现更精细的伸缩策略,但需要更多的配置工作。 希望通过今天的讲解,大家能够更好地理解和应用 HPA,构建高可用、高性能的 PHP 应用。
10. 灵活伸缩,保障应用稳定
通过合理配置 HPA,我们可以根据实际业务负载动态调整 PHP 应用的资源配置,从而实现资源的有效利用,并保障应用的稳定性和性能。 掌握 HPA 的配置和最佳实践,是构建云原生 PHP 应用的关键技能。