Documentation
¶
Overview ¶
Package container provides a runtime-agnostic container integration layer for Gopherstack. It supports Docker and Podman (any OCI-compatible runtime) via a single env var switch: CONTAINER_RUNTIME=docker|podman|auto.
The Runtime interface abstracts image management and container lifecycle operations (create/start/stop/remove), volume mounts, and a simple warm-container pool with configurable idle timeout.
Index ¶
- Constants
- Variables
- func BindHostFor(advertiseHost string) string
- func CreateAndStartRetry(ctx context.Context, rt Starter, prepare func() (Spec, error), release func()) (string, error)
- func IsPortConflict(err error) bool
- func ParsePortSpec(spec string) (netip.Addr, string, string, error)
- func PortSpec(bindHost, hostPort, containerPort string) string
- func ResolveOCIRuntime(ctx context.Context, rt Runtime, candidates ...string) (string, error)
- type APIClient
- type Config
- type DockerRuntime
- func (r *DockerRuntime) AcquireWarm(ctx context.Context, spec Spec) (*PooledContainer, error)
- func (r *DockerRuntime) Close() error
- func (r *DockerRuntime) ConnectNetwork(ctx context.Context, networkID, containerID string) error
- func (r *DockerRuntime) CreateAndStart(ctx context.Context, spec Spec) (string, error)
- func (r *DockerRuntime) CreateNetwork(ctx context.Context, name string) (string, error)
- func (r *DockerRuntime) Exec(ctx context.Context, containerID string, cmd []string) (ExecResult, error)
- func (r *DockerRuntime) ExecStream(ctx context.Context, containerID string, cmd []string, out io.Writer) (int, error)
- func (r *DockerRuntime) HasImage(ctx context.Context, imageRef string) (bool, error)
- func (r *DockerRuntime) OCIRuntimes(ctx context.Context) ([]string, error)
- func (r *DockerRuntime) Ping(ctx context.Context) error
- func (r *DockerRuntime) PullImage(ctx context.Context, imageRef string) error
- func (r *DockerRuntime) PullImageWithCredentials(ctx context.Context, imageRef, username, password string) error
- func (r *DockerRuntime) ReadLogs(ctx context.Context, containerID, tail string, follow bool, ...) error
- func (r *DockerRuntime) ReapIdleContainers(ctx context.Context)
- func (r *DockerRuntime) ReleaseContainer(containerID string) error
- func (r *DockerRuntime) RemoveNetwork(ctx context.Context, networkID string) error
- func (r *DockerRuntime) StartContainer(ctx context.Context, containerID string) error
- func (r *DockerRuntime) StartReaper(ctx context.Context, interval time.Duration)
- func (r *DockerRuntime) StopAndRemove(ctx context.Context, containerID string) error
- func (r *DockerRuntime) StopContainer(ctx context.Context, containerID string) error
- func (r *DockerRuntime) StreamLogs(ctx context.Context, containerID string, stdout, stderr io.Writer) error
- func (r *DockerRuntime) TagAndPush(ctx context.Context, source, target string) (string, error)
- func (r *DockerRuntime) WaitExit(ctx context.Context, containerID string) (int, error)
- type ExecAPIClient
- type ExecResult
- type ExecStreamAPIClient
- type ExitWaiter
- type ImagePusher
- type Injection
- type LogReader
- type LogStreamer
- type LogsAPIClient
- type NetworkAPIClient
- type NetworkRuntime
- type OCIRuntimeAPIClient
- type OCIRuntimeLister
- type PooledContainer
- type PushAPIClient
- type Runtime
- type RuntimeName
- type Spec
- type Starter
- type StreamExecer
- type WaitAPIClient
Constants ¶
const ( // EnvInjectDNS is a comma-separated DNS server list given to every spawned container. EnvInjectDNS = "GOPHERSTACK_CONTAINER_DNS" // EnvInjectCAFile is a host CA PEM mounted into every spawned container and exported as CA bundle vars. EnvInjectCAFile = "GOPHERSTACK_CONTAINER_CA_FILE" // InjectedCAPath is where the CA lands inside containers. InjectedCAPath = "/etc/gopherstack/ca.pem" )
const AllInterfacesHost = "0.0.0.0"
AllInterfacesHost binds a published port on every host interface.
const LoopbackHost = "127.0.0.1"
LoopbackHost is the default bind address for engine-published ports.
const PortRetries = 5
PortRetries bounds CreateAndStartRetry attempts.
Variables ¶
var ErrContainerNotFound = errors.New("container not found")
ErrContainerNotFound is returned when a requested container does not exist in the pool.
var ErrExecUnsupported = errors.New("container exec is not supported by this runtime client")
ErrExecUnsupported is returned by Exec when the underlying client cannot run commands in a container.
var ErrInvalidPort = errors.New("invalid port mapping")
ErrInvalidPort is returned when a Spec.Ports entry is not a valid [IP:]HOST:CONTAINER mapping.
var ErrLogsUnsupported = errors.New("container logs are not supported by this runtime client")
ErrLogsUnsupported is returned by StreamLogs when the underlying client cannot read container logs.
var ErrNetworkUnsupported = errors.New("container networks are not supported by this runtime client")
ErrNetworkUnsupported is returned when the underlying client cannot manage networks.
var ErrOCIRuntimeMissing = errors.New("OCI runtime is not registered with the container daemon")
ErrOCIRuntimeMissing is returned when a requested OCI runtime is not registered with the daemon.
var ErrOCIRuntimeUnverifiable = errors.New("cannot list the container daemon's OCI runtimes")
ErrOCIRuntimeUnverifiable is returned when the daemon's registered runtimes cannot be listed.
var ErrPoolExhausted = errors.New("container pool exhausted")
ErrPoolExhausted is returned when no warm container is available and the pool is full.
var ErrPushUnsupported = errors.New("image push is not supported by this runtime client")
ErrPushUnsupported is returned by TagAndPush when the underlying client cannot tag and push images.
ErrUnavailable is returned when the container runtime is not available on the host.
var ErrUnknownRuntime = errors.New("unknown container runtime")
ErrUnknownRuntime is returned when an unrecognised runtime name is provided.
var ErrWaitFailed = errors.New("container wait failed")
ErrWaitFailed wraps an error the daemon reported while waiting.
var ErrWaitUnsupported = errors.New("container wait is not supported by this runtime client")
ErrWaitUnsupported is returned by WaitExit when the underlying client cannot wait on a container.
Functions ¶
func BindHostFor ¶
BindHostFor picks the host IP to publish ports on: loopback unless the operator advertised a non-loopback host, in which case all interfaces.
func CreateAndStartRetry ¶
func CreateAndStartRetry( ctx context.Context, rt Starter, prepare func() (Spec, error), release func(), ) (string, error)
CreateAndStartRetry starts the spec returned by prepare. On a host-port bind conflict it calls release, then prepare again for fresh ports, up to PortRetries attempts. release is also not called on success; the caller owns the ports of the container it got back.
func IsPortConflict ¶
IsPortConflict reports whether err is a runtime host-port bind failure.
func ParsePortSpec ¶
ParsePortSpec splits "[IP:]HOST:CONTAINER"; an absent IP yields the IPv4 unspecified address.
Types ¶
type APIClient ¶
type APIClient interface {
ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error)
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
ContainerCreate(
ctx context.Context,
cfg *dockercontainer.Config,
hostConfig *dockercontainer.HostConfig,
networkingConfig any,
platform any,
containerName string,
) (dockercontainer.CreateResponse, error)
ContainerStart(ctx context.Context, containerID string, options dockercontainer.StartOptions) error
ContainerStop(ctx context.Context, containerID string, options dockercontainer.StopOptions) error
ContainerRemove(ctx context.Context, containerID string, options dockercontainer.RemoveOptions) error
Ping(ctx context.Context) (any, error)
Close() error
}
APIClient is a subset of the Docker/Podman SDK client interface used by DockerRuntime. It is defined as an interface to enable testing without a real container daemon.
type Config ¶
type Config struct {
Logger *slog.Logger
// Injection overrides the env-derived DNS/CA injection for spawned containers.
Injection *Injection
Runtime RuntimeName
PoolSize int
IdleTimeout time.Duration
}
Config holds configuration for the container runtime layer.
type DockerRuntime ¶
type DockerRuntime struct {
// contains filtered or unexported fields
}
DockerRuntime implements Runtime using the Docker daemon.
func NewDockerRuntimeWithAPI ¶
func NewDockerRuntimeWithAPI(api APIClient, cfg Config) *DockerRuntime
NewDockerRuntimeWithAPI creates a DockerRuntime with an injected APIClient. This is primarily intended for testing; production code should use NewRuntime.
func (*DockerRuntime) AcquireWarm ¶
func (r *DockerRuntime) AcquireWarm(ctx context.Context, spec Spec) (*PooledContainer, error)
AcquireWarm returns a warm container from the pool for the given image. If no warm container is available, a new one is created (up to PoolSize). The caller must call ReleaseContainer when done.
Note: PoolSize is a soft limit. When multiple goroutines call AcquireWarm concurrently, the pool may temporarily exceed PoolSize by the number of concurrent callers that see no idle container and concurrently create new ones.
func (*DockerRuntime) Close ¶
func (r *DockerRuntime) Close() error
Close releases resources held by the Docker client.
func (*DockerRuntime) ConnectNetwork ¶
func (r *DockerRuntime) ConnectNetwork(ctx context.Context, networkID, containerID string) error
ConnectNetwork attaches a running container to the network.
func (*DockerRuntime) CreateAndStart ¶
CreateAndStart creates a new container from spec and starts it. Returns the container ID.
func (*DockerRuntime) CreateNetwork ¶
CreateNetwork creates a bridge network and returns its ID.
func (*DockerRuntime) Exec ¶
func (r *DockerRuntime) Exec(ctx context.Context, containerID string, cmd []string) (ExecResult, error)
Exec runs cmd inside a running container and waits for it to finish.
func (*DockerRuntime) ExecStream ¶
func (r *DockerRuntime) ExecStream(ctx context.Context, containerID string, cmd []string, out io.Writer) (int, error)
ExecStream runs cmd like Exec but writes stdout and stderr to out as the command produces them.
func (*DockerRuntime) HasImage ¶
HasImage reports whether the given image reference is already present locally.
func (*DockerRuntime) OCIRuntimes ¶
func (r *DockerRuntime) OCIRuntimes(ctx context.Context) ([]string, error)
OCIRuntimes returns the OCI runtime names registered with the daemon.
func (*DockerRuntime) Ping ¶
func (r *DockerRuntime) Ping(ctx context.Context) error
Ping checks whether the Docker daemon is reachable.
func (*DockerRuntime) PullImage ¶
func (r *DockerRuntime) PullImage(ctx context.Context, imageRef string) error
PullImage pulls the specified image from the registry.
func (*DockerRuntime) PullImageWithCredentials ¶
func (r *DockerRuntime) PullImageWithCredentials(ctx context.Context, imageRef, username, password string) error
PullImageWithCredentials pulls imageRef authenticating to the registry as username/password.
func (*DockerRuntime) ReadLogs ¶
func (r *DockerRuntime) ReadLogs( ctx context.Context, containerID, tail string, follow bool, stdout, stderr io.Writer, ) error
ReadLogs reads the container's logs, demultiplexing stdout and stderr into the writers.
func (*DockerRuntime) ReapIdleContainers ¶
func (r *DockerRuntime) ReapIdleContainers(ctx context.Context)
ReapIdleContainers stops and removes containers that have been idle longer than IdleTimeout.
func (*DockerRuntime) ReleaseContainer ¶
func (r *DockerRuntime) ReleaseContainer(containerID string) error
ReleaseContainer marks a pooled container as idle. If the container is not in the pool, ErrContainerNotFound is returned.
func (*DockerRuntime) RemoveNetwork ¶
func (r *DockerRuntime) RemoveNetwork(ctx context.Context, networkID string) error
RemoveNetwork deletes the network.
func (*DockerRuntime) StartContainer ¶
func (r *DockerRuntime) StartContainer(ctx context.Context, containerID string) error
StartContainer starts a previously stopped container.
func (*DockerRuntime) StartReaper ¶
func (r *DockerRuntime) StartReaper(ctx context.Context, interval time.Duration)
StartReaper launches a background goroutine that periodically reaps idle containers. It stops when ctx is cancelled.
func (*DockerRuntime) StopAndRemove ¶
func (r *DockerRuntime) StopAndRemove(ctx context.Context, containerID string) error
StopAndRemove stops and removes a container.
func (*DockerRuntime) StopContainer ¶
func (r *DockerRuntime) StopContainer(ctx context.Context, containerID string) error
StopContainer stops a container without removing it, keeping its published ports and data.
func (*DockerRuntime) StreamLogs ¶
func (r *DockerRuntime) StreamLogs(ctx context.Context, containerID string, stdout, stderr io.Writer) error
StreamLogs follows the container's logs, demultiplexing stdout and stderr into the writers.
func (*DockerRuntime) TagAndPush ¶
TagAndPush tags the local image source as target and pushes it.
type ExecAPIClient ¶
type ExecAPIClient interface {
ContainerExec(
ctx context.Context,
containerID string,
cmd []string,
) (stdout, stderr []byte, exitCode int, err error)
}
ExecAPIClient is implemented by clients that can run commands inside a container.
type ExecResult ¶
type ExecResult struct {
// Stdout and Stderr hold the demultiplexed output streams.
Stdout string
Stderr string
// ExitCode is the command's exit status.
ExitCode int
}
ExecResult is the outcome of a command run inside a container.
type ExecStreamAPIClient ¶
type ExecStreamAPIClient interface {
ContainerExecStream(
ctx context.Context,
containerID string,
cmd []string,
stdout, stderr io.Writer,
) (int, error)
}
ExecStreamAPIClient is implemented by clients that can stream a command's output while it runs.
type ExitWaiter ¶
type ExitWaiter interface {
// WaitExit blocks until the container stops and returns its exit code.
WaitExit(ctx context.Context, containerID string) (int, error)
}
ExitWaiter is implemented by runtimes that can report a container's exit status.
type ImagePusher ¶
type ImagePusher interface {
// TagAndPush tags the local image source as target, pushes target, and returns the pushed digest when known.
TagAndPush(ctx context.Context, source, target string) (string, error)
}
ImagePusher is implemented by runtimes that can publish a local image to a registry.
type Injection ¶
Injection points spawned containers at the embedded DNS and trusts the gopherstack CA, so SDKs inside them reach real AWS endpoint names transparently.
func InjectionFromEnv ¶
func InjectionFromEnv() *Injection
InjectionFromEnv reads EnvInjectDNS and EnvInjectCAFile; nil when neither is set.
type LogReader ¶
type LogReader interface {
// ReadLogs writes the last tail lines (all when tail is empty) to the writers; follow keeps streaming.
ReadLogs(ctx context.Context, containerID, tail string, follow bool, stdout, stderr io.Writer) error
}
LogReader is implemented by runtimes that can read a container's recent logs, optionally following them.
type LogStreamer ¶
type LogStreamer interface {
// StreamLogs writes the container's stdout and stderr to the given writers as they are produced.
// It blocks until the container is removed or stops, or ctx ends.
StreamLogs(ctx context.Context, containerID string, stdout, stderr io.Writer) error
}
LogStreamer is implemented by runtimes that can follow a container's stdout and stderr.
type LogsAPIClient ¶
type LogsAPIClient interface {
ContainerLogs(ctx context.Context, containerID string, options dockercontainer.LogsOptions) (io.ReadCloser, error)
}
LogsAPIClient is implemented by clients that can read a container's logs.
type NetworkAPIClient ¶
type NetworkAPIClient interface {
NetworkCreate(ctx context.Context, name string) (string, error)
NetworkConnect(ctx context.Context, networkID, containerID string) error
NetworkRemove(ctx context.Context, networkID string) error
}
NetworkAPIClient is implemented by clients that can manage user-defined networks.
type NetworkRuntime ¶
type NetworkRuntime interface {
// CreateNetwork creates a bridge network and returns its ID.
CreateNetwork(ctx context.Context, name string) (string, error)
// ConnectNetwork attaches a running container to the network.
ConnectNetwork(ctx context.Context, networkID, containerID string) error
// RemoveNetwork deletes the network.
RemoveNetwork(ctx context.Context, networkID string) error
}
NetworkRuntime is implemented by runtimes that can manage user-defined container networks.
type OCIRuntimeAPIClient ¶
OCIRuntimeAPIClient is implemented by clients that can list the daemon's registered OCI runtimes.
type OCIRuntimeLister ¶
OCIRuntimeLister is implemented by runtimes that can list the daemon's registered OCI runtimes.
type PooledContainer ¶
type PooledContainer struct {
// LastUsed is the timestamp of the last time this container was used.
LastUsed time.Time
// ID is the container ID.
ID string
// Image is the image the container was started from.
Image string
// InUse indicates whether the container is currently handling an invocation.
InUse bool
}
PooledContainer tracks a container managed by the warm pool.
type PushAPIClient ¶
type PushAPIClient interface {
ImageTag(ctx context.Context, source, target string) error
ImagePush(ctx context.Context, ref string) (string, error)
}
PushAPIClient is implemented by clients that can tag and push images.
type Runtime ¶
type Runtime interface {
// Ping checks whether the container daemon is reachable.
Ping(ctx context.Context) error
// PullImage pulls the specified image from the registry.
PullImage(ctx context.Context, imageRef string) error
// HasImage reports whether the given image reference is already present locally.
HasImage(ctx context.Context, imageRef string) (bool, error)
// CreateAndStart creates a new container from spec and starts it.
// Returns the container ID.
CreateAndStart(ctx context.Context, spec Spec) (string, error)
// StopAndRemove stops and removes a container.
StopAndRemove(ctx context.Context, containerID string) error
// Exec runs cmd inside a running container and waits for it to finish.
// A non-zero exit status is reported in the result, not as an error.
Exec(ctx context.Context, containerID string, cmd []string) (ExecResult, error)
// AcquireWarm returns a warm container from the pool for the given image.
AcquireWarm(ctx context.Context, spec Spec) (*PooledContainer, error)
// ReleaseContainer marks a pooled container as idle.
ReleaseContainer(containerID string) error
// ReapIdleContainers stops and removes containers idle longer than IdleTimeout.
ReapIdleContainers(ctx context.Context)
// StartReaper launches a background goroutine that periodically reaps idle containers.
StartReaper(ctx context.Context, interval time.Duration)
// Close releases resources held by the runtime client.
Close() error
}
Runtime is the container-runtime abstraction used throughout Gopherstack. Both DockerRuntime and PodmanRuntime implement this interface.
func NewRuntime ¶
NewRuntime creates a Runtime using the configured (or auto-detected) container runtime.
The runtime is selected in the following order:
- cfg.Runtime (if non-empty)
- CONTAINER_RUNTIME environment variable
- Defaults to RuntimeDocker
RuntimeAuto probes the Docker socket first, then the Podman socket. Returns ErrUnavailable if the selected runtime is not reachable.
type RuntimeName ¶
type RuntimeName string
RuntimeName identifies which container runtime to use.
const ( // RuntimeDocker selects the Docker daemon. RuntimeDocker RuntimeName = "docker" // RuntimePodman selects the Podman daemon via its Docker-compatible socket. RuntimePodman RuntimeName = "podman" // RuntimeAuto auto-detects the available runtime by probing sockets. RuntimeAuto RuntimeName = "auto" )
type Spec ¶
type Spec struct {
Image string
Name string
Network string
// WorkingDir overrides the image's working directory; empty keeps it.
WorkingDir string
// User runs the container process as uid[:gid]; empty keeps the image's user.
User string
// GroupAdd lists supplementary group IDs for the container process.
GroupAdd []string
// OCIRuntime selects the daemon-registered OCI runtime (e.g. runsc); empty uses the daemon default.
OCIRuntime string
Env []string
Mounts []string
Cmd []string
Entrypoint []string
Ports []string
Tmpfs []string
Privileged bool
// MemoryBytes caps container memory; zero is unlimited.
MemoryBytes int64
// NanoCPUs caps CPU in billionths of a CPU; zero is unlimited.
NanoCPUs int64
}
Spec holds the specification for creating a container.
type StreamExecer ¶
type StreamExecer interface {
// ExecStream runs cmd, writing combined stdout and stderr to out as produced; it returns the exit status.
ExecStream(ctx context.Context, containerID string, cmd []string, out io.Writer) (int, error)
}
StreamExecer is implemented by runtimes that can stream a command's output while it runs.
type WaitAPIClient ¶
type WaitAPIClient interface {
ContainerWait(
ctx context.Context,
containerID string,
options dockercontainer.WaitOptions,
) dockercontainer.WaitResult
}
WaitAPIClient is implemented by clients that can wait for a container to stop.