deadman-switch · worker3 infra 节点的外部存活心跳
deadman-switch 是一个钉在 worker3 上的 CronJob 心跳器:它每分钟从 worker3 向集群外的 Uptime Kuma 推送一次心跳。
worker3 是唯一承担 workload=infra 的节点,同时托管全部数据库(node-role=database)和 infra 组件,是集群的单点。把心跳 Job 通过 nodeSelector: workload=infra 钉死在 worker3 上,当 worker3 宕机或不可达时 Job 无法调度、心跳随之停止,集群外(Oracle 主机上)的 Uptime Kuma 在其宽限窗口后告警。它监控的是 worker3 自身与出网链路的存活,而不是 Prometheus / Alertmanager 这条告警流水线本身——后者跑在同一个可能一起挂掉的集群里,无法自证存活,所以需要这个独立于集群的外部探针来兜底。
部署形态
- Name
- 命名空间
- Description
- deadman-switch(独立 namespace,本仓库 namespace.yaml 创建)
- Name
- 工作负载类型
- Description
- CronJob(batch/v1),schedule
* * * * *(每分钟)
- Name
- 镜像
- Description
- curlimages/curl:8.20.0
- Name
- 调度
- Description
- nodeSelector
workload: infra—— 钉死在 worker3(集群中唯一带该标签的节点)
- Name
- 并发策略
- Description
- concurrencyPolicy
Forbid,startingDeadlineSeconds 30,单 Job activeDeadlineSeconds 40,backoffLimit 0,restartPolicy Never
- Name
- 历史保留
- Description
- successfulJobsHistoryLimit 1 / failedJobsHistoryLimit 3
- Name
- 资源
- Description
- requests 10m CPU / 16Mi mem,limits 100m CPU / 64Mi mem
- Name
- 安全上下文
- Description
- runAsNonRoot(uid 65534)、readOnlyRootFilesystem、allowPrivilegeEscalation false、drop ALL capabilities、seccomp RuntimeDefault、automountServiceAccountToken false
容器的全部逻辑就是一行 curl:
curl -4 -fsS -m 20 "$PUSH_URL" && echo "heartbeat sent"
-4 强制走 IPv4:心跳目标 uptime.yldm.tech(Cloudflare)同时有 AAAA 记录,但 Pod 网络没有可用的 IPv6 出口,不加 -4 时 curl 约一半概率选到 IPv6 地址而连接失败,导致心跳抖动。
配置与依赖
心跳推送地址 PUSH_URL 不写进 git,而是通过 ExternalSecret 从 Vault 拉取,沿用 alertmanager-telegram 的模式。
- Name
- ExternalSecret
- Description
- deadman-switch-kuma,secretStoreRef 指向 ClusterSecretStore
vault-backend,refreshInterval 1h,creationPolicy Owner
- Name
- Vault 路径
- Description
monitoring/deadman-switch/kuma(dataFrom.extract),keypush_url;写入时对应vault kv put secret/monitoring/deadman-switch/kuma push_url=...
- Name
- env 注入
- Description
- PUSH_URL 来自 secretKeyRef
deadman-switch-kuma的push_url键
- Name
- 外部依赖
- Description
- Uptime Kuma(部署在集群外的 Oracle 主机上),经
uptime.yldm.tech(Cloudflare 前置)接收 push 心跳
ArgoCD 侧:Application deadman-switch 归属 project platform,开启 automated: {prune: true, selfHeal: true},CreateNamespace=false(namespace 由仓库内 namespace.yaml 显式创建)。三类资源用 sync-wave 排序:namespace -2 → ExternalSecret / NetworkPolicy -1 → CronJob 0,确保 namespace 和 secret 先于心跳 Job 就绪。
访问与监控
这是一个纯出站心跳器,没有 Service、Ingress、ServiceMonitor、HPA/VPA/PDB——监控由集群外的 Uptime Kuma 反向承担:有心跳即存活,停跳即告警。
namespace 内有一条默认拒绝的 NetworkPolicy(podSelector 选中全部 Pod):
| 方向 | 规则 |
|---|---|
| Ingress | 全部拒绝(ingress: []) |
| Egress | 仅允许到 CoreDNS(k8s-app: kube-dns,UDP/TCP 53)解析域名,以及对 0.0.0.0/0 的 TCP 443 出站 HTTPS |
出站 HTTPS 不能锁到单个源 IP:uptime.yldm.tech 现已挪到 Cloudflare 后面,边缘 IP 轮换,旧的 129.150.55.22/32 固定 pin 会因 deadman Pod 生命周期极短、抢在 NetworkPolicy 编程完成之前发起请求而间歇性失败。
注意事项
这个组件本身就是对 worker3 单点风险的兜底手段,理解时要抓住几点。
监控对象是 worker3 节点 + 出网链路的存活,不是 Prometheus / Alertmanager 流水线。infra 单点宕机后的处置顺序、哪些工作负载能漂移、哪些必须恢复,见仓库内的 docs/infra-node-down-runbook.md(H3 段专门讲到该心跳)。
心跳停跳到告警之间有一个宽限窗口,由集群外 Uptime Kuma 一侧配置;CronJob 这侧每分钟一跳、Forbid 并发、单 Job 40 秒超时,意味着探针对调度延迟敏感,worker3 一旦无法调度 Job,心跳会很快归零。
curl 的 -4 与 NetworkPolicy 放开 0.0.0.0/0:443 都是为修过往的间歇性失败而存在的(IPv6 误选、Cloudflare 动态边缘 IP),不要在"加固"时把它们改回固定 IP pin 或去掉 -4,否则心跳会重新抖动而误报。
返回 infrastructure 总览