Documentation
¶
Overview ¶
Package docker provides a thin Docker Engine API client.
Supported endpoints:
- Unix socket: "/var/run/docker.sock" (Linux / macOS default)
- Named pipe: "npipe:////./pipe/docker_engine" (Windows default)
- TCP: "tcp://host:port" (DinD sidecars, all platforms)
This avoids pulling in the massive github.com/docker/docker SDK with its transitive dependencies (otel, protobuf, etc.). We only need a handful of API calls: create/start/stop/remove container, pull image, create/inspect network. The Docker Engine API is stable REST over a Unix socket or TCP.
Reference: https://docs.docker.com/engine/api/v1.45/
Index ¶
- Constants
- func EndpointAliases(addresses ...string) []string
- func IsConflict(err error) bool
- func IsNotFound(err error) bool
- func ManagedLabels(service, resourceID string) map[string]string
- type Client
- func (d *Client) Available(timeout time.Duration) bool
- func (d *Client) ConnectNetwork(ctx context.Context, networkID, containerID string) error
- func (d *Client) ConnectNetworkWithAliases(ctx context.Context, networkID, containerID string, aliases []string) error
- func (d *Client) ContainerLogs(ctx context.Context, id string, tail string) ([]byte, error)
- func (d *Client) ContainerLogsSince(ctx context.Context, id string, since time.Time) (io.ReadCloser, error)
- func (d *Client) ContainerLogsStream(ctx context.Context, id string, since time.Time) (io.ReadCloser, error)
- func (d *Client) ContainerMemoryUsage(ctx context.Context, id string) (usageBytes int64, err error)
- func (d *Client) CopyFileFromContainer(ctx context.Context, id, path string) ([]byte, error)
- func (d *Client) CopyToContainer(ctx context.Context, id, destPath string, tarData io.Reader) error
- func (d *Client) CreateContainer(ctx context.Context, name string, req *CreateContainerRequest) (string, error)
- func (d *Client) CreateNetwork(ctx context.Context, name string) (string, error)
- func (d *Client) CreateNetworkWithOptions(ctx context.Context, opts CreateNetworkOptions) (string, error)
- func (d *Client) DisconnectNetwork(ctx context.Context, networkID, containerID string) error
- func (d *Client) GetContainerByName(ctx context.Context, name string) (*ContainerInspect, error)
- func (d *Client) ImageExists(ctx context.Context, image string) (bool, error)
- func (d *Client) ImageMatchesPlatform(ctx context.Context, image, platform string) (bool, error)
- func (d *Client) InspectContainer(ctx context.Context, id string) (*ContainerInspect, error)
- func (d *Client) InspectNetwork(ctx context.Context, nameOrID string) (*NetworkInspect, error)
- func (d *Client) ListContainers(ctx context.Context, service string) ([]ContainerSummary, error)
- func (d *Client) ListNetworks(ctx context.Context, service string) ([]NetworkSummary, error)
- func (d *Client) Ping(ctx context.Context) error
- func (d *Client) PruneDanglingImages(ctx context.Context) error
- func (d *Client) PullImage(ctx context.Context, image string) error
- func (d *Client) PullImageForPlatform(ctx context.Context, image, platform string) error
- func (d *Client) RemoveContainer(ctx context.Context, id string, force bool) error
- func (d *Client) RemoveContainerForce(id string) error
- func (d *Client) RemoveNetwork(ctx context.Context, nameOrID string) error
- func (d *Client) StartContainer(ctx context.Context, id string) error
- func (d *Client) StopContainer(ctx context.Context, id string, timeoutSec int) error
- func (d *Client) UpdateContainerResources(ctx context.Context, id string, update *UpdateResourcesRequest) error
- func (d *Client) WaitContainer(ctx context.Context, id string) (int, error)
- type ContainerConfig
- type ContainerInspect
- type ContainerSummary
- type CreateContainerRequest
- type CreateContainerResponse
- type CreateNetworkOptions
- type EndpointSettings
- type GC
- type HostConfig
- type ImageInspect
- type ImagePuller
- type NetworkIPAM
- type NetworkIPAMConfig
- type NetworkInspect
- type NetworkSummary
- type NetworkingConfig
- type PortBinding
- type ProbeResult
- type ServiceConfig
- type ServiceResult
- type Supervisor
- type UpdateResourcesRequest
- type Watcher
Constants ¶
const ( // LabelManaged marks a resource as Overcast-managed. LabelManaged = "overcast.managed" // LabelService identifies which Overcast service owns the resource // (e.g. "lambda", "ecs", "rds", "ec2"). LabelService = "overcast.service" // LabelResourceID identifies the logical resource that owns the // Docker resource (e.g. function name, ECS task ID, VPC ID). LabelResourceID = "overcast.resource-id" )
Standard labels applied by Overcast services to Docker resources (containers and networks). The Docker watcher filters on LabelManaged so it only sees our resources.
Variables ¶
This section is empty.
Functions ¶
func EndpointAliases ¶
EndpointAliases returns unique, non-IP hostnames suitable for Docker DNS aliases.
func IsConflict ¶
IsConflict reports whether an error is a Docker 409 Conflict response (e.g. container name already in use).
func IsNotFound ¶
IsNotFound reports whether an error is a Docker 404 Not Found response.
func ManagedLabels ¶
ManagedLabels returns the standard Overcast labels for a Docker resource. All services should use this instead of constructing the map inline.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a lightweight Docker Engine API client.
func NewClient ¶
NewClient creates a Docker client for the given endpoint.
The endpoint can be:
- A Unix socket path: "/var/run/docker.sock" (Linux / macOS)
- A Windows named pipe: "npipe:////./pipe/docker_engine" (Windows)
- A TCP address: "tcp://host:port" (for DinD sidecars, all platforms)
Use the package-level defaultDockerSocket constant for the platform default.
func (*Client) ConnectNetwork ¶
ConnectNetwork attaches a container to a network.
func (*Client) ConnectNetworkWithAliases ¶
func (d *Client) ConnectNetworkWithAliases(ctx context.Context, networkID, containerID string, aliases []string) error
ConnectNetworkWithAliases attaches a container to a network with optional DNS aliases.
func (*Client) ContainerLogs ¶
ContainerLogs fetches container stdout+stderr logs (non-streaming).
func (*Client) ContainerLogsSince ¶
func (d *Client) ContainerLogsSince(ctx context.Context, id string, since time.Time) (io.ReadCloser, error)
ContainerLogsSince fetches the full stdout+stderr log payload for a container starting from a given Unix timestamp (seconds). Used for reconciliation — after a streaming follower fails or on container teardown — to backfill any log frames that the streaming connection may have missed. Output includes per-line RFC3339Nano timestamps (timestamps=true) so the caller can deduplicate against events already delivered.
The response is a multiplexed Docker log stream identical in shape to ContainerLogsStream's body; pass it through dockerLogStripper to extract payload bytes.
func (*Client) ContainerLogsStream ¶
func (d *Client) ContainerLogsStream(ctx context.Context, id string, since time.Time) (io.ReadCloser, error)
ContainerLogsStream opens a streaming connection to the container log endpoint with follow=true. The caller is responsible for closing the returned ReadCloser. When ctx is cancelled the underlying HTTP connection is closed automatically, which causes reads on the stream to return an error, making the reader goroutine exit cleanly without an explicit close call.
The since parameter (Unix seconds with nanosecond fraction) lets a caller resume after a stream failure without re-receiving lines that were already delivered. Pass time.Time{} for "from start of container".
func (*Client) ContainerMemoryUsage ¶
ContainerMemoryUsage returns the current memory usage (in bytes) of a container. Uses the one-shot stats endpoint (stream=false) so it returns immediately.
func (*Client) CopyFileFromContainer ¶
CopyFileFromContainer returns the raw bytes of a file path from inside a container using Docker's archive endpoint.
func (*Client) CopyToContainer ¶
CopyToContainer copies a tar archive into a container at the given path. This uses the Docker "Put Archive" API endpoint.
func (*Client) CreateContainer ¶
func (d *Client) CreateContainer(ctx context.Context, name string, req *CreateContainerRequest) (string, error)
CreateContainer creates a container (does not start it).
func (*Client) CreateNetwork ¶
CreateNetwork creates a Docker network. Returns the network ID. Ignores "already exists" errors.
func (*Client) CreateNetworkWithOptions ¶
func (d *Client) CreateNetworkWithOptions(ctx context.Context, opts CreateNetworkOptions) (string, error)
CreateNetworkWithOptions creates a Docker network with full control over labels, CIDR, and internal mode. Returns the network ID. Ignores "already exists" errors.
func (*Client) DisconnectNetwork ¶
DisconnectNetwork detaches a container from a network.
func (*Client) GetContainerByName ¶
GetContainerByName looks up a container by its name (without the leading "/"). Returns (nil, nil) if no container with that name exists.
func (*Client) ImageExists ¶
ImageExists checks if an image exists locally.
func (*Client) ImageMatchesPlatform ¶
ImageMatchesPlatform reports whether the local image tag exists and matches the requested Docker platform. Empty platform preserves ImageExists behavior.
func (*Client) InspectContainer ¶
InspectContainer returns container details.
func (*Client) InspectNetwork ¶
InspectNetwork returns network details.
func (*Client) ListContainers ¶
ListContainers returns all containers (running and stopped) that carry overcast.managed=true and optionally overcast.service=<service>. Pass an empty service string to list across all services.
func (*Client) ListNetworks ¶
ListNetworks returns all Overcast-managed networks, optionally filtered by service.
func (*Client) PruneDanglingImages ¶
PruneDanglingImages removes all dangling (untagged) images. Equivalent to `docker image prune -f`. Safe to call after any pull or image retag — it only removes images that have no tag and are not referenced by a running container, so it cannot break in-use resources.
func (*Client) PullImageForPlatform ¶
PullImageForPlatform pulls an image for a specific Docker platform such as linux/amd64. Docker Engine expects platform in the images/create query string, not in a JSON body.
func (*Client) RemoveContainer ¶
RemoveContainer removes a container. force=true kills it first if running.
func (*Client) RemoveContainerForce ¶
RemoveContainerForce removes a container using a background context with a deadline, ensuring cleanup always succeeds even when the request context is cancelled. Use this for teardown/cleanup paths only.
func (*Client) RemoveNetwork ¶
RemoveNetwork removes a Docker network by name or ID.
func (*Client) StartContainer ¶
StartContainer starts a previously created container.
func (*Client) StopContainer ¶
StopContainer stops a running container with a timeout.
func (*Client) UpdateContainerResources ¶
func (d *Client) UpdateContainerResources(ctx context.Context, id string, update *UpdateResourcesRequest) error
UpdateContainerResources updates resource limits on a running container. Only the non-zero fields in the request are applied; zero values are ignored by the Docker daemon. Mirrors POST /containers/{id}/update.
type ContainerConfig ¶
type ContainerConfig struct {
Image string `json:"Image"`
Env []string `json:"Env,omitempty"`
Cmd []string `json:"Cmd,omitempty"`
Entrypoint []string `json:"Entrypoint,omitempty"`
WorkingDir string `json:"WorkingDir,omitempty"`
ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty"`
Labels map[string]string `json:"Labels,omitempty"`
}
ContainerConfig describes the container's runtime configuration.
type ContainerInspect ¶
type ContainerInspect struct {
ID string `json:"Id"`
Name string `json:"Name"` // e.g. "/overcast-rds-mydb"
Labels map[string]string `json:"Labels"`
Config struct {
Labels map[string]string `json:"Labels"`
} `json:"Config"`
State struct {
Status string `json:"Status"` // "created", "running", "exited", etc.
Running bool `json:"Running"`
ExitCode int `json:"ExitCode"`
Error string `json:"Error"` // runtime error, e.g. "OCI runtime create failed: ..."
OOMKilled bool `json:"OOMKilled"` // true if the kernel OOM-killer terminated the container
StartedAt string `json:"StartedAt"`
FinishedAt string `json:"FinishedAt"`
} `json:"State"`
HostConfig struct {
Binds []string `json:"Binds"`
} `json:"HostConfig"`
NetworkSettings struct {
Networks map[string]struct {
IPAddress string `json:"IPAddress"`
} `json:"Networks"`
// Ports maps "containerPort/proto" → list of host bindings.
// e.g. "3306/tcp" → [{"HostIp":"0.0.0.0","HostPort":"33060"}]
Ports map[string][]PortBinding `json:"Ports"`
} `json:"NetworkSettings"`
}
ContainerInspect holds container state and networking details.
func (*ContainerInspect) HasOvercastLabels ¶
func (c *ContainerInspect) HasOvercastLabels(service, resourceID string) bool
HasOvercastLabels reports whether the container was created by Overcast with the given service name and resource ID. Use this before reusing a container found by name to avoid accidentally attaching to a user-created container that happens to share the same name.
type ContainerSummary ¶
type ContainerSummary struct {
ID string `json:"Id"`
Names []string `json:"Names"` // e.g. ["/overcast-rds-mydb"]
Image string `json:"Image"`
State string `json:"State"` // "running", "exited", "created", etc.
Status string `json:"Status"` // human-readable, e.g. "Up 2 hours"
Labels map[string]string `json:"Labels"`
Ports []struct {
HostPort int `json:"PublicPort"`
ContainerPort int `json:"PrivatePort"`
Type string `json:"Type"`
} `json:"Ports"`
}
ContainerSummary is the lightweight container representation returned by GET /containers/json (list endpoint), as opposed to the full ContainerInspect returned by GET /containers/{id}/json.
func (*ContainerSummary) FirstName ¶
func (c *ContainerSummary) FirstName() string
FirstName returns the primary container name without the leading slash.
func (*ContainerSummary) ResourceID ¶
func (c *ContainerSummary) ResourceID() string
ResourceID returns the overcast.resource-id label value (empty string if not set).
func (*ContainerSummary) Service ¶
func (c *ContainerSummary) Service() string
Service returns the overcast.service label value (empty string if not set).
type CreateContainerRequest ¶
type CreateContainerRequest struct {
*ContainerConfig
HostConfig *HostConfig `json:"HostConfig,omitempty"`
NetworkingConfig *NetworkingConfig `json:"NetworkingConfig,omitempty"`
Platform string `json:"-"`
}
CreateContainerRequest combines all container creation parameters.
type CreateContainerResponse ¶
type CreateContainerResponse struct {
ID string `json:"Id"`
Warnings []string `json:"Warnings,omitempty"`
}
CreateContainerResponse is the response from container creation.
type CreateNetworkOptions ¶
type CreateNetworkOptions struct {
Name string
Labels map[string]string // nil = no labels
Subnet string // CIDR, e.g. "10.0.0.0/16"; empty = Docker default
Internal bool // true = no outbound internet access
}
CreateNetworkOptions configures a Docker network.
type EndpointSettings ¶
type EndpointSettings struct {
// Empty settings are enough to attach to a network. Aliases are advertised by
// Docker's embedded DNS to containers on the same user-defined network.
Aliases []string `json:"Aliases,omitempty"`
}
EndpointSettings describes a container's attachment to a Docker network.
type GC ¶
type GC struct {
// contains filtered or unexported fields
}
GC manages async Docker container cleanup. Services schedule containers for removal and the GC handles stop+remove in background goroutines:
- StopNow: fires immediately in a dedicated goroutine (non-blocking). A running container can still execute code — stop it ASAP.
- ScheduleRemove: enqueued and processed at leisure by the background loop. Failures are re-enqueued for retry (up to 3 attempts).
DrainAndSweep is called at shutdown: it drains the remove queue and then removes every managed container (Docker-level sweep), catching any orphans.
Zero value is invalid — use NewGC.
func NewGC ¶
NewGC creates a GC tied to a Docker client. keepContainers=true means containers are never removed — stop only (useful for debugging / post-mortem inspection).
func (*GC) DrainAndSweep ¶
DrainAndSweep shuts down the GC and removes every managed container for the given service. service="" matches all services. Blocks until complete or ctx expires during the drain phase.
Call from each service's Stop() method — this is the safety net that catches any container whose store record was already deleted but whose Docker container was never cleaned up.
Once DrainAndSweep returns the GC is inert; further StopNow / ScheduleRemove calls are no-ops.
func (*GC) ScheduleRemove ¶
ScheduleRemove enqueues a container for async removal. The background loop picks it up when it can — removal is not urgent once the container is stopped. Non-blocking. If the remove queue is full the request is dropped (logged).
func (*GC) StartRemoveLoop ¶
StartRemoveLoop begins the background remove worker. It blocks until ctx is cancelled or the GC is shut down. Safe to call multiple times — each call starts an independent worker goroutine tracked by the internal WaitGroup.
func (*GC) StopAndScheduleRemove ¶
StopAndScheduleRemove stops a container immediately (to halt any code running inside) and then queues it for deferred removal with exponential backoff. The stop fires in a dedicated goroutine so the caller can proceed without waiting for Docker to respond. The deferred removal retries indefinitely until the GC shuts down or the container is gone.
type HostConfig ¶
type HostConfig struct {
Binds []string `json:"Binds,omitempty"`
NetworkMode string `json:"NetworkMode,omitempty"`
Memory int64 `json:"Memory,omitempty"` // bytes
MemorySwap int64 `json:"MemorySwap,omitempty"` // bytes (-1 = unlimited)
NanoCPUs int64 `json:"NanoCPUs,omitempty"` // 1e9 = 1 CPU
AutoRemove bool `json:"AutoRemove,omitempty"`
PortBindings map[string][]PortBinding `json:"PortBindings,omitempty"`
Privileged bool `json:"Privileged,omitempty"` // required by k3s
Tmpfs map[string]string `json:"Tmpfs,omitempty"` // tmpfs mounts (path → options)
}
HostConfig describes the host-side container configuration.
type ImageInspect ¶
ImageInspect holds the platform metadata returned by Docker image inspect.
type ImagePuller ¶
type ImagePuller struct {
// contains filtered or unexported fields
}
ImagePuller deduplicates Docker image pulls. It ensures each image is pulled at most once per process lifetime. Services that run containers (RDS, ECS, Lambda) should share an ImagePuller rather than duplicating the sync.Map + sync.Once pattern.
func NewImagePuller ¶
func NewImagePuller(c *Client) *ImagePuller
NewImagePuller creates a puller backed by the given Docker client.
func (*ImagePuller) Ensure ¶
func (p *ImagePuller) Ensure(ctx context.Context, image string) error
Ensure pulls image if it hasn't been pulled yet. Concurrent calls for the same image block until the first pull completes. On error the entry is NOT cleared — callers get the cached error rather than hammering the registry.
func (*ImagePuller) Prewarm ¶
func (p *ImagePuller) Prewarm(image string)
Prewarm starts Ensure in a background goroutine using a detached context so the pull is not tied to any caller's request deadline. Safe to call from request handlers at resource-creation time (CreateFunction, RegisterTaskDefinition, CreateDBInstance). If the same image is requested again on the invoke path, the caller blocks on the same sync.Once and reuses the in-flight pull.
type NetworkIPAM ¶
type NetworkIPAM struct {
Config []NetworkIPAMConfig `json:"Config"`
}
NetworkIPAM describes IP address management for a Docker network.
type NetworkIPAMConfig ¶
NetworkIPAMConfig describes one IPAM pool.
type NetworkInspect ¶
type NetworkInspect struct {
ID string `json:"Id"`
Name string `json:"Name"`
Internal bool `json:"Internal"`
Labels map[string]string `json:"Labels"`
IPAM NetworkIPAM `json:"IPAM"`
}
NetworkInspect holds Docker network details.
type NetworkSummary ¶
type NetworkSummary struct {
ID string `json:"Id"`
Name string `json:"Name"`
Labels map[string]string `json:"Labels"`
IPAM NetworkIPAM `json:"IPAM"`
}
NetworkSummary is a lightweight network representation used by ListNetworks.
func (*NetworkSummary) ResourceID ¶
func (n *NetworkSummary) ResourceID() string
ResourceID returns the overcast.resource-id label value (empty string if not set).
func (*NetworkSummary) Service ¶
func (n *NetworkSummary) Service() string
Service returns the overcast.service label value (empty string if not set).
func (*NetworkSummary) Subnet ¶
func (n *NetworkSummary) Subnet() string
Subnet returns the first IPAM subnet for the network, or empty if unset.
type NetworkingConfig ¶
type NetworkingConfig struct {
EndpointsConfig map[string]*EndpointSettings `json:"EndpointsConfig,omitempty"`
}
NetworkingConfig specifies the container's networking configuration.
type PortBinding ¶
type PortBinding struct {
HostIP string `json:"HostIp,omitempty"`
HostPort string `json:"HostPort,omitempty"`
}
PortBinding represents a host-to-container port mapping.
type ProbeResult ¶
ProbeResult is returned by Probe on success.
func Probe ¶
func Probe(socketPath, network string, logger *zap.Logger) (*ProbeResult, error)
Probe creates a Docker client, verifies connectivity with retries, and ensures the named network exists. This is the common bootstrap pattern shared by Lambda, ECS, and RDS.
Returns nil with a logged warning (not an error) when Docker is unreachable — callers degrade gracefully (metadata ops work, container ops return errors).
type ServiceConfig ¶
type ServiceConfig struct {
// Name is used for logging ("rds", "ecs", "lambda").
Name string
// Socket is the Docker daemon socket path (e.g. /var/run/docker.sock).
Socket string
// Network is the Docker network to create for this service.
Network string
}
ServiceConfig describes a single service's Docker requirements. The Supervisor uses this to probe the socket, create the network, and wire the Docker client into the service.
type ServiceResult ¶
ServiceResult is returned per-service after a successful probe.
type Supervisor ¶
type Supervisor struct {
// contains filtered or unexported fields
}
Supervisor centralises Docker lifecycle management for the entire process. It deduplicates probes (one per unique socket path), creates per-service networks, runs a single event watcher per Docker daemon, and provides startup reconciliation.
Usage:
sup := docker.NewSupervisor(bus, logger)
results := sup.Probe(ctx, []ServiceConfig{...})
// wire results into services
sup.Run(ctx) // blocks — starts watchers; returns when ctx is done
sup.Close() // called during shutdown
func NewSupervisor ¶
func NewSupervisor(bus *events.Bus, logger *zap.Logger) *Supervisor
NewSupervisor creates a Supervisor that will publish Docker container events on the provided bus.
func (*Supervisor) Close ¶
func (s *Supervisor) Close()
Close signals all background goroutines (including Probe blockers and watchers) to stop. Safe to call before, during, or after Run.
func (*Supervisor) Probe ¶
func (s *Supervisor) Probe(ctx context.Context, configs []ServiceConfig) []ServiceResult
Probe probes Docker for each ServiceConfig. Configs sharing the same socket path reuse a single client connection and share a single availability probe. Each config gets its own network created. Returns one ServiceResult per successful config. Configs that fail to probe are logged and skipped.
func (*Supervisor) Run ¶
func (s *Supervisor) Run(ctx context.Context)
Run starts one Watcher goroutine per unique Docker client. It blocks until ctx is cancelled or Close is called. Call this from a goroutine after Probe.
type UpdateResourcesRequest ¶
type UpdateResourcesRequest struct {
NanoCPUs int64 `json:"NanoCPUs,omitempty"` // 1e9 = 1 CPU
Memory int64 `json:"Memory,omitempty"` // bytes
MemorySwap int64 `json:"MemorySwap,omitempty"` // bytes (-1 = unlimited)
}
UpdateResourcesRequest contains the resource fields that can be changed on a running container via the Docker Engine API POST /containers/{id}/update.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher listens to the Docker Engine events stream and publishes typed events on an events.Bus. Only Overcast-managed resources (those with the overcast.managed label) are tracked — both containers and networks.
Usage:
w := docker.NewWatcher(client, bus, logger) go w.Run(ctx) // blocks until ctx is cancelled
func NewWatcher ¶
NewWatcher creates a Watcher that translates Docker container and network events into bus events. Call Run to start watching.