218 lines
6.5 KiB
Markdown
218 lines
6.5 KiB
Markdown
|
|
---
|
|||
|
|
tags: [kubernetes, hpa, autoscaling, statefulset, horizontal-pod-autoscaler]
|
|||
|
|
create time: 2026-05-18 00:30
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# K8s 扩缩容与有状态应用 — HPA & StatefulSet
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
K8s 提供多种扩缩容机制。**HPA** 基于 CPU/Memory 或其他自定义指标实现 Pod 级别的弹性伸缩,适用于无状态服务。**StatefulSet** 则是数据库、消息队列等有状态组件的理想选择。两者各有适用场景。
|
|||
|
|
|
|||
|
|
## HPA 弹性伸缩
|
|||
|
|
|
|||
|
|
### 基础示例
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
apiVersion: autoscaling/v2
|
|||
|
|
kind: HorizontalPodAutoscaler
|
|||
|
|
metadata:
|
|||
|
|
name: order-service-hpa
|
|||
|
|
spec:
|
|||
|
|
scaleTargetRef:
|
|||
|
|
apiVersion: apps/v1
|
|||
|
|
kind: Deployment
|
|||
|
|
name: order-service
|
|||
|
|
minReplicas: 3
|
|||
|
|
maxReplicas: 20
|
|||
|
|
metrics:
|
|||
|
|
- type: Resource
|
|||
|
|
resource:
|
|||
|
|
name: cpu
|
|||
|
|
target:
|
|||
|
|
type: Utilization
|
|||
|
|
averageUtilization: 70 # CPU > 70% 时扩容
|
|||
|
|
- type: Resource
|
|||
|
|
resource:
|
|||
|
|
name: memory
|
|||
|
|
target:
|
|||
|
|
type: Utilization
|
|||
|
|
averageUtilization: 80
|
|||
|
|
behavior:
|
|||
|
|
scaleUp:
|
|||
|
|
stabilizationWindowSeconds: 60 # 扩容稳定期
|
|||
|
|
policies:
|
|||
|
|
- type: Pods
|
|||
|
|
value: 2
|
|||
|
|
periodSeconds: 60 # 每分钟最多扩 2 个
|
|||
|
|
scaleDown:
|
|||
|
|
stabilizationWindowSeconds: 300 # 缩容稳定期 5min(防抖动)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 扩展指标:基于自定义 Metric 扩缩容
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
metrics:
|
|||
|
|
- type: Pods
|
|||
|
|
pods:
|
|||
|
|
metric:
|
|||
|
|
name: http_requests_per_second
|
|||
|
|
target:
|
|||
|
|
type: AverageValue
|
|||
|
|
averageValue: "100" # 每个 Pod 平均 100 QPS 时扩容
|
|||
|
|
- type: Object
|
|||
|
|
object:
|
|||
|
|
metric:
|
|||
|
|
name: active_users
|
|||
|
|
describedObject:
|
|||
|
|
apiVersion: apps/v1
|
|||
|
|
kind: Deployment
|
|||
|
|
name: web-app
|
|||
|
|
target:
|
|||
|
|
type: Value
|
|||
|
|
value: "500" # 每 500 活跃用户触发一次扩容
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!info] HPA 的工作机制
|
|||
|
|
>
|
|||
|
|
> HPA 控制器每 15 秒查询 Metrics Server(CPU/Memory)或自定义 Metrics Adapter(QPS 等),计算所需 Replica 数。公式:`ceil(当前指标值 / 目标指标值 × 当前副本数)`。为了防止抖动,scaleDown 的稳定窗口通常比 scaleUp 长很多。
|
|||
|
|
|
|||
|
|
### HPA 调优最佳实践
|
|||
|
|
|
|||
|
|
| 参数 | 推荐值 | 说明 |
|
|||
|
|
|------|--------|------|
|
|||
|
|
| `averageUtilization` (CPU) | 60~70% | 低于 60% 浪费资源,高于 80% 延迟风险大 |
|
|||
|
|
| `scaleUp.stabilizationWindow` | 0~60s | 突发流量快速响应 |
|
|||
|
|
| `scaleDown.stabilizationWindow` | 300~600s | 防止抖动导致的频繁扩缩 |
|
|||
|
|
| `pods[].periodSeconds` | 60s | 限制扩容频率,避免雪崩 |
|
|||
|
|
|
|||
|
|
## StatefulSet — 有状态应用
|
|||
|
|
|
|||
|
|
Deployment 适合无状态服务,而有状态服务(数据库、分布式协调器等)需要 **稳定的网络标识 + 有序的启停**。StatefulSet 就是为此而生的控制器。
|
|||
|
|
|
|||
|
|
### 完整示例
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
apiVersion: apps/v1
|
|||
|
|
kind: StatefulSet
|
|||
|
|
metadata:
|
|||
|
|
name: mysql-cluster
|
|||
|
|
spec:
|
|||
|
|
serviceName: mysql # 绑定 Headless Service
|
|||
|
|
replicas: 3
|
|||
|
|
podManagementPolicy: Parallel # 并行启动(生产建议 OrderedReady 逐步启动)
|
|||
|
|
|
|||
|
|
updateStrategy:
|
|||
|
|
type: RollingUpdate
|
|||
|
|
rollingUpdate:
|
|||
|
|
partition: 0 # 从最后一个 Pod 开始逐步滚动
|
|||
|
|
|
|||
|
|
selector:
|
|||
|
|
matchLabels:
|
|||
|
|
app: mysql
|
|||
|
|
|
|||
|
|
template:
|
|||
|
|
metadata:
|
|||
|
|
labels:
|
|||
|
|
app: mysql
|
|||
|
|
spec:
|
|||
|
|
containers:
|
|||
|
|
- name: mysql
|
|||
|
|
image: mysql:8.0
|
|||
|
|
ports:
|
|||
|
|
- containerPort: 3306
|
|||
|
|
volumeMounts:
|
|||
|
|
- name: data
|
|||
|
|
mountPath: /var/lib/mysql
|
|||
|
|
|
|||
|
|
volumeClaimTemplates:
|
|||
|
|
- metadata:
|
|||
|
|
name: data
|
|||
|
|
spec:
|
|||
|
|
accessModes: ["ReadWriteOnce"]
|
|||
|
|
resources:
|
|||
|
|
requests:
|
|||
|
|
storage: 20Gi
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### StatefulSet 的核心特性
|
|||
|
|
|
|||
|
|
| 特性 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| **稳定名称** | Pod 名为 `{statefulset-name}-{ordinal}`,如 `mysql-cluster-0` |
|
|||
|
|
| **有序部署** | 默认依次启动:0 → 1 → 2(设置 `Parallel` 可并行) |
|
|||
|
|
| **有序删除** | 反向删除:2 → 1 → 0(保证主从切换安全) |
|
|||
|
|
| **持久化存储** | `volumeClaimTemplates` 为每个 Pod 独立创建 PVC,Pod 重建后数据不丢失 |
|
|||
|
|
| **Headless Service** | 需搭配 `ClusterIP: None` 的 Service,每个 Pod 有独立的 DNS 记录 |
|
|||
|
|
|
|||
|
|
### StatefulSet vs Deployment 对比
|
|||
|
|
|
|||
|
|
| 维度 | Deployment | StatefulSet |
|
|||
|
|
|------|-----------|-------------|
|
|||
|
|
| **Pod 命名** | 随机后缀 | `{name}-{0,1,2,...}` |
|
|||
|
|
| **存储** | 共享 PVC 或不持久 | 每个 Pod 独立 PVC |
|
|||
|
|
| **启动顺序** | 并发 | 串行(默认) |
|
|||
|
|
| **删除顺序** | 随机 | 逆序 |
|
|||
|
|
| **DNS 稳定性** | 每次重建 IP 变 | 域名不变 |
|
|||
|
|
| **适用场景** | Web/API 无状态服务 | DB、ZooKeeper、Kafka |
|
|||
|
|
|
|||
|
|
> [!note] 为什么有状态应用不适合 Deployment?
|
|||
|
|
>
|
|||
|
|
> Deployment 会随机销毁和重建 Pod——这意味着 PVC 会被重新绑定到不同的 Pod,存储卷中的数据和节点 ID 完全错位。StatefulSet 保证同一个 Pod 始终使用同一片存储,这对数据库、Kafka、ZooKeeper 等组件至关重要。
|
|||
|
|
|
|||
|
|
### Headless Service — StatefulSet 的灵魂搭档
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
apiVersion: v1
|
|||
|
|
kind: Service
|
|||
|
|
metadata:
|
|||
|
|
name: mysql-headless
|
|||
|
|
spec:
|
|||
|
|
clusterIP: None # 关键:不分配 ClusterIP
|
|||
|
|
selector:
|
|||
|
|
app: mysql
|
|||
|
|
ports:
|
|||
|
|
- port: 3306
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
通过 DNS 可以直接访问单个 Pod:
|
|||
|
|
- `mysql-cluster-0.mysql-headless.production.svc.cluster.local:3306`
|
|||
|
|
- `mysql-cluster-1.mysql-headless.production.svc.cluster.local:3306`
|
|||
|
|
|
|||
|
|
## 补充:Vertical Pod Autoscaler (VPA)
|
|||
|
|
|
|||
|
|
HPA 只管 Pod 数量,不管单 Pod 的资源配置。如果你经常遇到 OOMKill 或 CPU Throttling,可以尝试 VPA:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
apiVersion: autoscaling.k8s.io/v1
|
|||
|
|
kind: VerticalPodAutoscaler
|
|||
|
|
metadata:
|
|||
|
|
name: order-service-vpa
|
|||
|
|
spec:
|
|||
|
|
targetRef:
|
|||
|
|
apiVersion: apps/v1
|
|||
|
|
kind: Deployment
|
|||
|
|
name: order-service
|
|||
|
|
updatePolicy:
|
|||
|
|
updateMode: "Auto" # Auto / Initial / Off
|
|||
|
|
resourcePolicy:
|
|||
|
|
containerPolicy:
|
|||
|
|
minAllowed:
|
|||
|
|
cpu: 100m
|
|||
|
|
memory: 128Mi
|
|||
|
|
maxAllowed:
|
|||
|
|
cpu: "2"
|
|||
|
|
memory: 4Gi
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!warning] VPA 的限制
|
|||
|
|
>
|
|||
|
|
> VPA 在调整资源时会**驱逐并重建 Pod**。与 HPA 不同,VPA 不能无缝运行——建议在开发/测试环境中先用 `Initial` 模式观察推荐值,确定合理后再切到 `Auto`。生产环境通常结合 HPA(管数量)+ 手动调优 Resources(管质量)。
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
|
|||
|
|
- [[../01-核心概念与Deployment]] — Deployment 基础,HPA 的目标控制器
|
|||
|
|
- [[../02-配置管理]] — StatefulSet 的数据库凭据通过 Secret 注入
|
|||
|
|
- [[../03-网络与服务发现]] — Headless Service 为 StatefulSet 提供 DNS 解析
|
|||
|
|
- [[../hhs/MS/05-部署运维/04-SRE实践]] — SLO/Error Budget 决定扩容阈值
|