Kubernetes 运行时架构
概述
本文说明 gobrave 当前使用的 Kubernetes 运行时架构。
该实现基于以下代码:
internal/container_runtime/kubernetes/runtime.gointernal/container_runtime/kubernetes/monitor_v2.go
运行时支持两类工作负载:
deployment(长运行服务)job(一次性执行任务)
架构目标
- 在大规模场景下保持运行时监控高效。
- 避免同一个 runtime ID 启动重复监控循环。
- 将 Kubernetes 工作负载状态转换为稳定的 gobrave 运行时事件。
- 让用户侧生命周期行为保持可预测(
start、stop、delete、logs、inspect)。
高层流程
flowchart TD
A[Create ContainerSpec] --> B[KubernetesRuntime.Create]
B --> C{WorkloadKind}
C -->|deployment| D[Create Deployment]
C -->|job| E[Create Job]
D --> F[Optional Service -svc]
D --> G[Return runtimeID]
E --> G
H[Start or Recovery] --> I[KubernetesRuntime.Monitor]
I --> J{MarkIfNotMonitoring}
J -->|already monitoring| K[Return idempotently]
J -->|new| L[Start shared informers once]
L --> M[Register subscription kind namespace name]
M --> N[Deployment or Job events]
N --> O[Emit RuntimeEvent]
O --> P[ContainerManager state transition]Runtime ID 模型
Runtime ID 编码格式为:
<runtimeName>-<namespace>|<kind>|<name>
示例:
k8s-default|deployment|web-apik3s-ai|job|batch-import-001
该格式是 Start、Stop、Delete、Logs、Inspect 等运行时操作的前提。
资源创建模型
Deployment 路径
当 WorkloadKind 为 deployment(或为空,默认值)时:
- 创建 Deployment,并带上标签:
app=<workloadName>gobrave-workload=<workloadName>
- 若
ExposeService=true且ExposedPort>0,创建名为<workloadName>-svc的 ClusterIP Service。 - 返回 runtime ID。
Job 路径
当 WorkloadKind 为 job 时:
- 创建 Job,并带上标签:
app=<workloadName>gobrave-workload=<workloadName>
- 返回 runtime ID。
命名空间解析
命名空间优先级:
spec.RuntimeNamespace- 运行时配置中的 namespace
default
Pod Spec 映射(用户可见行为)
从 ContainerSpec 到 Kubernetes Pod 规范的映射:
Image、Entrypoint、Command、WorkDir直接映射。Env注入前按 key 排序(确保输出确定性)。CPU与Memory映射到容器资源限制。Volumes映射为hostPath挂载。User(数字 uid 或uid:gid)在可解析时映射到RunAsUser。ExposedPort增加容器端口。node类型调度约束映射到 required node affinity。
重启策略:
- Deployment:
Always - Job:
Never
监控架构(Informer 驱动)
KubernetesRuntime 默认使用 monitor_v2。
关键设计
- 共享 informer 在运行时进程内只启动一次。
- 通过
MarkIfNotMonitoring(runtimeID)保证监控注册幂等。 - 订阅键为
kind|namespace|name。 - 注册订阅后会立即执行一次快照检查。
使用的 Informer
- Deployment informer:add/update/delete
- Job informer:add/update/delete
为什么需要快照检查
在等待 informer 事件之前,运行时会对目标工作负载执行一次直接 Get。
这能避免错过注册前刚刚发生的启动或终态信号。
事件映射
运行时向 ContainerManager 发出以下事件:
Job
- 启动:
Status.Active > 0或Status.StartTime != nil->ContainerStarted - 成功:
Status.Succeeded > 0->ContainerExited,消息为0 - 失败:
Status.Failed > 0->ContainerFailed,消息取 condition message 或 failed count - 删除/未找到:delete 事件或查询未找到 ->
ContainerDeleted
Deployment
- 启动:
Status.ReadyReplicas > 0->ContainerStarted - 失败:副本失败或进度超时 ->
ContainerFailed - 退出:
spec.replicas == 0且status.replicas == 0->ContainerExited,消息为0 - 删除/未找到:delete 事件或查询未找到 ->
ContainerDeleted
发出终态事件后,会移除订阅并取消该 runtime ID 的监控成员标记。
生命周期语义
Start
- Deployment:扩容到 1,然后开始监控。
- Job:校验 Job 存在,然后开始监控。
Stop 与 Pause
- Deployment:缩容到 0。
- Job:删除 Job(foreground propagation)。
Pause当前实现等同于Stop。
Resume
Resume当前实现等同于Start。
Delete
- Deployment:删除 Service
<name>-svc(忽略 not found),再删除 Deployment。 - Job:删除 Job(foreground propagation)。
日志与 Inspect
Logs
Logs(runtimeID, tail):
- 从 runtime ID 解析工作负载元信息。
- 按标签
gobrave-workload=<name>找到最新 Pod。 - 读取 Pod 日志(默认 tail:200 行)。
Inspect
- Deployment:
IPAddress返回服务 DNS:<name>-svc.<namespace>.svc.cluster.localNodeName在可用时取最新 Pod 的节点名
- Job:
IPAddress为 Pod IPNodeName为 Pod 所在节点
限制与兼容性说明
- 支持的运行时名称:
k8s、k3s。 EnsureImage接受拉取策略Always与IfNotPresent。- 预检会拒绝拉取策略
Never。 Exec目前尚未实现。- 被删除的 Job 不能以同名工作负载重新启动。
运行建议
- 始终为受管工作负载保留
gobrave-workload标签。 - 使用单运行时进程 + 共享 informer,不要为每个工作负载单独建客户端。
- 可重复调用监控注册逻辑(其本身是安全幂等的)。
- 保持重启恢复能力开启,使进程重启后可重新接管非终态 runtime ID。
排障清单
- 没有收到生命周期更新:
- 检查 runtime ID 格式和运行时前缀(
k8s-或k3s-)。 - 检查 informer 启动与缓存同步错误。
- Deployment 一直不上报 started:
- 检查
ReadyReplicas与 Pod 调度状态。 - 检查 Deployment 失败条件(
ReplicaFailure、ProgressDeadlineExceeded)。
- Job 未发出终态事件:
- 检查
Succeeded/Failed字段与 Job conditions。 - 检查 Job 是否在监控注册前已被删除。
相关文档
- 运行时监控恢复:
/docs/runtime-monitor-recovery - 容器监控与队列状态:
/docs/container-monitoring - 事件订阅者:
/docs/event-bus-subscribers