NAME
API::Docker::API::Exec - Docker Engine Exec API
VERSION
version 0.004
SYNOPSIS
my $docker = API::Docker->new;
# Create an exec instance
my $exec = $docker->exec->create($container_id,
Cmd => ['/bin/sh', '-c', 'echo hello'],
AttachStdout => 1,
AttachStderr => 1,
);
# Start the exec -- ArrayRef of { stream => ..., data => ... } frames
my $frames = $docker->exec->start($exec->{Id});
my $output = join '', map { $_->{data} } @$frames;
# The exit status comes from a separate call
my $exit = $docker->exec->inspect($exec->{Id})->{ExitCode};
# Inspect exec instance
my $info = $docker->exec->inspect($exec->{Id});
DESCRIPTION
This module provides methods for executing commands inside running containers using the Docker Exec API.
Accessed via $docker->exec, or through "using" in API::Docker::Role::Using for a run of calls that needs its own transport bound: $docker->exec->using(read_timeout => 5).
client
Reference to API::Docker client. Weak reference to avoid circular dependencies.
create
my $exec = $exec->create($container_id,
Cmd => ['/bin/sh', '-c', 'echo hello'],
AttachStdout => 1,
AttachStderr => 1,
Tty => 0,
);
Create an exec instance. Returns hashref with Id.
Required config: Cmd (ArrayRef of command and arguments).
Common config keys: AttachStdin, AttachStdout, AttachStderr, Tty, Env, User, WorkingDir.
The boolean flags (AttachStdin, AttachStdout, AttachStderr, Tty, Privileged) may be given as a Perl 1/0 or as a JSON boolean; either goes out as a real JSON true/false, which the engine's body type-check requires. Passing 1 where the daemon wants a boolean would otherwise be rejected.
start
my $frames = $exec->start($exec_id, Detach => 0);
my $output = join '', map { $_->{data} } @$frames;
Start an exec instance. Returns an ArrayRef of frames in the same shape as "logs" in API::Docker::API::Containers:
[ { stream => 'stdout', data => "OUT\n" },
{ stream => 'stderr', data => "ERR\n" } ]
An exec instance created without a TTY multiplexes stdout and stderr into one framed stream, which this method demultiplexes. One created with a TTY has no frame headers and its output arrives as a single stream => 'raw' frame. A detached start produces no output, so it returns an empty ArrayRef.
The exit status is not part of this response. It comes from a separate call once the exec has finished:
my $exit = $exec->inspect($exec_id)->{ExitCode};
Options:
Detach- Run detached; the engine returns immediately and no output is streamedTty- Declares that this exec instance was created with a TTY. It is sent in the request body, where the engine expects it to match theTtygiven to "create", and it also suppresses demultiplexing of the response. Framing is otherwise detected from the response bytes -- see "Detecting a framed stream" in API::Docker::Role::HTTPon_frame- CodeRef called with each frame as it arrives, instead of the ArrayRef being collected and returned; see below
Watching the output as it is produced
Without a callback this returns when the command has finished and the daemon has closed the stream -- a command that runs for a minute is a minute of silence, and one that never finishes never returns. Pass on_frame and the frames are handed over as they arrive:
my $summary = $exec->start($exec_id,
on_frame => sub {
my ($frame, $stop) = @_;
print $frame->{data};
$stop->() if $frame->{data} =~ /ready/;
},
);
$summary; # { delivered => 9, stopped => 1 }
With a callback the return value is that summary HashRef, not the frames: delivered is how many went to the callback, stopped is 1 when the callback ended the stream and 0 when the daemon did. Nothing is accumulated, so joining the output is the callback's job. See "Streaming a response as it arrives" in API::Docker::Role::HTTP.
A detached start produces no output, so its summary is { delivered => 0, stopped => 0 } where the buffered call returns an empty ArrayRef.
Tty means something stronger on this path. The buffered path decides framing by walking the whole body, which is exactly what a streamed one does not have; so with on_frame it is a promise about the exec instance rather than a hint, and an undeclared stream that turns out not to be framed croaks instead of being handed back raw. Pass the same Tty that went to "create" -- the engine expects them to agree in any case.
resize
$exec->resize($exec_id, h => 40, w => 120);
Resize the TTY for an exec instance.
Options:
h- New height in character rowsw- New width in character columns
inspect
my $info = $exec->inspect($exec_id);
Get information about an exec instance.
SEE ALSO
API::Docker - Main Docker client
API::Docker::API::Containers - Container management
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.