docker

package
v0.1.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package docker implements a box.Provisioner backed by the Docker Engine API. Each box is a container whose entrypoint is the llmbox guest (run under tini); the host reaches the guest over a per-box Unix socket bind-mounted from the host into the container, so all box behaviour (login, exec, logs, port dialing) runs through the guest rather than through Docker exec/attach. The provisioner only owns compute: it creates, lists, resolves, and destroys containers, and hands back a control channel to the guest.

Safety: every container carries ManagedLabel; list/find/destroy are scoped to that label so unrelated host containers are never touched. A provisioner may additionally be pinned to a namespace (SetNamespace): its containers then also carry NamespaceLabel and list/find/destroy are scoped to it, so two spokes sharing one Docker daemon never see, reap, or destroy each other's boxes.

Index

Constants

View Source
const (
	// ManagedLabel marks every container created by this provisioner.
	ManagedLabel = "com.llmbox.managed"

	// BoxIDLabel and DescriptionLabel persist the caller-assigned box ID and
	// description so List can report them straight from a container summary.
	BoxIDLabel       = "com.llmbox.box-id"
	DescriptionLabel = "com.llmbox.description"

	// GenerationLabel persists the box's opaque generation token: the per-box
	// incarnation identity exposed to the hub as the box's InstanceID. It is a
	// spoke-minted random token (never the Docker container id), stored on the
	// container so List can recover it after a spoke restart. The hub uses it only
	// for staleness/reap equality — it is never parsed, prefix-matched, or used to
	// address the box (addressing is by box ID). Keeping it distinct from the real
	// container id is what prevents any Docker-native handle from reaching the hub.
	GenerationLabel = "com.llmbox.generation"

	// NamespaceLabel scopes a container to one provisioner's namespace (see
	// SetNamespace). It is only set when a namespace is configured; boxes created
	// without one carry no NamespaceLabel and are visible to any unscoped
	// provisioner, preserving the pre-namespace behaviour.
	NamespaceLabel = "com.llmbox.namespace"

	// DefaultImage is launched when the caller does not specify one. It bakes in
	// the box workload, the llmbox-guest binary (its entrypoint),
	// tini, and a CA bundle (see Dockerfile.box).
	DefaultImage = "ghcr.io/clems4ever/llmbox-box:latest"

	// DefaultSocketDir is the host directory holding per-box control sockets when
	// the operator does not configure one. Each box gets a 0700 subdirectory.
	DefaultSocketDir = "/run/llmbox/boxsockets"
)

Variables

This section is empty.

Functions

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err indicates that no managed box matched the identifier. It recognizes both the typed ErrBoxNotFound (local calls) and an error that round-tripped over the cluster transport as a bare string.

@arg err The error to classify; nil is not a not-found error. @return bool Whether err means the box does not exist.

@testcase TestIsNotFound recognizes the sentinel, a wrapped error, a wire string, and rejects others.

Types

type Provisioner

type Provisioner struct {
	// contains filtered or unexported fields
}

Provisioner creates and tears down boxes on a Docker daemon and exposes each box's guest over a bind-mounted Unix socket. It implements box.Provisioner.

func NewProvisioner

func NewProvisioner(defaultImage, socketDir string, peers []string, ports boxapi.PortService) (*Provisioner, error)

NewProvisioner builds a Provisioner using Docker configuration from the environment. An empty defaultImage falls back to DefaultImage; an empty socketDir falls back to DefaultSocketDir.

@arg defaultImage The image launched when a caller does not specify one; empty uses DefaultImage. @arg socketDir The host directory holding per-box control sockets; empty uses DefaultSocketDir. @arg peers Resource-server container names connected into every box's network. @arg ports The service serving box-originated port requests; nil disables the per-box box-port API. @return *Provisioner A provisioner wired to a Docker client built from the environment. @error error if the Docker client cannot be created.

@testcase TestProvisionCreatesGuestBox covers a provisioner built by NewProvisioner.

func (*Provisioner) Close

func (p *Provisioner) Close() error

Close stops every live box-port API listener and releases the Docker client. The boxes themselves keep running (they are recovered on the next start via RecoverBoxAPIs).

@error error if the Docker client cannot be closed.

@testcase TestProvisionCreatesGuestBox builds a provisioner whose client is closed in cleanup. @testcase TestCloseStopsBoxAPIListeners stops the box-port listeners on Close.

func (*Provisioner) Find

func (p *Provisioner) Find(ctx context.Context, idOrName string) (box.Instance, error)

Find resolves an ID or name to the single managed box it identifies.

@arg ctx Context for the underlying list. @arg idOrName The caller-assigned box ID (the usual handle), the box's generation token, or its container name. @return box.Instance The matched box. @error error wrapping sandbox.ErrBoxNotFound if no managed box matches.

