Documentation
¶
Overview ¶
Package k8s is the Kubernetes sandbox backend: one disposable Pod per session, driven over the Kubernetes API. The image must carry /bin/bash at that exact path (the plan's image contract) plus a userland with `setsid` (the deadline wrapper backgrounds the command in its own session), `tee` and `wc` (the write path counts the bytes the exec stream delivered), `cat` (every read streams through one, and a write that refuses or fails with the body still unread drains it with one, #303/#304), `mv` and `rm` (it lands the bytes under a temporary name and renames them into place), `tar` (a bulk write's archive is extracted inside the pod here, where the docker backend hands its own to the daemon and needs nothing — so an image without one loses skill materialization outright, #206), and a `stat` that accepts `-c`, GNU or BusyBox — required here rather than merely wanted as it is on docker, because a read's size gate exits on it. (`chmod` and that same `stat` also carry the target's mode onto the temporary file on a write, but that step degrades to a 0644 file rather than failing.) A shade beyond bare POSIX, but met by any mainstream base image. It is the self-hosted twin of the docker backend and passes the same sandboxtest contract suite.
Index ¶
- type Config
- type Provider
- func (p *Provider) Export(ctx context.Context, sessionID domain.ID, root string) (io.ReadCloser, error)
- func (p *Provider) Owned(ctx context.Context) ([]domain.ID, error)
- func (p *Provider) Provision(ctx context.Context, spec sandbox.Spec) (sandbox.Sandbox, error)
- func (p *Provider) Reap(ctx context.Context, sessionID domain.ID) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
Kubeconfig string
Context string
Namespace string
NetSetupImage string
RuntimeClass string
NodeSelector string
Tolerations string
ImagePullSecrets string
// GateTokenRevoker, when non-nil, is called by Reap before it deletes a
// session's pod, so a gate token never outlives its gate (#197). On the
// provider — not a Spec — because Reap has no Spec: the reaper works from
// a session id alone. The executor supplies its pool-backed
// implementation; the BYOC worker has no database and leaves it nil.
GateTokenRevoker sandbox.GateTokenRevoker
}
Config selects the cluster and namespace. Kubeconfig empty with Context empty tries in-cluster config first (the executor running as a Deployment), then the default loading rules (KUBECONFIG, ~/.kube/config) — the latter is what the contract test and local development use.
NetSetupImage is the tiny utility image whose init container flushes a limited sandbox's routing table (it needs an `ip` command, which the sandbox image is not required to carry); empty defaults to busybox.
RuntimeClass names the RuntimeClass sandbox pods run under — a hardened runtime such as gVisor's `runsc` or Kata. It lives here rather than on sandbox.Spec because which runtimes a cluster has is a property of the cluster, not of a session. Empty uses the cluster's default runtime; a name no RuntimeClass object defines makes the kubelet refuse the pod, which is the fail-closed direction.
NodeSelector and Tolerations are where a sandbox pod may run, and are here for the same reason RuntimeClass is: which nodes a cluster has is a property of the cluster. They are carried as the raw strings the deployment configured, so the one place that knows their encoding is the one place that parses them (placement.go) — New rejects a malformed value rather than letting it become a pod that never schedules.
ImagePullSecrets names the Secrets sandbox pods pull images with — comma-separated, raw here and parsed the same way (pullsecrets.go), for the same reason: which registry credential a cluster holds is a property of the deployment, not of a session.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider provisions per-session pods.
func (*Provider) Export ¶ added in v0.2.0
func (p *Provider) Export(ctx context.Context, sessionID domain.ID, root string) (io.ReadCloser, error)
Export streams one root out of the session's pod as a tar via an in-pod `tar -cf - -C <parent> <base>` exec — members under one top-level directory named after the root's base name, matching the Docker archive endpoint's shape so the checkpoint engine reads one contract. The pod is selected by label, never by derived name, and must be running: a K8s exec has no stopped-container path, so an unexecable pod surfaces its error and the caller degrades to reap-without-checkpoint (plan 24 D8). tar is the image contract's one guaranteed archiver.
func (*Provider) Owned ¶ added in v0.2.0
Owned lists the distinct session ids of every pod in this namespace carrying the ownership label — the gate rides inside the sandbox pod here, so one pod is a session's entire holding.
func (*Provider) Provision ¶
Provision returns the session's pod, creating and starting it only if none exists. Two executors racing on the same session converge: the loser of the create race adopts the winner's pod.
func (*Provider) Reap ¶ added in v0.2.0
Reap destroys everything this namespace owns for the session — its pod, gate sidecar included — revoking the session's gate token first when the provider has a revoker (#197; revoke-before-teardown keeps a partial failure retryable). It selects by label rather than deriving the pod name, needs no live handle, and waits for each pod object to be gone from the API (deleteAndWaitGone) — never returning success, or failure, on a pod that is merely terminating. The delete is grace-0, so "gone" carries Destroy's own bound: the API object is final at once, while a partitioned node's kubelet may lag stopping the containers. A session owning nothing is a no-op.