NAME
API::Docker - Perl client for the Docker Engine API
VERSION
version 0.003
SYNOPSIS
use API::Docker;
# Connect to local Docker daemon via Unix socket
my $docker = API::Docker->new;
# Or connect to remote Docker daemon
my $docker = API::Docker->new(
host => 'tcp://192.168.1.100:2375',
);
# System information
my $info = $docker->system->info;
my $version = $docker->system->version;
# Container management
my $containers = $docker->containers->list(all => 1);
my $result = $docker->containers->create(
Image => 'nginx:latest',
name => 'my-nginx',
);
$docker->containers->start($result->{Id});
# Image operations
$docker->images->pull(fromImage => 'nginx', tag => 'latest');
my $images = $docker->images->list;
# Network and volume management
my $networks = $docker->networks->list;
my $volumes = $docker->volumes->list;
DESCRIPTION
API::Docker is a Perl client for the Docker Engine API. It provides a clean object-oriented interface to manage Docker containers, images, networks, and volumes.
Key features:
Pure Perl implementation with minimal dependencies
Unix socket and TCP transport support, both plaintext -- there is no TLS, and "tls" croaks rather than implying there is
Automatic API version negotiation
Object-oriented entity classes (Container, Image, Network, Volume)
Comprehensive logging via Log::Any
Architecture
The distribution is organized into several layers:
Main Client - API::Docker - Entry point with API version negotiation
API Modules - Resource-specific API methods:
API::Docker::API::System - System info, version, ping
API::Docker::API::Containers - Container management
API::Docker::API::Images - Image management
API::Docker::API::Networks - Network management
API::Docker::API::Volumes - Volume management
API::Docker::API::Exec - Exec into containers
Entity Classes - Object wrappers for Docker resources:
API::Docker::Container - Container entity with convenience methods
API::Docker::Image - Image entity
API::Docker::Network - Network entity
API::Docker::Volume - Volume entity
HTTP Role - API::Docker::Role::HTTP - HTTP transport layer
host
Docker daemon connection URL. Defaults to $ENV{DOCKER_HOST} or unix:///var/run/docker.sock.
No other source is consulted; see "Socket discovery".
Supported formats:
unix:///path/to/socket- Unix socket (default)tcp://host:port- TCP connection
api_version
Docker API version to use (e.g., 1.41). If not set, the client will automatically negotiate the highest API version supported by the daemon.
This attribute is set automatically by "negotiate_version".
tls
Not implemented. tls => 1 croaks at construction; the default of 0 is the only value this client accepts.
The attribute is kept rather than removed because silence is the failure mode worth preventing here. API::Docker::Role::HTTP builds a plain IO::Socket::INET connection and speaks HTTP over it, and nothing anywhere reads this attribute -- so a tcp:// daemon has always been addressed in cleartext, tls => 1 or not, and a caller who asked for TLS got an unencrypted connection and no indication of it. Anyone who was passing this option was, by definition, sending credentials in the clear while believing otherwise.
Terminate TLS in front of the daemon instead and point "host" at the local end of it:
# stunnel, socat or plain ssh -- whatever is already in the stack
ssh -N -L 2375:127.0.0.1:2376 dockerhost
my $docker = API::Docker->new(host => 'tcp://127.0.0.1:2375');
Implementing TLS here is new work, not a repair: it needs the socket builder to know about IO::Socket::SSL, client certificates and verification policy. Until then this croaks.
cert_path
Unused. Path to TLS certificates, defaulting to $ENV{DOCKER_CERT_PATH}. No code reads it.
Unlike "tls" it does not croak, and deliberately so: it defaults from the environment, and DOCKER_CERT_PATH is commonly exported on machines that also run the docker CLI. Croaking on it would break clients that never asked for TLS at all, over a value the caller did not pass. On its own it also asserts nothing and transmits nothing -- setting it cannot make an unencrypted connection look encrypted, which is the specific harm "tls" was doing. The path that would act on it is the one that croaks.
system
Returns API::Docker::API::System instance for system operations like info, version, ping, and events.
containers
Returns API::Docker::API::Containers instance for container operations like list, create, start, stop, and remove.
images
Returns API::Docker::API::Images instance for image operations like list, pull, push, and remove.
networks
Returns API::Docker::API::Networks instance for network operations like list, create, connect, and disconnect.
volumes
Returns API::Docker::API::Volumes instance for volume operations like list, create, and remove.
exec
Returns API::Docker::API::Exec instance for executing commands in containers.
negotiate_version
$docker->negotiate_version;
Automatically negotiate the highest API version supported by the Docker daemon. This is called automatically before the first API request if "api_version" is not set.
After negotiation, "api_version" will contain the negotiated version (e.g., 1.41).
CONTAINER ENGINES
This client speaks the Docker Engine HTTP API over a socket. It never shells out to the docker binary, so any engine serving that API works, whether or not Docker itself is installed.
Podman
Podman ships a Docker-compatible API service. Enable its rootless socket and point "host" at it:
systemctl --user enable --now podman.socket
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock"
The socket announces API version 1.41, which "negotiate_version" picks up like any other daemon. Multi-stage builds are passed through unchanged, target included, down to skipping the stages the target does not depend on.
Socket discovery
"host" resolves in two steps and no more: $ENV{DOCKER_HOST}, then unix:///var/run/docker.sock. It deliberately does not read Docker contexts. currentContext in ~/.docker/config.json and the matching ~/.docker/contexts/meta/*/meta.json are ignored, so if you switch daemons with docker context use, that choice is not picked up here. Set DOCKER_HOST explicitly instead.
Other clients sit at different points on that scale. The docker CLI and docker-java resolve contexts, with DOCKER_HOST outranking them when set. docker-py's from_env() reads DOCKER_HOST and otherwise falls back to the default socket, leaving contexts to a separate API. Testcontainers layers its own ~/.testcontainers.properties and a rootless probe list ($XDG_RUNTIME_DIR/docker.sock, ~/.docker/run/docker.sock, ~/.docker/desktop/docker.sock, /run/user/$UID/docker.sock) on top.
What none of them do is guess Podman's socket path: that probe list is for rootless Docker, not for Podman. Every one of those projects documents DOCKER_HOST as the way to reach Podman, which is the same answer given above.
ENVIRONMENT VARIABLES
DOCKER_HOST-
Docker daemon connection URL. Used as default for "host" if not explicitly set.
Examples:
unix:///var/run/docker.sock,tcp://localhost:2375Also the supported way to reach a non-Docker engine such as Podman:
unix://$XDG_RUNTIME_DIR/podman/podman.sock. See "CONTAINER ENGINES". DOCKER_CERT_PATH-
Path to TLS certificates directory. Used as default for "cert_path", which nothing reads -- this client has no TLS support at all. Setting it changes nothing, and having it set (as machines running the
dockerCLI usually do) breaks nothing.
SEE ALSO
API::Docker::Role::HTTP - HTTP transport implementation
API::Docker::API::System - System and daemon operations
API::Docker::API::Containers - Container management
API::Docker::API::Images - Image management
API::Docker::API::Networks - Network management
API::Docker::API::Volumes - Volume management
API::Docker::API::Exec - Execute commands in containers
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-api-docker/issues.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.