3. K8s资源对象与etcd映射:Pod、Service、ConfigMap等资源在etcd中的存储路径与数据结构

Kubernetes 将所有资源对象的状态持久化存储在 etcd 中。理解资源对象在 etcd 中的存储路径与数据结构,是进行一致性复核、故障排查和压测分析的基础。本章将深入剖析 Pod、Service、ConfigMap 等核心资源在 etcd 中的存储机制。

3.1 存储路径结构:/registry/ 前缀与资源分组

所有 K8s 资源对象均存储在 etcd 的 /registry/ 根路径下,遵循统一的层级结构:

/registry/<资源组>/<资源类型>/<命名空间>/<资源名称>
资源对象 etcd 存储路径示例 说明
Pod /registry/pods/default/nginx-pod 核心组 v1,无资源组前缀
Service /registry/services/specs/default/my-service specs 存储 Service 规格,endpoints 存储端点
ConfigMap /registry/configmaps/default/app-config 核心组 v1
Deployment /registry/deployments/default/web-deploy apps/v1 组
Secret /registry/secrets/default/db-secret 核心组 v1
Node /registry/minions/node-01 集群级别资源,无命名空间
关键路径差异: Service 资源在 etcd 中分为 specs 和 endpoints 两个子路径存储,分别保存 Service 的规格定义和实际端点列表。这种分离设计使得端点变更不会触发 Service 规格的版本更新。

3.2 数据结构:序列化与版本控制

etcd 中存储的 K8s 资源对象以 Protobuf 序列化 格式保存,并通过 etcd v3 的 key-value 模型 管理。每个资源对象包含以下核心字段:

  • Key:资源路径,如 /registry/pods/default/nginx-pod
  • Value:Protobuf 编码的完整资源对象,包含 metadata、spec、status 等
  • CreateRevision:该 key 创建时的 etcd 全局修订版本号
  • ModRevision:该 key 最后一次修改时的修订版本号
  • Version:K8s 资源对象的内部版本号(resourceVersion)
  • Lease:关联的 etcd lease ID(用于 TTL 自动清理)
一致性复核关键字段: ModRevision 和 resourceVersion 是判断资源对象是否发生变更的核心依据。在压测沙盘中,通过对比这两个字段可以快速检测资源状态是否与预期一致。

3.3 Pod 资源在 etcd 中的完整数据结构

以 Pod 为例,其 etcd 存储的 Protobuf 结构(简化后)如下:

{
  "metadata": {
    "name": "nginx-pod",
    "namespace": "default",
    "uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "resourceVersion": "123456",
    "creationTimestamp": "2025-01-15T10:30:00Z",
    "labels": {"app": "nginx"}
  },
  "spec": {
    "containers": [{
      "name": "nginx",
      "image": "nginx:1.25",
      "ports": [{"containerPort": 80}]
    }],
    "nodeName": "node-01"
  },
  "status": {
    "phase": "Running",
    "podIP": "10.244.1.5",
    "conditions": [
      {"type": "Ready", "status": "True"}
    ]
  }
}
注意: etcd 中存储的是完整的资源对象,包括 status 字段。这意味着 etcd 的写入频率不仅受用户操作影响,还受控制器(如 kubelet、controller-manager)的状态更新影响。在压测场景中,状态更新可能占 etcd 写入量的 60% 以上。

3.4 资源对象与 etcd 映射关系图

下图展示了 K8s 核心资源在 etcd 中的存储路径层级与数据流向:

K8s资源对象与etcd映射关系 K8s 资源对象 → etcd 存储映射 Kubernetes API Server 核心组资源 (v1) Apps 组资源 (apps/v1) 其他 API 组资源 Pod Service ConfigMap Secret Deployment etcd v3 存储层 (Key-Value + 修订版本) etcd 存储示例(Key-Value 结构) Key: /registry/pods/default/nginx-pod Value: {metadata: {name: nginx-pod, resourceVersion: 123456, ...}, spec: {containers: [...], nodeName: node-01}, status: {phase: Running, podIP: 10.244.1.5, ...}}

3.5 资源对象版本号与 etcd 修订版本的关系

K8s 资源对象的 resourceVersion 与 etcd 的 ModRevision 存在直接映射关系:

概念 所属系统 作用范围 变更时机 一致性复核用途
resourceVersion Kubernetes 单个资源对象 资源 spec 或 status 变更时递增 判断资源是否被更新
ModRevision etcd 全局所有 key 任何 key 创建/更新/删除时递增 判断 etcd 层面是否发生变更
CreateRevision etcd 单个 key key 创建时固定 判断资源是否被重建
压测沙盘一致性复核策略: 在压测过程中,通过定期抓取 etcd 的 ModRevision 和 K8s 资源的 resourceVersion,对比两者的变化趋势。如果 ModRevision 递增但 resourceVersion 未变化,说明 etcd 层面发生了非资源变更的操作(如 lease 续期),需要进一步排查。

