# K8s 升级分步 Maintenance 标记设计方案

> 飞书文档（Source of Truth）：[K8s 升级分步 Maintenance 标记设计方案](https://pingcap.feishu.cn/docx/CcGMdT7KQoXcDLxcibycj5oMnPc)  
> 开发 Plan：[.cursor/plans/k8s升级分步maintenance_63c69c85.plan.md](../../.cursor/plans/k8s升级分步maintenance_63c69c85.plan.md)  
> 最后同步：2026-06-24

---

## 背景

**问题**：当前 DevOps 在任务 Maintenance running 后即全量打 maintenance 标记，Infra 侧 UO 自行推进各 step，二者独立并行，相互之间没有协调：

1. maintenance 窗口范围过大、时间过长，没有参与升级的 TiDB 集群也无法正常做运维操作；
2. 无法保证「打标完成后再执行升级」的设定。

**目标**：

- maintenance 窗口范围粒度拆细，在 TiDB 集群粒度上开启/关闭 maintenance；
- 没有参与升级的 TiDB 集群可以正常执行运维操作；
- maintenance 标记完整覆盖集群升级周期。

| 模式 | 描述 | 配置 | Step 级 Maintenance 行为 |
|------|------|------|-------------------------|
| **Legacy** | 现状，任务开始时给所有集群设置 maintenance | 默认 | 任务开始前 StartExecution（全部），全程有效，任务结束后 Finish + Close；**无握手** |
| **ClusterMaintenance** | TiDB 集群粒度设置 maintenance，按需设置 | tenant/project | tidb-nodes：Start/Finish **单集群**；其余 step（含 controlplane）无 maintenance |

---

## 核心设计

### Maintenance Window 生命周期

- **任务级**：CreateMaintenance（全部 TiDB 集群）→ MW 保持 Open → CloseMaintenance（任务/UO 结束）
- **Step 级**：仅 StartExecution / FinishExecution，不每 step 重复 Create/Close

### 核心逻辑变更对比

| 维度 | Legacy（默认） | ClusterMaintenance |
|------|---------------|-------------------|
| CreateMaintenance | 任务开始前 1 次 | 任务开始前 1 次（相同） |
| CloseMaintenance | 任务结束后 1 次 | 任务结束后 1 次（相同） |
| Start/FinishExecution | 任务级 Start 全部，结束 Finish 全部 | **按 step + scope** Start/Finish |
| 协同机制 | 无 | **UO CR annotation 握手** |
| UO CR 变更 | 无 | spec.mode=**cluster-maintenance** + annotations |

### Step 是否需要 maintenance

| Step Target | Legacy | ClusterMaintenance |
|-------------|--------|-------------------|
| controlplane | — | — |
| tidb-nodes | — | 需要，scope=单 cluster |
| admin-nodepool / o11y / addons / cdc / dm / empty nodepools | — | — |

---

## 时序图

### Legacy 模式（默认）

任务级一次性打标，无 per-step annotation 握手。

```mermaid
sequenceDiagram
    autonumber
    participant Sync as DevOps Task Sync
    participant MW as ClusterMaintenance
    participant UO as UO CR
    participant Infra as Infra UO Controller

    Sync->>MW: CreateMaintenance + StartExecution（全部）
    Sync->>UO: Create UO（mode=legacy）
    Infra->>Infra: 执行全部 steps（无 annotation）
    Infra-->>Sync: UO Completed
    Sync->>MW: FinishExecution（全部）+ CloseMaintenance
```

### ClusterMaintenance 模式

任务级 CreateMaintenance 一次；仅 tidb-nodes 走 annotation Gate。

```mermaid
sequenceDiagram
    autonumber
    participant Sync as DevOps Task Sync
    participant MW as ClusterMaintenance
    participant UO as UO CR
    participant Infra as Infra UO Controller

    Sync->>MW: CreateMaintenance
    Sync->>UO: Create UO（mode=cluster-maintenance）
    Infra->>Infra: controlplane / admin / o11y 等（直接执行）
    Infra->>UO: request-step-N（spec only）
    Sync->>MW: StartExecution（单集群）
    Sync->>UO: 回写 status=done
    Infra->>Infra: 执行 tidb-nodes
    Infra->>UO: release-step-N（spec only）
    Sync->>MW: FinishExecution（单集群）
    Sync->>UO: 回写 status=done
    Infra-->>Sync: UO Completed
    Sync->>MW: CloseMaintenance
```

---

## 实体变化

### DevOps 配置（YAML）

控制给哪些租户/project 开启对应功能：

```yaml
services:
  featureGates:
    k8supgradeClusterMaintenance:
      all: true
      tenants:
        - xxx
      projects:
        - xxx
```

### UO CR（Infra 侧）

| 位置 | 字段 | 说明 |
|------|------|------|
| spec | `maintenancePolicyMode` | DevOps 创建 UO 时写入，`legacy` / **`cluster-maintenance`** |
| annotations | `maintenance.pingcap.com/request-step-{N}` 等 | step 级 Start/Finish 握手 |

### Annotations（step 级握手）

**Key 格式**：

- 开启 maintenance：`maintenance.pingcap.com/request-step-{N}`
- 关闭 maintenance：`maintenance.pingcap.com/release-step-{N}`

N 为对应 step 的索引，不同 step 使用不同的 key。

**Value 格式**：

```json
{
  "spec": {
    "cluster_id": "133456456345456",
    "time": "1235345456"
  },
  "status": {
    "result": "done",
    "time": "1235345456"
  }
}
```

> `cluster_id` 为 step 对应集群 ID（注释中提及 controlplane 场景可用 `all`，ClusterMaintenance 模式下仅 tidb-nodes 使用）。

**握手流程**：

| 阶段 | Infra | DevOps |
|------|-------|--------|
| Step 开始执行前 — 请求 maintenance | 设置 `request-step-{N}`（仅 spec） | 读取 annotation → StartExecution → 回写 spec + status |
| Step 执行阶段 | 执行 step 升级任务 | — |
| Step 结束 — 关闭 maintenance | 设置 `release-step-{N}`（仅 spec） | 读取 annotation → FinishExecution → 回写 spec + status |

---

## 接口变化

### Infra UO Controller

| 变更 | 说明 |
|------|------|
| 读取 spec.maintenancePolicyMode | step 执行前判定是否需要 maintenance |
| annotation 写入/轮询 | 需 maintenance 的 step：写 request → 等 done → 执行 → 写 release → 等 done |
| 无需 maintenance 的 step | 直接执行，不写 annotation |

### Regional Server

| 变更 | 说明 |
|------|------|
| GetUpgradeOperation | 需返回 **annotations** |
| UpdateUpgradeOperation | DevOps 需能**写回 annotations** |
| CreateUpgradeOperation | spec 增加 maintenancePolicyMode |

### DevOps 内部

| 变更 | 说明 |
|------|------|
| 创建 UO 时 | 解析 policy → 写入 maintenancePolicyMode |
| Task Sync | 轮询 UO annotations → Start/FinishExecution → 写回 annotation |
| Legacy 路径 | 保持现有逻辑（任务级 Start 全部，无 annotation） |

---

## 监控告警

| item | 生成方 | desc |
|------|--------|------|
| `k8supgrader_maintenance_stuck` | **infra-provider** Regional Server collector（`pkg/metrics/collectors/upgradeoperation.go`） | UO annotation 有 `spec` 但 DevOps 未回写 `status.result=done` 时置 1 |

> `k8supgrader_step_stuck` 本期不实现。

---

## 开发周期

| Item | Desc | Time |
|------|------|------|
| 功能实现 | DevOps annotation 处理；Regional Server API；UO Controller step 级协同 | 3d |
| 监控告警 | infra-provider collector 增加 `k8supgrader_maintenance_stuck` | 1d |
| 单测 | 双仓库单元测试（不含 EKS/GKE 联调） | — |

**ETA：07/21**

---

## 评审会议

### 2026-06-24

- 移除 Level-1 模式，只保留 **ClusterMaintenance**（原 Level-2）
- 启动开发
- 提供测试计划
- ETA：07/21
