dockerpool

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 11, 2025 License: MIT Imports: 13 Imported by: 0

README

dockerpool

A Go library for managing a pool of Docker containers with automatic replenishment, graceful shutdown, and concurrent operations control.

Features

  • Container pooling — pre-created containers ready for immediate use
  • Auto-refill — automatically maintains minimum idle containers
  • Graceful shutdown — waits for in-use containers before cleanup
  • Concurrent operations limit — prevents Docker daemon overload
  • Container sync — recovers existing containers on restart
  • Flexible configuration — customize pool size, images, labels, and more

Installation

go get github.com/bermanf/dockerpool

Quick Start

package main

import (
    "context"
    "fmt"
    "github.com/bermanf/dockerpool"
)

func main() {
    ctx := context.Background()

    // Create Docker client
    docker, err := dockerpool.NewDockerClient()
    if err != nil {
        panic(err)
    }
    defer docker.Close()

    // Setup network and pull image
    docker.EnsureNetwork(ctx, "my-network")
    docker.PullImage(ctx, "alpine:latest")
    // Set timeout for container cleanup on errors (default: 30s)
    docker.SetCleanupTimeout(1 * time.Second)

    // Create pool with default config
    pool, err := dockerpool.NewDockerPool(ctx, docker, "my-pool", "my-network", 
        dockerpool.DefaultDockerPoolConfig())
    if err != nil {
        panic(err)
    }
    defer pool.Shutdown(ctx)

    // Acquire container from pool
    container, err := pool.Acquire(ctx)
    if err != nil {
        panic(err)
    }

    // Execute command
    result, _ := container.Exec(ctx, []string{"echo", "Hello!"})
    fmt.Println(result.Stdout)

    // Return container to pool
    pool.Return(ctx, container)
}

Configuration

config := dockerpool.DockerPoolConfig{
    // Pool sizing
    MinIdle: 10,   // Minimum idle containers (default: 5)
    MaxIdle: 100,  // Maximum idle containers (default: 10)

    // Timing
    RefillInterval: 50 * time.Millisecond, // How often to check pool (default: 100ms)

    // Concurrency
    MaxConcurrentDockerOps: 20, // Parallel Docker operations (default: 10)

    // Container settings
    ContainerConfig: dockerpool.CreateContainerOptions{
        Config: &container.Config{
            Image: "python:3.11-alpine",
            Cmd:   []string{"sleep", "infinity"},
        },
    },

    // Custom labels
    Labels: map[string]string{
        "env": "production",
    },

    // Error handling
    OnError: func(err error) {
        log.Printf("Pool error: %v", err)
    },
}

pool, err := dockerpool.NewDockerPool(ctx, docker, "my-pool", "network", config)

Command Execution

Simple execution
result, err := container.Exec(ctx, []string{"ls", "-la"})
// result.Stdout, result.Stderr, result.ExitCode
With options (timeout, limit)
result, err := container.ExecStd(ctx, []string{"cat", "/etc/passwd"}, dockerpool.ExecOptions{
    Timeout: 5 * time.Second,
    Limit:   1024 * 10, // 10KB max output
})
Streaming output
exitCode, err := container.ExecStream(ctx,
    []string{"sh", "-c", "echo building... && sleep 5 && echo done"},
    os.Stdout,  // stdout writer
    os.Stderr,  // stderr writer
    dockerpool.ExecOptions{},
)
With stdin
input := strings.NewReader("hello\nworld\n")
result, err := container.ExecStd(ctx, []string{"grep", "world"}, dockerpool.ExecOptions{
    Stdin: input,
})

Pool Operations

// Acquire container (blocks if pool empty, creates new)
container, err := pool.Acquire(ctx)

// Return to pool (or removes if pool full)
pool.Return(ctx, container)

// Remove without returning to pool
pool.Remove(ctx, container)

// Get metrics
idle := pool.IdleCount()  // Containers in pool
inUse := pool.InUse()     // Containers currently acquired

// Graceful shutdown (waits for in-use containers)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := pool.Shutdown(ctx)

Performance Tips

  1. Increase MinIdle for high-throughput scenarios
  2. Tune RefillInterval — lower values = faster recovery, more CPU
  3. Adjust MaxConcurrentDockerOps based on your Docker daemon capacity
  4. Use ExecStream for large outputs to avoid memory pressure

License

MIT

Documentation

Index

Constants

View Source
const (
	LabelManagedBy      = "dockerpool.managed-by"
	LabelManagedByValue = "dockerpool"
	LabelPoolName       = "dockerpool.pool-name"
)

Labels for identifying pool containers

Variables

View Source
var (
	// ErrImageRequired is returned when Docker image is not specified
	ErrImageRequired = errors.New("image is required")

	// ErrOutputLimitExceeded is returned when exec output exceeds the limit
	ErrOutputLimitExceeded = errors.New("output limit exceeded")

	// ErrPoolNameRequired is returned when pool name is empty
	ErrPoolNameRequired = errors.New("pool name is required")

	// ErrNetworkNameRequired is returned when network name is empty
	ErrNetworkNameRequired = errors.New("network name is required")
)