@testcase TestFindResolvesByIDAndBoxID resolves a box by its generation token and by its box id. @testcase TestFindUnknownBox errors when no managed box matches.

func (*Provisioner) List

func (p *Provisioner) List(ctx context.Context) ([]box.Instance, error)

List returns a handle to every managed box, running or not.

@arg ctx Context for the Docker list request. @return []box.Instance One handle per managed container. @error error if listing containers fails.

@testcase TestListMapsManagedContainers checks the mapping and the managed filter.

func (*Provisioner) Provision

func (p *Provisioner) Provision(ctx context.Context, opts sandbox.CreateOptions) (box.Instance, error)

Provision creates and starts a box: a container whose entrypoint is the guest, with the box's host socket directory bind-mounted in so the host can reach the guest. The box is created on its own network (peers wired in, isolated from other boxes), named with the pending prefix, and run as root with no-new-privileges, the configured resource caps and GPUs, and a restart policy of "unless-stopped" so a crashed box (and its always-on guest) comes back. When the provisioner is namespaced, the box (and its network) carry NamespaceLabel.

@arg ctx Context for the Docker calls and the socket wait. @arg opts The caller-controlled box ID, description, and files (the image is the spoke's configured default). @return box.Instance A handle to the started box, in the pending phase. @error error if the box id is invalid, the image cannot be pulled, or the box cannot be created, networked, started, or its guest socket does not appear.

@testcase TestProvisionCreatesGuestBox creates a guest-entrypoint box with the socket mount and restart policy. @testcase TestProvisionCleansUpOnStartFailure removes the container, network, and socket dir when start fails. @testcase TestProvisionAppliesLimits applies the configured resource caps and no-new-privileges. @testcase TestProvisionAppliesGPUs attaches the configured GPU device requests. @testcase TestProvisionPullsMissingImage pulls the image then retries when it is absent. @testcase TestProvisionSetsNamespaceLabel stamps the configured namespace on the box.

func (*Provisioner) RecoverBoxAPIs

func (p *Provisioner) RecoverBoxAPIs(ctx context.Context) error

RecoverBoxAPIs restarts the box-port API listener of every managed box after a spoke restart: the containers persist (restart policy unless-stopped) but the host-side listeners die with the spoke process. Each box's identity and socket dir are recovered from its container labels. Best-effort per box — one failure is logged and does not block the others.

@arg ctx Context for the container listing. @error error if the managed containers cannot be listed.

@testcase TestRecoverBoxAPIsRestartsListeners restarts listeners from container labels.

func (*Provisioner) SetBoxGPUs

func (p *Provisioner) SetBoxGPUs(spec string) error

SetBoxGPUs configures the GPUs attached to every box, from a `docker run --gpus`-style spec: "" attaches none, "all" attaches every GPU, a positive integer attaches that many, and a comma-separated (optionally "device="- prefixed) list selects GPUs by id/index.

@arg spec The GPU spec: "", "all", a positive count, or a device list. @error error if the spec is malformed.

@testcase TestSetBoxGPUsParsesSpec accepts all/count/device-list specs and rejects bad ones. @testcase TestProvisionAppliesGPUs attaches the configured device requests to the host config.

func (*Provisioner) SetNamespace

func (p *Provisioner) SetNamespace(ns string)

SetNamespace pins this provisioner to a namespace so it only ever sees the boxes it created: created boxes carry NamespaceLabel with this value and List/Find/Destroy are scoped to it. This lets two spokes share one Docker daemon without collapsing each other's containers. An empty namespace leaves the provisioner unscoped (the pre-namespace behaviour).

@arg ns The namespace to scope this provisioner to; empty leaves it unscoped.

@testcase TestProvisionSetsNamespaceLabel labels a box with the configured namespace. @testcase TestManagedFilterScopesByNamespace scopes list/find to the namespace.

func (*Provisioner) SetPerBoxLimits

func (p *Provisioner) SetPerBoxLimits(l sandbox.Limits)

SetPerBoxLimits sets the per-box memory/CPU/PID caps applied at create. The MaxBoxes field is ignored here (box.Manager enforces the box count), as are the disk-size fields (DiskBytes/MaxDiskBytes): a container has no per-box resizable block device, so disk sizing is a Firecracker-only knob.

@arg l The resource limits; only MemoryBytes/NanoCPUs/PidsLimit are used.

@testcase TestProvisionAppliesLimits applies the configured caps to the host config.

func (*Provisioner) SetRegistryAuths

func (p *Provisioner) SetRegistryAuths(auths map[string]registry.AuthConfig)

SetRegistryAuths supplies pull credentials keyed by registry host; nil/empty leaves every pull anonymous.

@arg auths Pull credentials keyed by registry host.

@testcase TestProvisionPullsWithRegistryAuth pulls a private image using the configured credentials.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL