
OpenSandbox Task Executor 使用指南在 Kubernetes Pod 中运行与托管短期任务【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox本文档系统讲解 OpenSandbox 项目中task-executor组件的定位、部署启动、配置参数、HTTP API、任务规范TaskSpec与任务状态TaskStatus模型并结合仓库源码揭示其进程执行、Sidecar 命名空间注入、状态协调与持久化等底层实现原理。读完本文你将能够独立启动一个 task-executor 实例通过 REST API 或 Go SDK 创建、查询、同步与删除短期任务并理解其在BatchSandboxController等 Kubernetes 控制器协作链路中的角色。组件定位Pod 内的短期任务本地代理task-executor是一个轻量级组件设计用于在 Kubernetes Pod 环境中运行和管理短期任务进程或容器。它在 kubernetes/cmd/task-executor/main.go 中启动充当本地代理角色从 Kubernetes 控制器例如BatchSandboxController接收任务规范并在其运行的节点上执行这些任务同时暴露一个简单的 HTTP API 用于任务创建、状态查询与管理。从源码结构看task-executor 内部划分为五个清晰的功能模块位于 kubernetes/internal/task-executor模块职责关键文件config命令行标志 / 环境变量解析与默认值config/config.goserverHTTP 路由与 REST handlerserver/router.go、server/handler.gomanager任务生命周期管理、协调循环、状态持久化manager/task_manager.goruntime进程 / 容器执行器composite 分发runtime/composite.go、runtime/process.gostorage基于文件的任务状态存储storage/file_store.go入口程序 kubernetes/cmd/task-executor/main.go 的启动序列依次为加载配置环境变量 → 命令行标志→ 初始化 klog 日志 → 初始化文件存储 → 创建复合执行器 → 创建任务管理器并启动 → 注册 HTTP 路由 → 启动 HTTP 服务。进程收到SIGINT/SIGTERM后会先优雅关闭 HTTP 服务30 秒超时再停止任务管理器。运行 Task Executor基本启动使用 kubernetes/cmd/task-executor/main.go 作为入口点启动支持命令行标志与环境变量两种配置方式/path/to/cmd/task-executor/main --data-dir/var/lib/sandbox/tasks --listen-addr0.0.0.0:5758关键配置参数下表完整列出 task-executor 的配置项。其中默认值均取自 config/config.go 的NewConfig()标志 / 环境变量描述默认值--data-dir(DATA_DIR)用于持久化任务状态和日志的目录。/var/lib/sandbox/tasks--listen-addr(LISTEN_ADDR)HTTP API 服务器的地址和端口。0.0.0.0:5758--enable-sidecar-mode(ENABLE_SIDECAR_MODE)为true时启用 sidecar 模式执行任务在指定主容器的 PID 命名空间内运行需要nsenter和适当权限。false--main-container-name(MAIN_CONTAINER_NAME)启用 sidecar 模式时指定提供 PID 命名空间的主容器名称。main--enable-container-mode(ENABLE_CONTAINER_MODE)为true时启用基于 CRI 运行时的容器模式执行注意当前实现为占位符。false--cri-socket(CRI_SOCKET)容器模式下 CRI 套接字路径。/var/run/containerd/containerd.sock--reconcile-interval内部任务管理器协调任务状态的间隔。500ms补充配置参数源码级除上述文档化参数外config/config.go 还注册了以下标志便于在 Pod 中控制服务行为标志描述默认值--log-max-size单个日志文件最大大小MB达到后按 lumberjack 规则轮转。100--log-max-backups保留的最大日志备份文件数。10--log-max-age日志文件最长保留天数。7--log-dir日志文件目录日志写入log-dir/task-executor.log且启用 gzip 压缩轮转。logsHTTP 服务本身还内置了两个固定的超时参数无对应 CLI 标志ReadTimeout与WriteTimeout默认均为 30 秒config/config.go在 kubernetes/cmd/task-executor/main.go 中注入http.Server。环境变量仅在非空布尔变量为等于字符串true时覆盖默认值随后命令行标志再覆盖环境变量见 LoadFromEnv 与LoadFromFlags的调用顺序。HTTP API 端点task-executor 暴露了一套 RESTful HTTP API路由注册见 server/router.go。所有需要请求体的调用期望 JSON响应同样为 JSON出错时返回统一结构的ErrorResponse含code与message字段见 server/handler.go。1.POST /tasks— 创建新任务创建并启动单个任务。方法POST路径/tasks请求体application/json代表所需任务的对象。{ name: my-first-task, spec: { process: { command: [sh, -c], args: [echo Hello from my task! sleep 5 echo Task finished.] } } }响应体application/json创建的任务对象及其初始状态HTTP 201 Created。{ name: my-first-task, spec: { process: { command: [sh, -c], args: [echo Hello from my task! sleep 5 echo Task finished.] } }, status: { state: { waiting: { reason: Initialized } } } }curl 示例curl -X POST -H Content-Type: application/json -d { name: my-first-task, spec: { process: { command: [sh, -c], args: [echo \Hello from my task!\ sleep 5 echo \Task finished.\] } } } http://localhost:5758/tasks对应实现位于 CreateTask解码请求体 → 校验任务名非空 → 转换为内部任务 → 调用manager.Create。若任务名重复或活跃任务数已达上限返回 500 错误详见下文并发上限。2.GET /tasks/{id}— 获取任务状态按名称检索特定任务的当前状态。方法GET路径/tasks/{taskName}响应体application/json任务对象包括当前状态。{ name: my-first-task, spec: { process: { command: [sh, -c], args: [echo Hello from my task! sleep 5 echo Task finished.] } }, status: { state: { running: { startedAt: 2025-12-17T10:00:00Z } } } }curl 示例curl http://localhost:5758/tasks/my-first-task任务不存在时返回 404GetTask。3.DELETE /tasks/{id}— 删除任务标记要删除的任务。task-executor 会先尝试优雅停止任务再删除其状态与存储记录。方法DELETE路径/tasks/{taskName}响应成功标记删除时返回204 No Content。curl 示例curl -X DELETE http://localhost:5758/tasks/my-first-task这里实现的是软删除DeleteTask调用manager.Delete内部通过softDeleteLocked仅为任务打上DeletionTimestamp时间戳并持久化task_manager.go真正的进程停止与记录清理由后台协调循环完成。4.POST /setTasks— 同步任务此端点通常由控制器用于同步所需的任务集。不在所需列表中的任务将被标记删除新任务将被创建。它是控制器声明式调谐模式的落点。方法POST路径/setTasks请求体application/json代表所需状态的任务对象数组。[ { name: task-alpha, spec: { process: { command: [sleep, 10] } } }, { name: task-beta, spec: { process: { command: [ls, -l, /tmp] } } } ]响应体application/json同步后执行器管理的当前任务列表。[ { name: task-alpha, spec: { process: { command: [sleep, 10] } }, status: { state: { waiting: { reason: Initialized } } } }, { name: task-beta, spec: { process: { command: [ls, -l, /tmp] } }, status: { state: { waiting: { reason: Initialized } } } } ]curl 示例curl -X POST -H Content-Type: application/json -d \ [ { name: task-alpha, spec: { process: { command: [sleep, 10] } } }, { name: task-beta, spec: { process: { command: [ls, -l, /tmp] } } } ] http://localhost:5758/setTasks底层同步算法见 manager.Sync先遍历当前任务集合将不在期望列表中的任务软删除再遍历期望列表为尚不存在的任务创建两类操作中出现的错误通过errors.Join汇总返回但部分失败不会中断整体同步。5.GET /getTasks— 列出所有任务检索 task-executor 当前管理的所有任务列表。方法GET路径/getTasks响应体application/json任务对象数组。[ { name: task-alpha, spec: { process: { command: [sleep, 10] } }, status: { state: { running: { startedAt: 2025-12-17T10:05:00Z } } } }, { name: task-beta, spec: { process: { command: [ls, -l, /tmp] } }, status: { state: { terminated: { exitCode: 0, reason: Succeeded, startedAt: 2025-12-17T10:06:00Z, finishedAt: 2025-12-17T10:06:01Z } } } } ]curl 示例curl http://localhost:5758/getTasks6.GET /health— 健康检查返回 task-executor 的健康状态可挂载到 Pod 的readinessProbe/livenessProbe。方法GET路径/health响应体application/json{ status: healthy }curl 示例curl http://localhost:5758/health任务规范TaskSpec结构任务对象的spec字段定义了任务应如何执行。对外 API 类型定义在 kubernetes/pkg/task-executor/types.go目前支持process与container两种执行模式。执行器通过 compositeExecutor.getDelegate 按是否提供process字段自动分发到进程执行器或容器执行器。进程任务示例此模式直接作为进程执行命令是最常用、也是当前完全可用的模式{ name: my-process-task, spec: { process: { command: [python3, my_script.py], args: [--config, /etc/app/config.yaml], env: [ { name: DEBUG_MODE, value: true } ], workingDir: /app } } }Process类型还支持以下字段kubernetes/pkg/task-executor/types.go字段类型说明command[]string可执行命令必填。args[]string追加到命令的参数。env[]corev1.EnvVar注入进程的环境变量列表。workingDirstring进程工作目录。timeoutSeconds*int64进程超时秒数超过后状态转为Timeout。execModeLocal \| Remote执行位置Local在 task-executor 容器内执行Remote通过nsenter进入主容器执行为空时跟随--enable-sidecar-mode全局配置。lifecycleProcessLifecycle主进程前后的生命周期钩子见下文专节。容器任务示例占位符/未来特性此模式设计为在由 CRI 运行时管理的容器中执行任务。请注意runtime/container.go 中的容器执行器三个方法均直接返回container mode is not implemented yet - use process mode instead错误即该模式目前仍是占位符实际部署应使用进程模式{ name: my-container-task, spec: { container: { image: ubuntu:latest, command: [/bin/bash, -c], args: [apt update apt install -y curl], env: [ { name: http_proxy, value: http://myproxy.com:5758 } ], volumeMounts: [ { name: data-volume, mountPath: /data } ] } } }任务状态TaskStatus结构任务对象的status字段提供任务当前执行状态的详细信息。对外 API 层使用processStatusWaiting/Running/Terminated三态之一见 kubernetes/pkg/task-executor/types.go内部执行状态则定义在 kubernetes/internal/task-executor/types/task.go二者通过 convertInternalToAPITask 完成映射。{ name: my-task, spec: { ... }, status: { state: { waiting: { reason: Initialized } }, // 或者 state: { running: { startedAt: 2025-12-17T10:00:00Z } }, // 或者 state: { terminated: { exitCode: 0, reason: Succeeded, message: Task completed successfully, startedAt: 2025-12-17T10:00:00Z, finishedAt: 2025-12-17T10:00:05Z } } } }状态类型waiting任务正在等待执行如刚创建、reason为Initialized。running任务当前正在执行携带startedAt。terminated任务已完成成功或失败携带exitCode、reason、startedAt与finishedAt。内部状态机与子状态内部管理层面使用更细粒度的状态机types/task.goPending、Running、Succeeded、Failed、Unknown、NotFound、Timeout。每个状态还附带SubStatuses数组Reason/Message/ExitCode/StartedAt/FinishedAt用于向调度器暴露可读的失败细节。例如进程启动失败时会以PreStartHookFailed或ProcessStartFailed等机器可读的Reason持久化Failed状态manager/task_manager.go避免静默丢弃失败任务。进程执行器 runtime/process.go 的Inspect判定逻辑为存在退出码文件 → 退出码为 0 则SucceededReasonSucceeded否则Failed无退出码但有 PID 且进程存活 →Running若超过timeoutSeconds则转为TimeoutReasonTaskTimeout有 PID 但进程已消失且无退出码 →FailedReasonProcessCrashedExitCode137无 PID 文件 →Pending。生命周期钩子Lifecycle HooksProcess.Lifecycle支持preStart与postStop两个钩子类型定义见 kubernetes/pkg/task-executor/types.go每个钩子可指定exec.command、execMode默认本地执行与timeoutSeconds{ name: hook-task, spec: { process: { command: [/bin/bash, -c], args: [echo run], lifecycle: { preStart: { exec: { command: [/bin/sh, -c, mkdir -p /data/run] }, timeoutSeconds: 10 }, postStop: { exec: { command: [/bin/sh, -c, rm -f /data/run/lock] } } } } } }对应实现位于 runtime/process.gopreStart在启动主进程前执行失败则整个启动流程以StartError{Reason: PreStartHookFailed}终止postStop在停止主进程后执行失败以StopError{Reason: PostStopHookFailed}记录钩子输出使用头尾缓冲采集各保留前 8 KiB 与后 8 KiB中间以省略标记截断常量见 runtime/process.go失败时随错误信息返回钩子默认在本地执行execMode: Remote时才通过nsenter进入主容器命名空间任务管理器会确保终态任务即使重启后也不会重复执行postStop 钩子通过PostStopHookCompleted标记合并判定见 manager/task_manager.go。深入原理进程执行、协调循环与持久化进程执行shim 脚本充当 mini-initprocessExecutor.Start 为每个任务生成一段 shim 脚本buildShimScript其作用类似 mini-init以后台方式运行用户命令并记录CHILD_PID捕获SIGTERM并将其转发给子进程实现优雅停止传播等待子进程退出并捕获退出码写入data-dir/task-name/exit文件。每个任务目录下会持久化四个文件pid进程 PID、exit退出码、stdout.log、stderr.log进程标准输出/错误追加写入。进程以新的进程组启动Setpgid: true停止时先向进程组发送SIGTERM等待 10 秒后仍不退出则升级为SIGKILLstopMainProcess。状态协调循环任务管理器启动后会执行recoverTasks从文件存储恢复历史任务含命名空间丢失场景下的状态合并与僵尸任务丢弃判定manager/task_manager.go然后以--reconcile-interval默认 500ms为周期运行协调循环reconcileLoop。每轮协调执行观察每个任务状态 → 根据删除时间戳、终态、超时与 postStop 需求做出停止决策 → 最终删除已确认清理的任务。停止动作通过 goroutine 异步执行避免阻塞协调周期。并发上限从源码结构看任务管理器定义了maxConcurrentTasks 1manager/task_manager.go即同一时刻最多允许一个活跃任务Pending/Running超出时创建请求返回maximum concurrent tasks (1) reached错误。批量场景应优先使用/setTasks的声明式同步而非并发创建。文件存储与可写性校验storage/file_store.go 的NewFileStore在初始化时会创建数据目录并写入测试文件校验可写性随后以每任务一把读写锁的方式保证并发安全任务状态以 JSON 形式落盘使 task-executor 具备 Pod 重启后的状态恢复能力。示例场景运行 Sidecar 任务Sidecar 模式是 task-executor 的核心能力之一当配置--enable-sidecar-modetrue且--main-container-namemy-main-app时任务将在my-main-app容器的 PID 命名空间内执行仿佛任务进程直接运行在主业务容器中。实现上进程执行器通过nsenter完成命名空间注入runtime/process.go遍历/proc查找带有环境变量SANDBOX_MAIN_CONTAINER主容器名的进程解析其 PIDfindPidByEnvVar读取该进程的/proc/pid/environ作为任务进程的环境执行nsenter -t PID --mount --uts --ipc --net --pid -- /bin/sh -c shim-script。curl 示例# 假设 task-executor 在 sidecar 模式下运行在一个包含 my-main-app 的 pod 上 # 此任务将从主容器的命名空间内执行 ls /proc/self/ns curl -X POST -H Content-Type: application/json -d { name: sidecar-namespace-check, spec: { process: { command: [ls, /proc/self/ns] } } } http://localhost:5758/tasks停止时sidecar 任务会优先读取/proc/pid/task/pid/children找到真正运行在目标命名空间内的 shim 子进程对其发送SIGTERMstopMainProcess从而保证信号准确投递到目标命名空间内部。使用 Go SDK 客户端除了裸 HTTP API仓库还提供了官方 Go 客户端 kubernetes/pkg/task-executor/client.go封装了Set创建/更新传nil则清空全部任务与Get拉取任务列表两个方法。完整的可运行示例见 kubernetes/examples/task-executor/main.go核心流程如下baseURL : http://localhost:5758 client : taskexecutor.NewClient(baseURL) newTask : taskexecutor.Task{ Name: example-task, Process: taskexecutor.Process{ Command: []string{sh, -c}, Args: []string{echo Hello from SDK example! sleep 2 echo Task done.}, }, } // 提交任务内部映射为 POST /setTasks createdTask, err : client.Set(ctx, newTask) // 轮询状态直至 Terminated for i : 0; i 10; i { currentTask, err : client.Get(ctx) if currentTask.ProcessStatus.Terminated ! nil { fmt.Printf(Task finished with exit code: %d\n, currentTask.ProcessStatus.Terminated.ExitCode) break } time.Sleep(500 * time.Millisecond) } // 清理传 nil 清空任务 _, err client.Set(ctx, nil)该示例也演示了getTaskState帮助函数如何根据ProcessStatus中的Waiting/Running/Terminated字段呈现可读状态——与 HTTP API 返回的任务状态模型完全一致。总结task-executor以约 6 个 REST 端点为边界把进程级短期任务的创建、查询、同步、删除与健康检查完整封装为一个可独立部署的本地代理组件process模式开箱即用sidecar模式借助nsenter实现主容器命名空间注入container模式仍为占位符等待后续实现底层以 shim 脚本、PID/退出码文件与文件存储支撑进程生命周期管理和 Pod 重启恢复并以 500ms 协调循环持续将真实运行状态收敛到期望状态。对于需要在自己 Pod 中托管批处理、一次性脚本或诊断任务的开发者可直接复用本文的 curl 示例或 Go SDK 接入更完整的端到端集成示例可参考 kubernetes/examples/task-executor。【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考