Documentation
¶
Overview ¶
Package runtime defines the backend abstraction for container runtimes.
v1 ships a Docker backend. Future backends (Podman, Apple `container`, Firecracker, remote-SSH) can implement the same interface without changing the daemon, API, or CLI.
Index ¶
- type BindMount
- type ContainerStatus
- type CreateRequest
- type Docker
- func (d *Docker) BridgeGateway(ctx context.Context) (netip.Addr, error)
- func (d *Docker) BuildImage(ctx context.Context, contextDir, dockerfile, tag string, ...) (io.ReadCloser, error)
- func (d *Docker) ContainerMounts(ctx context.Context, name string) ([]string, error)
- func (d *Docker) ContainerReapsOrphans(ctx context.Context, name string) (bool, error)
- func (d *Docker) CopyFromContainer(ctx context.Context, name, containerPath, hostPath string) error
- func (d *Docker) CopyToContainer(ctx context.Context, name, hostPath, containerPath string) error
- func (d *Docker) CopyVolumeData(ctx context.Context, src, dst, image string) error
- func (d *Docker) CreateContainer(ctx context.Context, req CreateRequest) (string, error)
- func (d *Docker) DaemonReachable(ctx context.Context) bool
- func (d *Docker) DialContainerPort(ctx context.Context, name, host string, port int) (net.Conn, error)
- func (d *Docker) EnsureDaemon(ctx context.Context, log *slog.Logger) error
- func (d *Docker) EnsureNetwork(ctx context.Context, name string) error
- func (d *Docker) EnsureVolume(ctx context.Context, name string) error
- func (d *Docker) Exec(ctx context.Context, name string, cmd []string) (string, string, int, error)
- func (d *Docker) ExecStream(ctx context.Context, name string, cmd []string) (io.ReadCloser, error)
- func (d *Docker) ImageExists(ctx context.Context, image string) (bool, error)
- func (d *Docker) Inspect(ctx context.Context, name string) (Health, error)
- func (d *Docker) Logs(ctx context.Context, name string, follow bool) (io.ReadCloser, error)
- func (d *Docker) RemoveContainer(ctx context.Context, name string, force bool) error
- func (d *Docker) RemoveNetwork(ctx context.Context, name string) error
- func (d *Docker) RemoveVolume(ctx context.Context, name string, force bool) error
- func (d *Docker) StartContainer(ctx context.Context, name string) error
- func (d *Docker) Stats(ctx context.Context, name string) (Stats, error)
- func (d *Docker) StatsAll(ctx context.Context) (map[string]Stats, error)
- func (d *Docker) Status(ctx context.Context, name string) (ContainerStatus, error)
- func (d *Docker) StopContainer(ctx context.Context, name string) error
- func (d *Docker) UpdateResources(ctx context.Context, name, memory string) error
- func (d *Docker) VolumeSizes(ctx context.Context) (map[string]int64, error)
- type Health
- type Runtime
- type Stats
- type VolumeMount
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ContainerStatus ¶
type ContainerStatus string
ContainerStatus is a coarse-grained state from the runtime's perspective.
const ( StatusMissing ContainerStatus = "missing" StatusCreated ContainerStatus = "created" StatusRunning ContainerStatus = "running" StatusStopped ContainerStatus = "stopped" StatusExited ContainerStatus = "exited" StatusErrored ContainerStatus = "errored" )
type CreateRequest ¶
type CreateRequest struct {
Name string
Image string
Env map[string]string
Volumes []VolumeMount // named volumes
BindMounts []BindMount // host path → container path (read-only by default in M1)
Command []string // override entrypoint command (optional)
Labels map[string]string
Memory string // e.g. "4G" → --memory
CPUs string // e.g. "2.0" → --cpus
StorageSize string // e.g. "20G" → --storage-opt size=
// OOMScoreAdj biases the kernel OOM killer (−1000…+1000, higher = killed
// first) → --oom-score-adj. nil = don't pass the flag (kernel default).
OOMScoreAdj *int
Network string // user-defined bridge network name (empty = default)
// ExtraHosts are "host:ip" entries added with --add-host. Used to give the
// container a route to the daemon's host-internal listener (the in-island
// autonomy/telemetry path), e.g. "host.docker.internal:host-gateway".
ExtraHosts []string
}
CreateRequest describes a container to be created.
type Docker ¶
type Docker struct {
// Bin is the docker binary. Defaults to "docker".
Bin string
}
Docker shells out to the `docker` CLI. It is intentionally simple: no SDK dependency, easy to debug, easy to swap with `podman` by overriding Bin.
func NewDocker ¶
func NewDocker() *Docker
NewDocker returns a Docker runtime backed by the `docker` CLI.
func (*Docker) BridgeGateway ¶ added in v0.8.95
Reaching the HOST from inside an island.
The daemon runs two host-internal listeners islands need — the token- authenticated autonomy API and the egress proxy — and containers reach them by name: every island gets `--add-host host.docker.internal:host-gateway`.
THAT NAME RESOLVES TO THE BRIDGE GATEWAY, NOT TO THE HOST'S LOOPBACK, and the difference is invisible on the machines we develop on. Docker Desktop and colima run the engine in a VM and special-case host.docker.internal to reach the host's loopback through it. A NATIVE ENGINE — plain dockerd on Linux, which is what get.docker.com installs — has no VM and no indirection: the name is the bridge gateway, and a listener bound to 127.0.0.1 is not there.
So both listeners were unreachable from every island on every native engine. The DNS half was made engine-agnostic and the BIND half was not.
BridgeGateway asks the engine what that address actually is, so the daemon can listen there as well as on loopback. Not INSTEAD of loopback: a bind that guesses which kind of engine it is on is wrong in one direction or the other, and both listeners are still specific host-internal addresses, never a wildcard.
func (*Docker) BuildImage ¶
func (d *Docker) BuildImage(ctx context.Context, contextDir, dockerfile, tag string, buildArgs map[string]string) (io.ReadCloser, error)
BuildImage builds tag from contextDir using dockerfile (a path relative to contextDir). The returned stream carries combined build output; when the build fails the stream's final Read returns the build error instead of EOF (via CloseWithError), so callers distinguish success from failure without a side channel.
func (*Docker) ContainerMounts ¶ added in v0.8.66
ContainerMounts lists the destinations currently mounted into the container. An error is returned (not an empty list) when the container can't be inspected, so a caller can tell "not mounted" from "didn't find out".
func (*Docker) ContainerReapsOrphans ¶ added in v0.8.69
ContainerReapsOrphans reports whether this container runs an init as PID 1. An error is returned (not false) when the container can't be inspected, so a caller can tell "no reaper" from "didn't find out".
func (*Docker) CopyFromContainer ¶
func (*Docker) CopyToContainer ¶
func (*Docker) CopyVolumeData ¶
CopyVolumeData copies the contents of src into dst via a throwaway container that mounts both volumes (src read-only) and runs `cp -a`. image must provide a POSIX sh + cp (the island image does). Used by island clone.
func (*Docker) CreateContainer ¶
func (*Docker) DaemonReachable ¶
DaemonReachable reports whether the container runtime's server is up and answering. It shells out to `docker version` and checks for a server build.
func (*Docker) DialContainerPort ¶ added in v0.8.71
func (d *Docker) DialContainerPort(ctx context.Context, name, host string, port int) (net.Conn, error)
DialContainerPort opens a connection to host:port inside the named container.
The returned Conn owns a `docker exec` subprocess and kills it on Close. Deadlines work (it is a net.Pipe end, not a raw os.Pipe), which http.Transport and the websocket client both require.
func (*Docker) EnsureDaemon ¶
EnsureDaemon makes the container runtime ready: if `docker version` already reaches a server it returns immediately, otherwise it starts a local runtime (colima / Docker Desktop / OrbStack / systemd docker) when one is installed and polls until the daemon answers. This is what lets dejimad be the single thing a host operator starts — the VM/runtime becomes dejimad's private dependency rather than something the user babysits.
Best-effort by contract: the caller logs and continues on error so the API (doctor, status) still serves and the runtime can come up later.
func (*Docker) EnsureNetwork ¶
func (*Docker) ExecStream ¶
ExecStream runs a command inside a container and streams its combined output. Modeled on Logs: the command's stdout/stderr feed an io.Pipe the caller reads.
func (*Docker) ImageExists ¶
func (*Docker) RemoveContainer ¶
func (*Docker) RemoveNetwork ¶
func (*Docker) RemoveVolume ¶
func (*Docker) StartContainer ¶
func (*Docker) StopContainer ¶
func (*Docker) UpdateResources ¶
UpdateResources applies a live memory-limit change via `docker update`. Empty memory is a no-op (nothing to change). oom-score-adj has no live equivalent — callers recreate the container to apply a priority change.
func (*Docker) VolumeSizes ¶
VolumeSizes returns each volume's on-disk size in bytes via a single `docker system df -v` query. Best-effort: returns nil on error, and 0 for any volume whose size the storage driver doesn't report (shows as "N/A").
type Health ¶
type Health struct {
OOMKilled bool // last run was killed by the OOM killer (hit its memory cap)
RestartCount int // cumulative restarts under the restart policy
ExitCode int // last exit code (0 if running or never exited)
}
Health holds crash-relevant facts from a container inspect. These can't be derived by a remote client (they require engine access), so the daemon surfaces them for monitoring/dashboards.
type Runtime ¶
type Runtime interface {
// EnsureVolume creates a volume if it doesn't exist. Idempotent.
EnsureVolume(ctx context.Context, name string) error
// RemoveVolume deletes a volume. Errors if missing unless force=true.
RemoveVolume(ctx context.Context, name string, force bool) error
// CopyVolumeData copies the contents of volume src into volume dst (via a
// throwaway container running `cp -a`, src mounted read-only). image must
// provide sh + cp. Used to clone an island's workspace and home volumes.
CopyVolumeData(ctx context.Context, src, dst, image string) error
// EnsureNetwork creates a user-defined bridge network if it doesn't exist.
// Idempotent. The network isolates containers from other networks while
// retaining outbound internet access via Docker's NAT.
EnsureNetwork(ctx context.Context, name string) error
// RemoveNetwork deletes a network. Tolerates missing.
RemoveNetwork(ctx context.Context, name string) error
// Stats returns the container's current resource usage. Returns zero-valued
// stats if the container is not running or stats are unavailable.
Stats(ctx context.Context, name string) (Stats, error)
// StatsAll returns current resource usage for every running container in
// one engine query, keyed by container name. One `docker stats` sampling
// interval (~2s) covers any number of containers — callers serving lists
// must use this instead of per-container Stats calls.
StatsAll(ctx context.Context) (map[string]Stats, error)
// VolumeSizes returns the on-disk size in bytes of every volume in one
// engine query, keyed by volume name. Slower than StatsAll and reads 0 on
// storage drivers that don't report volume size, so callers should poll it
// sparingly and treat 0 as "unknown".
VolumeSizes(ctx context.Context) (map[string]int64, error)
// CreateContainer creates and starts a container. Returns the container ID.
CreateContainer(ctx context.Context, req CreateRequest) (string, error)
// UpdateResources applies resource changes to a running container without
// recreating it. Currently the memory limit ("" = leave unchanged), which
// `docker update` supports live. (OOM-score-adj has no live update — it's
// set at create, so a priority change needs a recreate.)
UpdateResources(ctx context.Context, name, memory string) error
// StopContainer gracefully stops a running container.
StopContainer(ctx context.Context, name string) error
// StartContainer starts a stopped container.
StartContainer(ctx context.Context, name string) error
// RemoveContainer removes a container (must be stopped unless force=true).
RemoveContainer(ctx context.Context, name string, force bool) error
// Status returns the container's current status.
Status(ctx context.Context, name string) (ContainerStatus, error)
// ContainerMounts returns the container paths currently mounted into the
// named container (bind mounts and volumes alike, by destination).
//
// Unlike Inspect, a failure here is deliberately NOT swallowed into a zero
// value. Callers use this to answer "is this credential actually mounted",
// and an empty list is the answer "nothing is mounted" — a very different
// statement from "I could not look". Collapsing the second into the first is
// how a surface comes to report containment it never verified.
ContainerMounts(ctx context.Context, name string) ([]string, error)
// ContainerReapsOrphans reports whether the container was created with an
// init process as PID 1 — the thing that reaps a process whose parent exited
// before it did.
//
// This is a create-time property and cannot be changed on a running
// container, so an island created before --init was passed keeps leaking
// zombies for its whole life while the daemon's code says it passes --init.
// That divergence is invisible from anywhere except the container itself,
// which is why it is asked of the runtime rather than inferred from the
// record.
//
// Like ContainerMounts and unlike Inspect, a failure is returned rather than
// flattened to false: "no init" and "couldn't look" are different answers and
// only one of them is a problem to report.
ContainerReapsOrphans(ctx context.Context, name string) (bool, error)
// DialContainerPort opens a connection to host:port INSIDE the named
// container. A framework gateway binds the container's loopback, which is
// unreachable from the host by any ordinary dial — not 127.0.0.1 (that is the
// host's own), and not the bridge address (nothing is bound there).
//
// ctx bounds the dial, not the connection: an http.Transport pools a conn past
// the request that opened it, and a websocket outlives every request context.
DialContainerPort(ctx context.Context, name, host string, port int) (net.Conn, error)
// Inspect returns crash-relevant health facts (OOM, restarts, exit code).
// Returns a zero Health if the container is missing or unavailable.
Inspect(ctx context.Context, name string) (Health, error)
// Exec runs a command inside a running container, returning stdout/stderr and exit code.
Exec(ctx context.Context, name string, cmd []string) (stdout, stderr string, exitCode int, err error)
// ExecStream runs a command inside a running container and streams its
// combined stdout/stderr until the command exits or ctx is canceled. Used
// for following a per-agent log file (`tail -f`).
ExecStream(ctx context.Context, name string, cmd []string) (io.ReadCloser, error)
// ImageExists reports whether the runtime has the named image locally.
ImageExists(ctx context.Context, image string) (bool, error)
// BuildImage builds tag from the build context at contextDir (dockerfile
// is relative to it), streaming combined build output. A failed build
// surfaces as a non-EOF error from the stream's final Read.
//
// buildArgs (may be nil) become --build-arg flags. They are not merely
// configuration: an ARG whose value changes invalidates the layer that
// consumes it, which is the only thing that makes a rebuild pick up new
// content for a step whose inputs the Dockerfile resolves at build time.
BuildImage(ctx context.Context, contextDir, dockerfile, tag string, buildArgs map[string]string) (io.ReadCloser, error)
// CopyToContainer copies a file or directory from host to container path.
CopyToContainer(ctx context.Context, name, hostPath, containerPath string) error
// CopyFromContainer copies a file or directory from container to host path.
CopyFromContainer(ctx context.Context, name, containerPath, hostPath string) error
// Logs returns the container's accumulated stdout/stderr. If follow is true,
// the reader streams new output until ctx is canceled.
Logs(ctx context.Context, name string, follow bool) (io.ReadCloser, error)
}
Runtime is the backend abstraction over a container engine.
type VolumeMount ¶
VolumeMount represents a named-volume mount.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package runtimetest provides a reusable in-memory runtime.Runtime fake for tests that need a real api.Server without a Docker engine — e.g.
|
Package runtimetest provides a reusable in-memory runtime.Runtime fake for tests that need a real api.Server without a Docker engine — e.g. |