Documentation
¶
Overview ¶
Package containerbackend 任务式执行后端的**容器参考实现**(issue #109 的示例半边)。
生命周期: Experimental(v0.35.0 定级)——参考实现随契约与真实引擎形态演进, 不构成任何兼容承诺;定级理由见 api-lifecycle.yaml,分级规则见 docs/api-compat.md。
为什么它是示例而不是内核包 ¶
内核 `backend` 只给契约与判据;把某个容器引擎的接法写进内核,等于把一种 部署形态焊进内核依赖面。本目录与 examples/pgstore 的分工同构: **宿主抄它,不 import 它**。两份实现:
- Docker(docker.go):逐字实现 `backend.Backend`,走 Docker Engine HTTP API(unix socket 或 TCP),**零第三方依赖**(stdlib net/http)—— 不引 Docker 客户端库,与内核「依赖面窄」的既有优势同一条纪律;
- Kubernetes Job(k8sjob.go):**接入点占位**——契约已经对齐,实现 留给宿主(client-go 是宿主侧依赖;本仓不引 K8s 客户端)。
接线方式(宿主视角) ¶
本包实现的是 `github.com/yi-nology/goagent-kernel/backend.Backend`。 宿主把它(或自己照抄的实现)登记进 backend.Registry,再按 backend.Spec 解析执行方:
var reg backend.Registry
_ = reg.Register(containerbackend.NewDocker()) // 容器隔离档
_ = reg.Register(backend.NewInline()) // 进程内兜底档
b, err := reg.Resolve(backend.Spec{
MinIsolation: backend.IsolationContainer,
Egress: sandbox.EgressDenied, // Docker 实现以 network=none 兑现
Budget: sandbox.Budget{MaxMemory: 256 << 20},
})
res, err := b.Exec(ctx, backend.Job{Image: "registry.example/app@sha256:…", ...})
README 的「执行后端」一节有同样的接线说明与升级边界。
dockerwire.go —— Docker 实现的**传输管道**:端点、请求骨架与日志流 demux。
拆分只为满足单文件 400 行阈值(make architecture-check):语义(自报什么、 执行步骤契约)在 docker.go,管道在这里。宿主改造接法时先读 docker.go。
k8sjob.go —— Kubernetes Job 适配的**接入点占位**(issue #109 明确本轮不做实现)。
为什么占位也要实现 backend.Backend:契约的接入点就是接口本身。占位结构体 让宿主在接线前就能编译通过(方法集齐全),同时**fail-closed**——见下面 Isolation 的自报说明:未接入前它按最弱档自报,判据不会在任何高于「无隔离」 的要求下选中它,Exec 一律报 ErrNotWired(响亮失败,不静默跑空)。
宿主接入 Kubernetes Job 的四步(写明边界,不留猜测空间) ¶
client-go 属**宿主侧依赖**:本仓与示例都不引 K8s 客户端(与
「Docker 客户端不进依赖面」同一条纪律;K8s 的清单/凭据更是宿主资产)。
1. **构造**:宿主用 client-go 的 kubernetes.NewForConfig 建客户端集,
存进自己的结构体(本占位不持有任何客户端字段);
2. **Isolation() 改回 Container**:Job 能落容器边界(namespace/cgroup
由内核裁剪)——接入后按事实自报,占位期的 IsolationNone 随即作废;
3. **实现 Exec**:Job → batchv1.Job 的映射参考 docker.go 的同一张表:
Job.Image → Containers[0].Image(**带 digest 原样携带**)、Job.Env → Env、
Job.Mounts → Volumes/VolumeMounts、Budget.MaxMemory → Resources.Limits、
Budget.WallClock → activeDeadlineSeconds(到点由 kubelet 终止,
对应 docker.go 的 kill 路径)、Job.BackoffLimit 设 1(作业失败不重试——
「跑几次」不是本契约的字段,交给 spec 层决定);
4. **出站能力如实声明**:集群的网络策略(NetworkPolicy / CNI)决定了
这个后端能强制哪一档 Egress——不能强制就别实现 EgressEnforcer
(沉默 = 判据按最弱处理,永远不会被要求禁网的 Spec 选中)。
为什么不提供一个「半成品 Exec」 ¶
任何半成品(空跑、只打日志、返回假成功)都会在宿主装配后把「没接上」 伪装成「跑过了」——那是本仓反复强调的最贵失败形态。ErrNotWired 让 未接入保持**未接入的形状**。
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEngineCall = errors.New("containerbackend: docker engine 调用失败")
ErrEngineCall Docker Engine 调用失败(创建 / 启动 / 等待 / 读取任一步失败)。
属于 backend.Result 注释里说的「后端基础设施故障」:作业没跑起来, 修复对象是引擎侧(引擎不可达 / 镜像不存在 / 参数被拒)。
var ErrNotWired = errors.New("containerbackend: k8s job 适配未接入(client-go 归宿主侧,接入步骤见包注释)")
ErrNotWired Kubernetes Job 适配尚未接入(接入步骤见包注释)。
Functions ¶
This section is empty.
Types ¶
type Docker ¶
type Docker struct {
// contains filtered or unexported fields
}
Docker Docker Engine 参考实现。
四条自报(判据按此判,实现按此兑现,缺一即登记门禁意义的说谎):
- Isolation() = IsolationContainer:作业跑在容器边界内(namespace / cgroup 由内核裁剪);
- Egress() = EgressDenied:**每个**作业都以 network=none 启动——出站 被网络命名空间强制阻断,不是「设了一组环境变量」;
- Capable:内存兜得住(容器内存上限),输出截断兜不住(如实自报 false),逐调用计数对作业形态不存在(同样 false);
- 墙钟经 context 截止兑现(超时杀容器,见 Exec)。
func NewDocker ¶
func NewDocker(opts ...DockerOption) *Docker
NewDocker 构造 Docker Engine 后端(缺省走宿主的缺省 socket——见 defaultSocket)。
func (*Docker) Egress ¶
func (d *Docker) Egress() sandbox.EgressMode
Egress 每个作业 network=none 启动 ⇒ 能强制禁网档。
func (*Docker) Exec ¶
Exec 执行一次作业:create → start → wait → inspect → logs → 清理。
步骤契约:
- 作业要求兜内存 ⇒ 容器以 Memory 上限启动(Capable 承诺的兑现点);
- 出站一律 network=none(Egress 承诺的兑现点);
- Budget.WallClock > 0 ⇒ wait 挂截止,到点 SIGKILL——超时不是「再等等」, 是预算的强制面;被预算终止的作业返回 Result{OK=false}(作业没跑完 是它的失败,不是引擎的故障);
- 作业跑完(无论成败)都读退出码与日志并清理容器;清理失败不掩盖 主结果(记进 Detail)。
type DockerOption ¶
type DockerOption func(*Docker)
DockerOption Docker 实现的装配项。
func WithAPIVersion ¶
func WithAPIVersion(v string) DockerOption
WithAPIVersion 覆盖 API 版本前缀(缺省 v1.41)。
func WithEndpoint ¶
func WithEndpoint(raw string) DockerOption
WithEndpoint 覆盖引擎端点(unix:///path/to.sock 或 http://host:port)。 测试以 httptest 端点注入假引擎。