API-Docker

 view release on metacpan or  search on metacpan

lib/API/Docker/API/Containers.pm  view on Meta::CPAN

C<< $containers->attach($id) >> B<replays> what the container has written and
returns.

B<This is a change.> Up to and including the previous release C<stream>
defaulted to 1, so the same call opened an open-ended subscription; a caller
who wants the live stream now has to ask for it with C<< stream => 1 >>.

The reason is that the subscription has exactly one terminator: the container
ending. C<stream> means I<stream attached streams from the time the request
was made onwards>, so on a container that has B<already exited> that
terminator is in the past and will not happen again. attach also hijacks the
connection -- the response carries no C<Content-Length> and no chunked
terminator -- so HTTP framing cannot signal the end either. The transport
reads until EOF, there is no EOF, and the call hangs. C<on_frame> does not
help: nothing will ever call C<< $stop->() >>.

Measured on Podman 5.4.2 (API 1.41), all four against one and the same
container:

=over

=item * C<?logs=1&stdout=1&stderr=1&stream=0>, exited container -- 200, the
frames, connection closed after 13 ms

=item * C<?logs=1&stdout=1&stderr=1&stream=1>, exited container -- 200, the
same frames, then hangs

=item * the same with C<Upgrade: tcp> -- 101 UPGRADED, the same frames, still
hangs

=item * C<?stream=1> while the container is still B<running> and exits three
seconds later -- closes cleanly after 3 s

=back

B<Docker does exactly the same, and that is measured now too.> Against Docker
29.7.2 (API 1.55): C<?logs=1&stdout=1&stderr=1&stream=1> on an exited
container was still open when a 10 s probe gave up, and
C<?logs=1&stdout=1&stderr=1&stream=0> answered 200 with byte-identical frames
and closed in half a millisecond. So the hang is not a Podman quirk to be
worked around -- it is what both engines do with a subscription whose only
terminator is already in the past, on an endpoint whose reference promises a
close in neither direction. It is unspecified behavior on both, which is the
case for the C<< stream => 0 >> default rather than an argument against it.

One more measured difference: Podman refuses C<< stream => 0 >> together with
C<< logs => 0 >> outright, with B<400> C<at least one of Logs or Stream must
be set>, rather than answering an empty 200.

Options:

=over

=item * C<stream> - Subscribe to what the container writes from the time of
the request onwards. Default B<0>, which is the engine's own default.
C<< stream => 1 >> on a container that is not running never returns; see
L</"The defaults follow the engine">

=item * C<logs> - Replay what the container has already written. Default
B<1>, so the call returns something without subscribing; combined with
C<< stream => 1 >> the replay comes first and then transitions seamlessly
into the live output. C<< logs => 0 >> without C<< stream => 1 >> is the
combination the engine refuses (400 on Podman)

=item * C<stdout> - Attach stdout. Default 1 (engine default: false)

=item * C<stderr> - Attach stderr. Default 1 (engine default: false)

=item * C<stdin> - Attach stdin. Sent as asked, but nothing can be written to
it here; see above

=item * C<tty> - Set to 1 when the container was created with a TTY and its
output is binary, to skip demultiplexing. Same meaning as in L</logs>, and
with C<on_frame> the same promise

=item * C<on_frame> - CodeRef called with each frame as it arrives, instead of
the ArrayRef being collected and returned. Same contract as in L</logs>

=item * C<require_running> - Ask L</inspect> whether the container is running
first, and croak rather than attach when it is not. Default B<1>. Set to 0 to
attach to a stopped container anyway, which also skips the round trip; see
L</"This method refuses a container that is not running"> for what the check
does and does not guarantee

=back

=head2 top

    my $processes = $containers->top($id, ps_args => 'aux');

List running processes in a container. Returns hashref with C<Titles> and C<Processes> arrays.

Options:

=over

=item * C<ps_args> - Arguments passed to C<ps> inside the container, e.g.
C<'aux'>. Omitted, the engine uses its own default

=back

=head2 stats

    my $stats = $containers->stats($id);

Get container resource usage statistics (CPU, memory, network, I/O). With no
options this is the one-shot call it always was: a single reading, returned as
a HashRef.

For a container that is B<not running> the two engines answer differently and
neither says so in the status line -- on Podman this method croaks, on Docker
it returns zeros that look like a reading. See
L</"A container that is not running: a croak on Podman, zeros on Docker">
before calling it on a container that may have stopped.

=head2 Following the stats

C<< stream => 1 >> asks the engine for a reading per sampling cycle for as long
as the container runs. Pass C<on_event> with it and the readings are handed
over as they arrive:



( run in 0.831 second using v1.01-cache-2.11-cpan-ad19def0cd9 )