Functions

func MergeLabels

func MergeLabels(labelMaps ...map[string]string) map[string]string

MergeLabels merges multiple map[string]string into one. Later maps overwrite values from earlier ones.

func PoolLabels

func PoolLabels(poolName string) map[string]string

PoolLabels creates base labels for a pool container

Types

type Container

type Container interface {
	ID() string
	Image() string
	Labels() map[string]string
	State() ContainerState
	Stop(ctx context.Context) error
	Exec(ctx context.Context, cmd []string) (*ExecResult, error)
	ExecStd(ctx context.Context, cmd []string, opts ExecOptions) (*ExecResult, error)
	ExecStream(ctx context.Context, cmd []string, stdout, stderr io.Writer, opts ExecOptions) (exitCode int, err error)
}

Container interface for working with a container

func NewContainerClient

func NewContainerClient(opts ContainerOpts) Container

type ContainerClient

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

ContainerClient is the implementation of the Container interface

func (*ContainerClient) Exec

func (c *ContainerClient) Exec(ctx context.Context, cmd []string) (*ExecResult, error)

func (*ContainerClient) ExecStd

func (c *ContainerClient) ExecStd(ctx context.Context, cmd []string, opts ExecOptions) (*ExecResult, error)

func (*ContainerClient) ExecStream

func (c *ContainerClient) ExecStream(ctx context.Context, cmd []string, stdout, stderr io.Writer, opts ExecOptions) (int, error)

func (*ContainerClient) ID

func (c *ContainerClient) ID() string

func (*ContainerClient) Image

func (c *ContainerClient) Image() string

func (*ContainerClient) Labels

func (c *ContainerClient) Labels() map[string]string

func (*ContainerClient) State

func (c *ContainerClient) State() ContainerState

func (*ContainerClient) Stop

func (c *ContainerClient) Stop(ctx context.Context) error

type ContainerOpts

type ContainerOpts struct {
	Docker Docker
	ID     string
	Image  string
	Labels map[string]string
	State  ContainerState
}

type ContainerState

type ContainerState string
const (
	StateCreated    ContainerState = "created"
	StateRunning    ContainerState = "running"
	StatePaused     ContainerState = "paused"
	StateRestarting ContainerState = "restarting"
	StateRemoving   ContainerState = "removing"
	StateExited     ContainerState = "exited"
	StateDead       ContainerState = "dead"
)

Container states

type CreateContainerOptions

type CreateContainerOptions struct {
	Config     *container.Config     // Container configuration (image, cmd, env, labels, etc.)
	HostConfig *container.HostConfig // Host settings (volumes, network, resources, etc.)
}

CreateContainerOptions contains options for creating a container

type Docker

type Docker interface {
	// Close closes the connection to Docker
	Close() error

	// Ping checks connection to Docker daemon
	Ping(ctx context.Context) error

	// SetCleanupTimeout sets the timeout for cleanup operations
	SetCleanupTimeout(timeout time.Duration)

	// Image operations
	PullImage(ctx context.Context, image string) error

	// Network operations
	EnsureNetwork(ctx context.Context, networkName string) (bool, error)
	RemoveNetwork(ctx context.Context, networkName string) error

	// Container operations
	CreateContainer(ctx context.Context, networkName string, opts CreateContainerOptions) (Container, error)
	StopContainer(ctx context.Context, containerID string, opts client.ContainerStopOptions) error
	RemoveContainer(ctx context.Context, containerID string) error

	// Exec operations
	Exec(ctx context.Context, containerID string, cmd []string) (*ExecResult, error)
	ExecStd(ctx context.Context, containerID string, cmd []string, opts ExecOptions) (*ExecResult, error)
	ExecStream(ctx context.Context, containerID string, cmd []string, stdout, stderr io.Writer, opts ExecOptions) (exitCode int, err error)

	// List operations
	ListContainersByLabels(ctx context.Context, labels ...Label) ([]Container, error)
}

Docker is the interface for working with Docker.

type DockerClient

type DockerClient struct {
	CleanupTimeout time.Duration
	// contains filtered or unexported fields
}

DockerClient is the implementation of the Docker interface

func NewDockerClient

func NewDockerClient() (*DockerClient, error)

NewDockerClient creates a new Docker client with default settings

func NewDockerClientWithOpts

func NewDockerClientWithOpts(opts ...client.Opt) (*DockerClient, error)

NewDockerClientWithOpts creates a Docker client with custom options Example:

client, err := NewDockerClientWithOpts(
    client.WithHost("tcp://127.0.0.1:2375"),
    client.WithAPIVersionNegotiation(),
)

func (*DockerClient) Close