3.6 Service 的特殊存储结构:specs 与 endpoints 分离

Service 资源在 etcd 中采用双路径存储设计,这是 K8s 中唯一一个将规格与状态分离存储的资源类型:

  • /registry/services/specs/<namespace>/<service-name>:存储 Service 的规格定义(ClusterIP、端口映射、选择器等)
  • /registry/services/endpoints/<namespace>/<service-name>:存储 Service 对应的端点列表(Pod IP + 端口)

这种分离设计带来的优势:

  • 端点变更(Pod 扩缩容、重启)不会触发 Service 规格的版本更新
  • 减少不必要的 etcd 写入和 watch 事件
  • 端点控制器可以独立更新 endpoints 路径,不影响 Service 规格
一致性复核陷阱: 在压测沙盘中,如果只监听 /registry/services/specs/ 路径的变更,可能会遗漏端点变化。必须同时监听 /registry/services/endpoints/ 路径,才能完整捕获 Service 相关的所有 etcd 变更。

3.7 ConfigMap 与 Secret 的存储特点

ConfigMap 和 Secret 作为配置类资源,在 etcd 中具有以下存储特点:

特性 ConfigMap Secret
存储路径 /registry/configmaps/<ns>/<name> /registry/secrets/<ns>/<name>
数据编码 明文 UTF-8 字符串 Base64 编码(非加密)
数据大小限制 etcd 默认 1.5 MiB(可通过 --max-request-bytes 调整) 同 ConfigMap
变更频率 低(配置更新时触发) 低(密钥轮换时触发)
watch 事件类型 PUT(创建/更新)、DELETE PUT(创建/更新)、DELETE
压测建议: ConfigMap 和 Secret 的变更频率通常较低,但在大规模集群中(1000+ 节点),如果每个 Pod 都挂载 ConfigMap,etcd 的 watch 连接数会显著增加。建议在压测沙盘中模拟 ConfigMap 批量更新场景,测试 etcd 的 watch 性能瓶颈。

3.8 资源对象在 etcd 中的生命周期状态机

下图展示了 K8s 资源对象从创建到删除在 etcd 中的状态转换:

K8s资源对象在etcd中的生命周期状态机 K8s 资源对象在 etcd 中的生命周期状态机 创建 (PUT) CreateRevision 记录 更新 (PUT) ModRevision 递增 删除 (DELETE) Key 被移除 状态更新循环(status 变更) etcd 事件类型与 K8s 资源操作对应关系 • PUT 事件:对应 K8s 资源的创建(Create)和更新(Update)操作 • DELETE 事件:对应 K8s 资源的删除(Delete)操作 • 注意:etcd 的 TTL 过期删除也会触发 DELETE 事件(如 Lease 过期) • 一致性复核:通过对比 etcd 事件序列与 K8s 审计日志,验证资源变更是否一致

3.9 一致性复核实践:etcd 与 K8s 资源映射验证

在压测沙盘中,可以通过以下步骤验证 K8s 资源对象与 etcd 存储的一致性:

  1. 获取 K8s 资源列表:使用 kubectl get pods -o json 获取所有 Pod 的 resourceVersion
  2. 获取 etcd 对应 key 列表:使用 etcdctl get /registry/pods/ --prefix --keys-only 获取所有 Pod 的 etcd key
  3. 对比数量:确保 K8s 资源数量与 etcd key 数量一致
  4. 对比版本号:随机抽取资源,对比 resourceVersion 与 etcd 的 ModRevision 是否匹配
  5. 检查孤儿资源:查找 etcd 中存在但 K8s 中不存在的资源(或反之)
自动化复核脚本示例:
#!/bin/bash
# 一致性复核:对比 K8s Pod 与 etcd 存储
K8S_PODS=$(kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | sort)
ETCD_PODS=$(etcdctl get /registry/pods/ --prefix --keys-only | sed 's|/registry/pods/||' | sort)

# 对比数量
echo "K8s Pods count: $(echo "$K8S_PODS" | wc -l)"
echo "etcd Pods count: $(echo "$ETCD_PODS" | wc -l)"

# 查找差异
diff <(echo "$K8S_PODS") <(echo "$ETCD_PODS") || echo "差异发现!"
压测沙盘最佳实践: 建议在压测前后各执行一次一致性复核,记录 etcd 的 ModRevision 变化量。如果压测期间 ModRevision 变化量远大于预期资源变更数,可能存在控制器频繁更新状态的问题,需要进一步排查。