Documentation
¶
Index ¶
- func ForListeningPort(port string) *waitForPort
- func WaitForAll(strategies ...WaitStrategy) *multiWait
- func WaitForFunc(fn func(ctx context.Context, target ContainerTarget) error) *waitFunc
- func WaitForHTTP(port, path string, expectedStatus int) *waitForHTTP
- func WaitForHealthy() *waitForHealthy
- func WaitForLog(pattern string) *waitForLog
- func WaitForPort(port string) *waitForPort
- type ContainerRequest
- type ContainerState
- type ContainerTarget
- type Executor
- func (e *Executor) Close() error
- func (e *Executor) ConnectionString(ctx context.Context, containerPort, template string) (string, error)
- func (e *Executor) ContainerID() string
- func (e *Executor) Endpoint(ctx context.Context, containerPort string) (string, error)
- func (e *Executor) ExitCode(ctx context.Context) (int, error)
- func (e *Executor) FollowLogs(ctx context.Context, w io.Writer, opts ...LogOption) error
- func (e *Executor) GetAllPorts(ctx context.Context) (map[string]string, error)
- func (e *Executor) GetIPAddress(ctx context.Context, network string) (string, error)
- func (e *Executor) GetLastNLines(ctx context.Context, n int) (string, error)
- func (e *Executor) GetLogsSince(ctx context.Context, since string) (string, error)
- func (e *Executor) GetNetworks(ctx context.Context) ([]string, error)
- func (e *Executor) GetStats(ctx context.Context) (container.StatsResponseReader, error)
- func (e *Executor) GetStderr(ctx context.Context) (string, error)
- func (e *Executor) GetStdout(ctx context.Context) (string, error)
- func (e *Executor) HealthCheck(ctx context.Context) (*HealthStatus, error)
- func (e *Executor) Host(_ context.Context) (string, error)
- func (e *Executor) Inspect(ctx context.Context) (*container.InspectResponse, error)
- func (e *Executor) IsRunning(ctx context.Context) (bool, error)
- func (e *Executor) Logs(ctx context.Context, opts ...LogOption) (string, error)
- func (e *Executor) MappedPort(ctx context.Context, containerPort string) (string, error)
- func (e *Executor) Restart(ctx context.Context) error
- func (e *Executor) Start(ctx context.Context) error
- func (e *Executor) Status(ctx context.Context) (*Status, error)
- func (e *Executor) Stop(ctx context.Context) error
- func (e *Executor) StreamLogs(ctx context.Context, opts ...LogOption) (<-chan LogEntry, <-chan error)
- func (e *Executor) Terminate(ctx context.Context) error
- func (e *Executor) Wait(ctx context.Context) (int64, error)
- func (e *Executor) WaitForState(ctx context.Context, targetState string, timeout time.Duration) error
- func (e *Executor) WaitHealthy(ctx context.Context, timeout time.Duration) error
- type HealthLog
- type HealthStatus
- type LogEntry
- type LogOption
- type Option
- func WithAutoRemove(autoRemove bool) Option
- func WithCapAdd(caps ...string) Option
- func WithCapDrop(caps ...string) Option
- func WithCmd(cmd ...string) Option
- func WithEntrypoint(entrypoint ...string) Option
- func WithEnv(env string) Option
- func WithEnvMap(env map[string]string) Option
- func WithExposedPorts(ports ...string) Option
- func WithHostname(hostname string) Option
- func WithImage(image string) Option
- func WithLabel(key, value string) Option
- func WithLabels(labels map[string]string) Option
- func WithName(name string) Option
- func WithNetwork(network string) Option
- func WithNetworkMode(mode string) Option
- func WithNetworks(networks ...string) Option
- func WithOTelConfig(otelConfig *otel.Config) Option
- func WithPortBindings(bindings map[string]string) Option
- func WithPorts(portMapping string) Option
- func WithPrivileged(privileged bool) Option
- func WithRequest(req ContainerRequest) Option
- func WithShmSize(size int64) Option
- func WithTimeout(timeout time.Duration) Option
- func WithTmpfs(path, options string) Option
- func WithUser(user string) Option
- func WithVolume(hostPath, containerPath string) Option
- func WithVolumeRO(hostPath, containerPath string) Option
- func WithVolumes(volumes map[string]string) Option
- func WithWaitStrategy(strategy WaitStrategy) Option
- func WithWorkDir(workDir string) Option
- type Status
- type WaitStrategy
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ForListeningPort ¶
func ForListeningPort(port string) *waitForPort
ForListeningPort is an alias for WaitForPort for testcontainers compatibility.
func WaitForAll ¶
func WaitForAll(strategies ...WaitStrategy) *multiWait
WaitForAll creates a wait strategy that waits for all strategies to pass.
func WaitForFunc ¶
func WaitForFunc(fn func(ctx context.Context, target ContainerTarget) error) *waitFunc
WaitForFunc creates a wait strategy from a custom function. This allows users to implement their own wait logic.
Example ¶
WaitForFunc wraps arbitrary readiness logic. The strategy receives a ContainerTarget exposing the container ID, a log stream, and a projected runtime state — no Docker client import required.
Output is non-deterministic; compile-checked only.
package main
import (
"context"
"fmt"
"time"
"github.com/jasoet/pkg/v3/docker"
)
func main() {
strategy := docker.WaitForFunc(func(ctx context.Context, target docker.ContainerTarget) error {
state, err := target.State(ctx)
if err != nil {
return err
}
if !state.Running {
return fmt.Errorf("container %s not running", target.ID())
}
return nil
}).WithStartupTimeout(30 * time.Second)
exec, err := docker.New(
docker.WithImage("redis:7-alpine"),
docker.WithWaitStrategy(strategy),
)
if err != nil {
fmt.Println("error:", err)
return
}
defer func() { _ = exec.Close() }()
}
Output:
func WaitForHTTP ¶
WaitForHTTP creates a wait strategy that waits for an HTTP endpoint. Port format: "8080" or "8080/tcp" Path: HTTP path (e.g., "/health") Expected status: HTTP status code (e.g., 200)
func WaitForHealthy ¶
func WaitForHealthy() *waitForHealthy
WaitForHealthy creates a wait strategy that waits for health check to pass. Container must have a HEALTHCHECK defined in Dockerfile or via Docker API.
func WaitForLog ¶
func WaitForLog(pattern string) *waitForLog
WaitForLog creates a wait strategy that waits for a log pattern. Pattern can be a simple string or regex pattern. If the pattern is invalid, WaitUntilReady will return an error instead of panicking.
Example ¶
WaitForLog creates a strategy that blocks Start until a line matching the pattern appears in the container logs. The pattern is a regular expression; plain strings work because they are valid regexes.
Output is non-deterministic; compile-checked only.
package main
import (
"context"
"fmt"
"time"
"github.com/jasoet/pkg/v3/docker"
)
func main() {
strategy := docker.WaitForLog("database system is ready to accept connections").
WithStartupTimeout(60 * time.Second)
exec, err := docker.New(
docker.WithImage("postgres:18-alpine"),
docker.WithEnvMap(map[string]string{
"POSTGRES_PASSWORD": "secret",
}),
docker.WithWaitStrategy(strategy),
)
if err != nil {
fmt.Println("error:", err)
return
}
defer func() { _ = exec.Close() }()
// Start blocks until the log pattern matches (requires a Docker daemon):
//
// ctx := context.Background()
// if err := exec.Start(ctx); err != nil { ... }
// defer exec.Terminate(ctx)
_ = context.Background()
}
Output:
func WaitForPort ¶
func WaitForPort(port string) *waitForPort
WaitForPort creates a wait strategy that waits for a port to be listening. Port format: "8080/tcp" or just "8080" (defaults to tcp).
Types ¶
type ContainerRequest ¶
type ContainerRequest struct {
// Image is the container image to use (e.g., "nginx:latest")
Image string
// Name is the container name (optional)
Name string
// Hostname sets the container hostname
Hostname string
// ExposedPorts are ports to expose (e.g., []string{"80/tcp", "443/tcp"})
ExposedPorts []string
// Env is a map of environment variables
Env map[string]string
// Cmd overrides the default command
Cmd []string
// Entrypoint overrides the default entrypoint
Entrypoint []string
// WorkingDir sets the working directory
WorkingDir string
// User sets the user (e.g., "1000:1000" or "username")
User string
// Labels are container labels
Labels map[string]string
// Volumes maps host paths to container paths
// Key: host path, Value: container path
Volumes map[string]string
// BindMounts allows raw Docker bind mount specs. Use with caution: callers are responsible for
// ensuring mount paths do not expose sensitive host directories.
// Key: container path, Value: bind mount spec
BindMounts map[string]string
// Networks to attach the container to
Networks []string
// NetworkMode sets the network mode (bridge, host, none, container:<name>)
NetworkMode string
// PortBindings maps container ports to host ports
// Key: container port (e.g., "80/tcp"), Value: host port (e.g., "8080")
PortBindings map[string]string
// AutoRemove automatically removes the container when it stops
AutoRemove bool
// Privileged runs the container in privileged mode
Privileged bool
// CapAdd adds Linux capabilities
CapAdd []string
// CapDrop drops Linux capabilities
CapDrop []string
// Tmpfs mounts tmpfs filesystems
// Key: container path, Value: options
Tmpfs map[string]string
// ShmSize sets the size of /dev/shm
ShmSize int64
// WaitingFor specifies the wait strategy for container readiness
WaitingFor WaitStrategy
// Timeout for container operations (default: 30s)
Timeout time.Duration
// OTelConfig enables OpenTelemetry instrumentation (optional)
OTelConfig *otel.Config `yaml:"-" mapstructure:"-"`
}
ContainerRequest represents a declarative container configuration, similar to testcontainers.ContainerRequest. This allows users to configure containers using a struct-based approach.
type ContainerState ¶
type ContainerState struct {
Running bool
HealthStatus string // "" when no healthcheck is defined
Ports map[string][]string // containerPort ("80/tcp") → hostPorts
}
ContainerState is a snapshot of a container's runtime state, projected from ContainerInspect into a library-owned type.
type ContainerTarget ¶
type ContainerTarget struct {
// contains filtered or unexported fields
}
ContainerTarget is the runtime surface a WaitStrategy can inspect. It wraps the Docker client and container ID internally so that strategies never need to import the docker client.
A ContainerTarget is only usable when constructed by the Executor (as passed to WaitStrategy.WaitUntilReady). The zero value holds a nil client and will panic on Logs and State.
func (ContainerTarget) Logs ¶
func (t ContainerTarget) Logs(ctx context.Context) (io.ReadCloser, error)
Logs streams the container's stdout and stderr (follow mode). The caller is responsible for closing the returned reader.
func (ContainerTarget) State ¶
func (t ContainerTarget) State(ctx context.Context) (ContainerState, error)
State inspects the container and projects the result into a ContainerState.
A nil inspect.State is treated as an error: it indicates an abnormal inspect response, and strategies polling for Running/HealthStatus would otherwise spin on a meaningless zero state until timeout. A nil NetworkSettings is tolerated (e.g., containers without networking) and yields an empty Ports map.
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor manages a Docker container lifecycle.
func New ¶
New creates a new Docker executor with functional options.
Example with functional options:
exec := docker.New(
docker.WithImage("nginx:latest"),
docker.WithPorts("80:8080"),
docker.WithEnv("KEY=value"),
)
Example with ContainerRequest struct:
req := docker.ContainerRequest{
Image: "nginx:latest",
ExposedPorts: []string{"80/tcp"},
Env: map[string]string{"KEY": "value"},
}
exec := docker.New(docker.WithRequest(req))
Example combining both:
req := docker.ContainerRequest{Image: "nginx:latest"}
exec := docker.New(
docker.WithRequest(req),
docker.WithOTelConfig(otelCfg), // Add observability
)
Example ¶
New assembles an executor from functional options. Constructing the executor only validates configuration and creates a Docker client handle; no container is started until Start is called.
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/docker"
)
func main() {
exec, err := docker.New(
docker.WithImage("nginx:latest"),
docker.WithPorts("80:0"), // host port auto-assigned
docker.WithEnv("ENV=production"),
docker.WithAutoRemove(true),
)
if err != nil {
fmt.Println("error:", err)
return
}
defer func() { _ = exec.Close() }()
fmt.Println("executor created, container started:", exec.ContainerID() != "")
}
Output: executor created, container started: false
func NewFromRequest ¶
func NewFromRequest(req ContainerRequest, opts ...Option) (*Executor, error)
NewFromRequest creates a new Docker executor from a ContainerRequest struct. Additional options can be passed to override or extend the request configuration.
Example with just struct:
req := docker.ContainerRequest{
Image: "nginx:latest",
Env: map[string]string{"KEY": "value"},
}
exec, err := docker.NewFromRequest(req)
Example with additional options (options override struct fields):
req := docker.ContainerRequest{
Image: "nginx:latest",
Name: "default-name",
}
exec, err := docker.NewFromRequest(req,
docker.WithName("override-name"), // Overrides struct name
docker.WithOTelConfig(otelCfg), // Adds observability
docker.WithPorts("80:8080"), // Adds port mapping
)
Example ¶
NewFromRequest is sugar over New(WithRequest(req), ...): it builds an executor from a ContainerRequest struct and lets trailing options override individual struct fields.
package main
import (
"fmt"
"time"
"github.com/jasoet/pkg/v3/docker"
)
func main() {
req := docker.ContainerRequest{
Image: "postgres:18-alpine",
ExposedPorts: []string{"5432/tcp"},
Env: map[string]string{
"POSTGRES_PASSWORD": "secret",
},
WaitingFor: docker.WaitForLog("ready to accept connections").
WithStartupTimeout(60 * time.Second),
}
// WithName overrides the (empty) struct field; options always win.
exec, err := docker.NewFromRequest(req, docker.WithName("my-postgres"))
if err != nil {
fmt.Println("error:", err)
return
}
defer func() { _ = exec.Close() }()
fmt.Println("executor created from request")
}
Output: executor created from request
func (*Executor) Close ¶
Close closes the Docker client connection. The container is NOT terminated automatically - call Terminate() first if needed. After Close(), any method that uses the Docker client will return an error.
func (*Executor) ConnectionString ¶
func (e *Executor) ConnectionString(ctx context.Context, containerPort, template string) (string, error)
ConnectionString builds a connection string for the container. This is useful for database containers. Use {{endpoint}} as the placeholder for the host:port value.
Example:
// For PostgreSQL
connStr, err := exec.ConnectionString(ctx, "5432/tcp", "postgres://user:pass@{{endpoint}}/db")
// Result: "postgres://user:pass@localhost:32768/db"
func (*Executor) ContainerID ¶
ContainerID returns the Docker container ID. Returns empty string if container hasn't been started yet.
func (*Executor) Endpoint ¶
Endpoint returns the full endpoint address (host:port) for a container port. This is a convenience method combining Host() and MappedPort().
Example:
endpoint, err := exec.Endpoint(ctx, "80/tcp")
// endpoint might be "localhost:32768"
// Use it directly with HTTP client
resp, err := http.Get("http://" + endpoint + "/health")
func (*Executor) ExitCode ¶
ExitCode retrieves the container exit code. Returns an error if the container hasn't exited yet.
func (*Executor) FollowLogs ¶
FollowLogs streams container logs to the provided writer. This is useful for piping logs to stdout or a file.
Example:
err := exec.FollowLogs(ctx, os.Stdout)
func (*Executor) GetAllPorts ¶
GetAllPorts returns all exposed ports and their mappings. Returns a map of container ports to host ports.
Example output:
{
"80/tcp": "8080",
"443/tcp": "8443",
}
func (*Executor) GetIPAddress ¶
GetIPAddress returns the container's IP address in a specific network. If network is empty, returns the IP from the first available network.
func (*Executor) GetLastNLines ¶
GetLastNLines retrieves the last N lines of logs.
func (*Executor) GetLogsSince ¶
GetLogsSince retrieves logs since a specific time. Time can be RFC3339 timestamp or duration string (e.g., "10m", "1h").
func (*Executor) GetNetworks ¶
GetNetworks returns all networks the container is connected to.
func (*Executor) GetStats ¶
GetStats retrieves container resource usage statistics. This includes CPU, memory, network, and disk I/O stats. Returns the stats response reader which can be read and decoded by the caller. Remember to close the response body after reading.
func (*Executor) HealthCheck ¶
func (e *Executor) HealthCheck(ctx context.Context) (*HealthStatus, error)
HealthCheck retrieves the current health status. Returns an error if health check is not configured for the container.
func (*Executor) Host ¶
Host returns the container host address. For local Docker, this is always "localhost" since containers use port forwarding.
func (*Executor) Inspect ¶
Inspect returns the full container inspection details. This provides access to all container metadata.
func (*Executor) Logs ¶
Logs returns all container logs as a string. Use LogOptions for more control.
func (*Executor) MappedPort ¶
MappedPort returns the host port mapped to a container port. Port format: "8080/tcp" or "8080" (defaults to tcp).
Example:
hostPort, err := exec.MappedPort(ctx, "80/tcp") // hostPort might be "32768" (randomly assigned by Docker)
func (*Executor) Restart ¶
Restart restarts the container. Note: There is a small TOCTOU window between the containerID check and the Docker API call. Concurrent Terminate() may cause a benign "container not found" error.
func (*Executor) Start ¶
Start pulls the image (if needed), creates and starts the container. If a wait strategy is configured, it blocks until the container is ready.
func (*Executor) Stop ¶
Stop gracefully stops the container (sends SIGTERM). The container can still be restarted after stopping. Note: There is a small TOCTOU window between the containerID check and the Docker API call. Concurrent Terminate() may cause a benign "container not found" error.
func (*Executor) StreamLogs ¶
func (e *Executor) StreamLogs(ctx context.Context, opts ...LogOption) (<-chan LogEntry, <-chan error)
StreamLogs streams container logs to a channel. The channel is closed when streaming completes or context is canceled. Docker multiplexed stream headers are parsed to correctly identify stdout vs stderr.
func (*Executor) Terminate ¶
Terminate forcefully stops and removes the container. This is a destructive operation and the container cannot be restarted.
type HealthLog ¶
type HealthLog struct {
// Start is when the check started
Start time.Time
// End is when the check completed
End time.Time
// ExitCode is the health check exit code
ExitCode int
// Output is the health check output
Output string
}
HealthLog represents a single health check result.
type HealthStatus ¶
type HealthStatus struct {
// Status is the health status (healthy, unhealthy, starting)
Status string
// FailingStreak is the number of consecutive failures
FailingStreak int
// Log contains recent health check results
Log []HealthLog
}
HealthStatus represents container health check status.
type LogEntry ¶
type LogEntry struct {
// Stream identifies the source (stdout or stderr)
Stream string
// Content is the log line content
Content string
}
LogEntry represents a single log entry from the container.
type LogOption ¶
type LogOption func(*logOptions)
LogOption is a functional option for log retrieval.
func WithFollow ¶
func WithFollow() LogOption
WithFollow streams logs in real-time (default: false).
func WithStderr ¶
WithStderr includes stderr in the logs (default: true).
func WithStdout ¶
WithStdout includes stdout in the logs (default: true).
func WithTail ¶
WithTail limits the number of lines from the end of the logs. Use "all" for all logs, or a number like "100" for last 100 lines.
func WithTimestamps ¶
func WithTimestamps() LogOption
WithTimestamps includes timestamps in log entries (default: false).
type Option ¶
type Option func(*config) error
Option is a functional option for configuring the executor.
func WithAutoRemove ¶
WithAutoRemove automatically removes the container when it stops.
func WithCapAdd ¶
WithCapAdd adds Linux capabilities to the container. WARNING: Adding capabilities increases the container's privileges. Only add capabilities that are strictly required.
func WithEntrypoint ¶
WithEntrypoint sets the container entrypoint.
func WithEnvMap ¶
WithEnvMap sets environment variables from a map.
func WithExposedPorts ¶
WithExposedPorts exposes ports without binding to host.
func WithHostname ¶
WithHostname sets the container hostname.
func WithLabels ¶
WithLabels sets multiple container labels.
func WithNetwork ¶
WithNetwork attaches the container to a network.
func WithNetworkMode ¶
WithNetworkMode sets the network mode (bridge, host, none, container:<name>).
func WithNetworks ¶
WithNetworks attaches the container to multiple networks.
func WithOTelConfig ¶
WithOTelConfig enables OpenTelemetry instrumentation.
func WithPortBindings ¶
WithPortBindings sets detailed port bindings. Key: container port with protocol (e.g., "80/tcp") Value: host port (e.g., "8080")
func WithPorts ¶
WithPorts adds port mappings in "containerPort:hostPort" format (e.g., "80:8080"). Protocol defaults to TCP. Use "80:8080/udp" for UDP.
func WithPrivileged ¶
WithPrivileged runs the container in privileged mode. WARNING: Privileged containers have full access to the host. Only use with trusted images.
func WithRequest ¶
func WithRequest(req ContainerRequest) Option
WithRequest creates an option from a ContainerRequest struct. This allows combining struct-based and functional options:
req := docker.ContainerRequest{Image: "nginx:latest", ...}
exec := docker.New(
docker.WithRequest(req),
docker.WithOTelConfig(otelCfg), // Additional options
)
func WithShmSize ¶
WithShmSize sets the size of /dev/shm in bytes.
func WithTimeout ¶
WithTimeout sets the timeout for container operations.
func WithVolume ¶
WithVolume mounts a volume. Format: "hostPath:containerPath" or "hostPath:containerPath:ro"
func WithVolumeRO ¶
WithVolumeRO mounts a read-only volume.
func WithVolumes ¶
WithVolumes sets multiple volume mounts.
func WithWaitStrategy ¶
func WithWaitStrategy(strategy WaitStrategy) Option
WithWaitStrategy sets the wait strategy for container readiness.
type Status ¶
type Status struct {
// ID is the container ID
ID string
// Name is the container name
Name string
// Image is the container image
Image string
// State is the container state (running, exited, etc.)
State string
// Status is the detailed status string
Status string
// Running indicates if the container is running
Running bool
// Paused indicates if the container is paused
Paused bool
// Restarting indicates if the container is restarting
Restarting bool
// ExitCode is the exit code (only valid if container has exited)
ExitCode int
// Error contains any error message from the container
Error string
// StartedAt is when the container started
StartedAt time.Time
// FinishedAt is when the container finished (only if stopped)
FinishedAt time.Time
// Health is the health check status (if configured)
Health *HealthStatus
}
Status represents the container status information.
type WaitStrategy ¶
type WaitStrategy interface {
// WaitUntilReady blocks until the container is ready or timeout occurs.
WaitUntilReady(ctx context.Context, target ContainerTarget) error
}
WaitStrategy defines how to wait for a container to be ready.