func (d *DockerClient) Close() error

Close closes the connection to Docker

func (*DockerClient) CreateContainer

func (d *DockerClient) CreateContainer(ctx context.Context, networkName string, opts CreateContainerOptions) (Container, error)

CreateContainer creates and starts a container. Returns the ID of the created container.

func (*DockerClient) EnsureNetwork

func (d *DockerClient) EnsureNetwork(ctx context.Context, networkName string) (bool, error)

EnsureNetwork creates a network if it does not exist. Returns true if the network was created, false if it already existed.

func (*DockerClient) Exec

func (d *DockerClient) Exec(ctx context.Context, containerID string, cmd []string) (*ExecResult, error)

Exec executes a command in a container and returns the result

func (*DockerClient) ExecStd

func (d *DockerClient) ExecStd(ctx context.Context, containerID string, cmd []string, opts ExecOptions) (*ExecResult, error)

ExecStd executes a command and returns output as strings in ExecResult. Use ExecStream if you need to stream output to io.Writer.

func (*DockerClient) ExecStream

func (d *DockerClient) ExecStream(ctx context.Context, containerID string, cmd []string, stdout, stderr io.Writer, opts ExecOptions) (int, error)

ExecStream executes a command and streams output to provided writers. Returns exit code directly. Use this for large outputs or real-time logging.

func (*DockerClient) ListContainersByLabels

func (d *DockerClient) ListContainersByLabels(ctx context.Context, labels ...Label) ([]Container, error)

ListContainersByLabels returns a list of containers with the specified labels (AND)

func (*DockerClient) Ping

func (d *DockerClient) Ping(ctx context.Context) error

Ping checks connection to Docker daemon

func (*DockerClient) PullImage

func (d *DockerClient) PullImage(ctx context.Context, image string) error

PullImage pulls an image from a registry and waits for completion

func (*DockerClient) RemoveContainer

func (d *DockerClient) RemoveContainer(ctx context.Context, containerID string) error

RemoveContainer stops and removes a container

func (*DockerClient) RemoveNetwork

func (d *DockerClient) RemoveNetwork(ctx context.Context, networkName string) error

RemoveNetwork removes a network

func (*DockerClient) SetCleanupTimeout

func (d *DockerClient) SetCleanupTimeout(timeout time.Duration)

SetCleanupTimeout sets the timeout for cleanup operations (container removal on error)

func (*DockerClient) StopContainer

func (d *DockerClient) StopContainer(ctx context.Context, containerID string, opts client.ContainerStopOptions) error

StopContainer stops a running container

type DockerPool

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

func NewDockerPool

func NewDockerPool(ctx context.Context, docker Docker, poolName string, networkName string, config DockerPoolConfig) (*DockerPool, error)

func (*DockerPool) Acquire

func (p *DockerPool) Acquire(ctx context.Context) (Container, error)

Acquire gets a container from the pool or creates a new one. After use, you must call Return() or Remove().

func (*DockerPool) IdleCount

func (p *DockerPool) IdleCount() int

IdleCount returns the number of idle containers in the pool

func (*DockerPool) InUse

func (p *DockerPool) InUse() int64

InUse returns the number of containers currently in use

func (*DockerPool) Remove

func (p *DockerPool) Remove(ctx context.Context, c Container)

Remove removes the container (does not return it to the pool)

func (*DockerPool) Return

func (p *DockerPool) Return(ctx context.Context, c Container)

Return returns the container to the pool. If the pool is full (>= maxIdle), the container is removed.

func (*DockerPool) Shutdown

func (p *DockerPool) Shutdown(ctx context.Context) error

type DockerPoolConfig

type DockerPoolConfig struct {
	// Error handling
	OnError func(error)

	// Container configuration
	ContainerConfig CreateContainerOptions
	Labels          map[string]string

	// Pool sizing
	MinIdle int
	MaxIdle int

	// Timing
	RefillInterval time.Duration

	// Concurrency limits
	MaxConcurrentDockerOps int
}

func DefaultDockerPoolConfig

func DefaultDockerPoolConfig() DockerPoolConfig

DefaultDockerPoolConfig returns a config with sensible defaults

type ExecOptions

type ExecOptions struct {
	Stdin   io.Reader     // Input to pass to the command
	Timeout time.Duration // If > 0, command will be cancelled after timeout
	Limit   int64         // If > 0, the output will be limited to the given number of bytes
}

ExecOptions contains options for executing a command in a container

type ExecResult

type ExecResult struct {
	ExitCode int
	Stdout   string
	Stderr   string
}

ExecResult contains the result of executing a command in a container

type Label

type Label struct {
	Key   string
	Value string
}

Label represents a key-value pair for filtering containers

type Pool

type Pool[T any] interface {
	Push(elem T)
	Pop() (elem T, ok bool)
	Len() int
}

func NewPool

func NewPool[T any]() Pool[T]

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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