# Elastic Scaler 技术规格说明文档

## §0 文档性质

本文件为 **Elastic Scaler** 的**技术规格与责任边界契约**。设计依据见提案 [OFEP-0030 通用扩缩容决策框架设计提案](https://gitcode.com/openFuyao/ofep/blob/main/ofeps/sig-ai-inference/0030-ofep-通用扩缩容决策框架设计提案.md) 与 [OFEP-0044 通用扩缩容决策框架增强提案](https://gitcode.com/openFuyao/ofep/blob/main/ofeps/sig-ai-inference/0044-ofep-通用扩缩容决策框架增强提案.md)。

安装步骤、YAML 示例与指标配置细节见 [README](./README.md) 及用户手册；注解键、Webhook 路径、API 组与默认镜像见**附录**。

文中涉及 ResourceScalingGroup（RSG）、Tidal 等处，仅说明与 Elastic Scaler 的**协作与责任边界**，不展开其独立规格；RSG/Tidal 的 Webhook、策略模式等详见各自用户手册（附录 D）。

作为 **InferNex-Bridge** 增强组件之一部署时，InferNex-Bridge 负责创建 `ElasticScaler` CR 及关联 RBAC（同模板可一并创建 `ResourceScalingGroup` / `Tidal` CR）；**Elastic Scaler 的扩缩决策与目标副本写入**由本组件负责。推理 Engine、Router 及 Pod 生命周期仍归上游（KServe / InferNex-Bridge）管理，见 [InferNex-Bridge 技术规格说明](../InferNex-Bridge-Technical-Specification.md) §3、§4。

---

## §1 环境前提

| 部署入口 | 详见 |
| -------- | ---- |
| `pd-orchestrator` 集成 Chart | **§1.1** |
| 独立子 Chart（按需启用单组件） | **§1.2** |

下列基础设施 **由用户/集群安装维护**；Elastic Scaler **不负责**，除非下文另有说明。

### 1.1 `pd-orchestrator` 集成部署

通过 `charts/pd-orchestrator` 一次性安装 Elastic Scaler、ResourceScalingGroup（RSG）、Tidal 三个控制器及对应 CRD。默认命名空间为 `scaling-system`（可通过 values 覆盖）。

**Elastic Scaler 额外前提**

| 依赖项 | 说明 |
| ------ | ---- |
| **Kubernetes** | 支持 CRD、`/scale` 子资源及 `autoscaling/v2` HPA 的集群版本 |
| **metrics-server** | 使用 `MetricsTrigger` + `Resource` 指标（CPU/内存）时 **必须** |
| **Custom Metrics Adapter** | 使用 `MetricsTrigger` + `Custom` 指标时 **必须**（`custom.metrics.k8s.io`） |
| **External Metrics Adapter** | 使用 `MetricsTrigger` + `External` 指标时 **必须**（`external.metrics.k8s.io`） |
| **Prometheus（或可查询的 HTTP 指标端点）** | 使用 `ExternalServer` 指标，或 RSG `GroupReplication` 缩容策略需 PromQL 时 **必须**；RSG Chart 默认 `prometheus.url` 为 `http://prometheus-k8s.monitoring.svc:9090` |
| **LeaderWorkerSet Operator** | RSG 管理 `LeaderWorkerSet` 目标时 **必须** |
| **cert-manager 或等效 TLS 方案** | 启用 Elastic Scaler Validating Webhook 且需自动生成证书时按需 |

Chart 默认：**Elastic Scaler Webhook 关闭**（`webhook.enabled: false`）。生产环境建议显式配置 Webhook TLS 与 `failurePolicy`。

### 1.2 独立子 Chart 部署

可单独安装 `charts/pd-orchestrator/charts/elastic-scaler`、`resourcescalinggroup`、`tidal` 子 Chart。未安装的组件其 CRD/控制器不可用；**§1.1 中与所启用 Trigger/策略相关的依赖项仍适用**。

| 场景 | 最低组件组合 |
| ---- | ------------ |
| 指标驱动扩缩（HPA 或内置 `apa` 算法） | `elastic-scaler` |
| PD 分离等多资源成组扩缩 | `elastic-scaler` + `resourcescalinggroup` |
| 潮汐 / 定时容量切换（StateTrigger + Tidal） | `elastic-scaler` + `tidal` |
| InferNex 默认 PD 模板（含 elastic-scaler、RSG、Tidal） | 通常由 InferNex-Bridge / `pd-orchestrator` 一并部署 |

---

## §2 架构与触发模式

### 2.1 组件分层

```
用户 / 上层编排（InferNex-Bridge、HPA、手工 kubectl）
        │
        ▼
┌─────────────────── 决策层 ───────────────────┐
│  ElasticScaler（Metrics / State / Signal）      │
│  Tidal（时间规则 → status.desiredReplicas）     │
└───────────────────┬────────────────────────────┘
                    │ 目标副本数 / scale 子资源
                    ▼
┌─────────────────── 编排层 ───────────────────┐
│  ResourceScalingGroup（GroupReplication /       │
│  InplaceScaling）                               │
└───────────────────┬────────────────────────────┘
                    │ 更新工作负载 replicas
                    ▼
┌─────────────────── 执行层（非本组件集） ────────┐
│  Deployment / StatefulSet / LeaderWorkerSet /   │
│  自定义 CR 及其原生 Controller                  │
└─────────────────────────────────────────────────┘
```

**职责摘要**：Elastic Scaler 负责**扩缩决策与目标副本写入**；**不负责**工作负载/Pod 的创建、销毁、镜像、调度及业务就绪判定。RSG、Tidal 等上下游组件职责见 §3，不在本文件展开独立规格。

### 2.2 `ElasticScaler` 触发模式

每个 `ElasticScaler` **仅能**配置一种 `spec.trigger.type`；控制器按类型分流，**不可混用**多种 Trigger 子配置。

| `trigger.type` | 决策输入 | 副本写入路径 | 实现状态 |
| -------------- | -------- | ------------ | -------- |
| `MetricsTrigger` + `scalingAlgorithm: HPA` | Resource / External / Custom 指标 | 创建/更新伴生 HPA `{name}-hpa`，由 **Kubernetes HPA Controller** 调 `/scale` | **已实现** |
| `MetricsTrigger` + 自定义算法（如 `apa`） | Resource / External / ExternalServer / Custom + 注解策略 | **ElasticScaler** 经 `ResourceHandler` 直接写目标 `/scale` 或 `spec.replicas` | **已实现** |
| `StateTrigger` | 目标 CR 的 `status.desiredReplicas`（可沿 `spec.targetRef` 链解析） | **ElasticScaler** 经 `ResourceHandler` 写入 | **已实现** |
| `SignalTrigger` | 外部信号 Endpoint | 设计为 scale-to/from-zero | **未实现**（Reconcile 置 `SignalTriggerNotImplemented`） |

**MetricsTrigger 轮询**：默认每 **30s** 集中 Poll 所有 `MetricsTrigger` 对象（`--metrics-trigger-poll-interval`，Chart 未暴露时可改 Deployment args）。设为 `0` 可关闭 Poll（仅依赖 Watch 触发）。

**StateTrigger 监听**：带标签 `elasticscaler.io/name`、`elasticscaler.io/namespace` 的目标资源变更会 Enqueue 对应 `ElasticScaler`（动态 Informer，默认无 Resync）。

**Tidal 与 StateTrigger 协作**：`Tidal` 控制器维护 `status.desiredReplicas`；用户创建 `StateTrigger` 类型 `ElasticScaler`，`targetRef` 指向 `Tidal`。`Tidal` **必须**携带标签 `elasticscaler.io/name`、`elasticscaler.io/namespace` 指向绑定的 `ElasticScaler`，否则 Tidal 控制器标记 `MissingRequiredLabels` 且不保证规则生效。

### 2.3 API 组（不可混用）

| CR | API Group | 用途 |
| -- | --------- | ---- |
| `ElasticScaler` | `elasticscaler.io/v1alpha1` | 统一扩缩决策入口 |
| `ResourceScalingGroup` | `autoscaling.openfuyao.com/v1alpha1` | 资源组成组编排 |
| `Tidal` | `tidal.io/v1alpha1` | 时间驱动目标副本 |

---

## §3 组件归属

| 组件 / 能力 | 谁 reconcile | 说明 |
| ----------- | ------------ | ---- |
| `ElasticScaler` CR 及 Status | **Elastic Scaler 控制器** | 校验、指标采集、算法/HPA 路径、写副本或伴生 HPA |
| 伴生 HPA `{es.name}-hpa` | **Elastic Scaler 创建/更新**；**HPA Controller 执行扩缩** | 与 ES 同命名空间；OwnerReference 指向 ES；`scalingAlgorithm: HPA` 时 **不支持** `ExternalServer` 指标 |
| `ResourceScalingGroup` 及组内克隆/缩容 | **RSG 控制器** | 含 ConfigMap 副本配置、Prometheus 缩容排序（若配置） |
| `Tidal` 时间规则与 Status | **Tidal 控制器** | CRON（须 `CRON_TZ=...` 前缀）；同刻多规则取 **最大副本数** |
| Deployment / StatefulSet / LWS 等目标工作负载 | **各自原生 Controller** | Elastic Scaler 经 `targetRef` 写 replicas（或 `/scale`）；RSG/Tidal 见上行 |
| metrics-server / Metrics Adapter | **用户** | Elastic Scaler 只 **消费** Metrics API |
| Prometheus | **用户** | RSG 缩容策略、`ExternalServer` 查询；本组件集 **不部署** Prometheus |
| InferNex Engine / Router / 增强 Sidecar | **KServe 或 InferNex-Bridge** | 见 InferNex-Bridge 规格 §3 |
| 独立 `MetricsAdapter`（external.metrics 暴露层） | **不在本阶段范围** | OFEP-0044 明确不建设；指标经 Collector 内聚采集 |

**插件扩展**

| 扩展点 | 注册方式 | 责任边界 |
| ------ | -------- | -------- |
| 自定义扩缩算法 | `scaling.RegisterAlgorithm` | 算法 **仅计算** `desiredReplicas`；不直接访问 API Server |
| 自定义目标资源 | `resource.RegisterResourceHandler` | Handler 负责读/写副本与 Pod 列表；未注册时使用 `DefaultCustomResourceHandler`（优先 `/scale`） |
| RSG 目标解析 / 策略引擎 | `resourcescalinggroup` 包内注册 | 仅影响 RSG 编排，不改变 ElasticScaler Trigger 语义 |

---

## §4 副本与扩缩边界

### 4.1 管理关系

- 每个 `targetRef`（同 namespace + GVK + name）**最多**被一个 `ElasticScaler` 管理；Reconcile 阶段校验冲突，重复绑定会失败并写入 `Validated=False`。
- `ElasticScaler` **不创建、不删除** `targetRef` 指向的工作负载；用户须预先创建目标及（若需要）RSG/Tidal。
- **SignalTrigger**：规格可提交，控制器 **不执行** 扩缩；勿用于生产零副本场景。

### 4.2 外部改副本

| 模式 | 外部 patch `replicas` / `scale` | 说明 |
| ---- | ------------------------------- | ---- |
| `MetricsTrigger` + 自定义算法 | **会被收敛** | ElasticScaler 按决策周期写回期望副本 |
| `StateTrigger` | **会被收敛** | 以目标 `status.desiredReplicas`（如 Tidal）为准 |
| `MetricsTrigger` + HPA | **HPA 与原生行为一致** | 实际扩缩由 HPA Controller 执行；手工改 replicas 可能被 HPA 覆盖 |
| RSG `GroupReplication` | **会被 RSG 收敛** | 组数由 `groupConfig.replicas` 驱动 |
| 无 ElasticScaler 绑定的 Deployment 等 | **用户自行管理** | Elastic Scaler 不介入；RSG 管理的组级副本见 RSG 用户手册 |

「省略 `minReplicas`」= YAML 不写该字段（非 `0`）；CRD 默认 `minReplicas=1`、`maxReplicas=10`。

### 4.3 与 InferNex-Bridge 的边界

InferNex-Bridge Chart 默认模板启用 cache-indexer、mooncake、pdOrchestrator、Eagle-Eye、**elastic-scaler**、**resource-scaling-group**、**tidal** 等增强组件；**IGR 默认关闭**。

- **Engine / Hermes Router 副本**：LLM 入口由 **KServe** reconcile；`InferNexService` 入口由 **InferNex-Bridge** reconcile（见 InferNex-Bridge §4）。Elastic Scaler **不** reconcile Engine/Router 的声明式 `replicas` 字段本身，除非用户显式创建指向这些资源的 `ElasticScaler`（经 RSG 等间接驱动时，RSG 规格见用户手册）。
- **增强组件副本（含 elastic-scaler Deployment）**：由 InferNex-Bridge **声明式**管理；填写 `replicas` 时不支持仅靠外部 patch 持久改副本（会被 Chart/CR 收敛）。

---

## §5 Admission 行为摘要

### 5.1 ElasticScaler Validating Webhook

| 项 | 行为 |
| -- | ---- |
| 触发 | Create / Update `ElasticScaler` |
| 默认 | Chart **关闭**；开启路径 `/validate-elasticscaler-io-v1alpha1-elasticscaler` |
| 校验范围 | **仅规格级**（无 client）：Trigger 互斥、MetricSpec、算法名注册（Webhook 侧不查集群）、Endpoint 格式等 |
| 集群态 | targetRef 存在性、一一对应、StateTrigger 目标 status — **仅 Reconcile 时**校验 |
| Delete | 放行 |
| 默认 `failurePolicy` | **Fail**（以 values 为准） |

---

## §6 适用范围与边界说明

本规格描述 **§1 环境前提**满足时，Elastic Scaler 对外交互契约（`ElasticScaler` CR 语义、Admission、副本收敛边界，及与 RSG/Tidal 的协作边界）。

**不在保证范围内**：

- `SignalTrigger` 及 OFEP-0044 附录中的预研设计；
- 独立 `MetricsAdapter` / 将框架指标暴露为集群级 External Metrics API；
- 同一目标同时被多个扩缩控制器（非 ES 冲突校验外的 HPA + ES 等）竞争时的最终副本 — 需用户避免重复绑定；
- 指标链路完全不可用时的扩缩行为 — 自定义算法路径保留当前副本并写入 `MetricsPipeline` / `Degraded` 类 Condition；HPA 路径遵循 Kubernetes HPA 行为；
- 偏离默认 Chart（关闭 CRD、修改 RBAC、非验证镜像版本）或 InferNex 非默认组合的现场行为。

各组件经验证镜像见 **附录 C**（与 InferNex-Bridge 附录 B 对齐处已注明）。

---

## 附录 A：`ElasticScaler` 指标与行为注解

以下注解作用于 `MetricsTrigger` + **自定义算法**路径，由 `ContextBuilder` / `RecommendationStabilizer` 解析；非法值回退默认。

**指标采集策略**

| 注解键 | 含义 |
| ------ | ---- |
| `elasticscaler.io/metrics.windowSeconds` | 指标聚合窗口（秒） |
| `elasticscaler.io/metrics.gcFactor` | 样本 GC 相对窗口的激进程度 |
| `elasticscaler.io/metrics.aggregationType` | 聚合模式（Average、Max、Min、P90 等） |
| `elasticscaler.io/metrics.missingDataPolicy` | 缺失样本策略（Ignore、TreatAsZero、Fail） |
| `elasticscaler.io/metrics.enableOutlierFilter` | 是否启用离群过滤（bool） |
| `elasticscaler.io/metrics.outlierThreshold` | 离群过滤灵敏度 |

**推荐副本平滑（自定义算法路径）**

| 注解键 | 含义 |
| ------ | ---- |
| `elasticscaler.io/behavior.scaleUp.stabilizationWindowSeconds` | 扩容稳定窗口（秒） |
| `elasticscaler.io/behavior.scaleDown.stabilizationWindowSeconds` | 缩容稳定窗口（秒） |
| `elasticscaler.io/behavior.scaleUp.maxPodsPerStep` | 单步最大扩容 Pod 数 |
| `elasticscaler.io/behavior.scaleDown.maxPodsPerStep` | 单步最大缩容 Pod 数 |

缩容/扩容速率等算法参数通过 `spec.trigger.metricsTrigger.algorithmConfig`（map）传入内置 `apa` 等算法，详见用户手册。

**StateTrigger 绑定标签**（写在 **被监听的资源** 上，如 `Tidal`）：

| 标签键 | 含义 |
| ------ | ---- |
| `elasticscaler.io/name` | 绑定的 `ElasticScaler` 名称 |
| `elasticscaler.io/namespace` | 绑定的 `ElasticScaler` 命名空间 |

---

## 附录 B：内置扩缩算法

| 算法名 | 说明 |
| ------ | ---- |
| `HPA` | 非插件；走 HPAAdapter，委托 Kubernetes HPA |
| `apa` | 默认内置算法（Average Algorithm）；多指标取最大建议副本，含容忍度与速率限制；`scalingAlgorithm` 省略时默认使用 |

自定义算法须在进程内 `RegisterAlgorithm` 注册；Reconcile 校验未注册名称会失败。

---

## 附录 C：默认镜像版本

以 Chart release（`charts/pd-orchestrator` 及子 Chart）为准。除下表列出的镜像外，其它版本暂未经过验证。

| 组件 | 版本/标签 | 镜像 |
| ---- | --------- | ---- |
| elastic-scaler | latest（Chart） | `cr.openfuyao.cn/openfuyao/elastic-scaler` |
| resource-scaling-group | latest（Chart） | `cr.openfuyao.cn/openfuyao/resource-scaling-group` |
| tidal | latest（Chart） | `cr.openfuyao.cn/openfuyao/tidal` |
| pd-orchestrator（umbrella） | 0.0.0-latest | `oci://cr.openfuyao.cn/charts/pd-orchestrator` |

InferNex-Bridge 默认模板中 **elastic-scaler** 标签 **0.21.1**，见 [InferNex-Bridge 技术规格说明](../InferNex-Bridge-Technical-Specification.md) 附录 B。

---

## 附录 D：CRD 与手册索引

| 资源 | 用户手册 |
| ---- | -------- |
| ElasticScaler | [AI 推理弹性伸缩用户手册](https://gitcode.com/openFuyao/sig-ai-inference/blob/main/docs/zh/ai_inference_elastic_scaling_system/ai_inference_elastic_scaling/user_guide/ai_inference_elastic_scaling.md) |
| ResourceScalingGroup | [AI 推理 ResourceScalingGroup 用户手册](https://gitcode.com/openFuyao/sig-ai-inference/blob/main/docs/zh/ai_inference_elastic_scaling_system/ai_inference_resourcescalinggroup/user_guide/ai_inference_resourcescalinggroup.md) |
| Tidal | [AI 推理潮汐调度算法用户手册](https://gitcode.com/openFuyao/sig-ai-inference/blob/main/docs/zh/ai_inference_elastic_scaling_system/ai_inference_tidal_algorithm/user_guide/ai_inference_tidal_algorithm.md) |
