Skip to content

Commit 00391b4

Browse files
committed
Documentation for streaming API endpoints
1 parent 10beb65 commit 00391b4

2 files changed

Lines changed: 165 additions & 5 deletions

File tree

README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ The `Client` is responsible for assembling and sending HTTP requests to the Dock
7373
It requires a `Browser` object bound to the main `EventLoop` in order to handle async requests and a base URL.
7474
The recommended way to create a `Client` is using the `Factory` (see above).
7575

76+
#### Commands
77+
7678
All public methods on the `Client` resemble the API described in the [Remote API documentation](https://docs.docker.com/reference/api/docker_remote_api_v1.15/) like this:
7779

7880
```php
@@ -92,6 +94,8 @@ $client->version();
9294

9395
Listing all available commands is out of scope here, please refer to the [Remote API documentation](https://docs.docker.com/reference/api/docker_remote_api_v1.15/) or the class outline.
9496

97+
#### Promises
98+
9599
Sending requests is async (non-blocking), so you can actually send multiple requests in parallel.
96100
Docker will respond to each request with a response message, the order is not guaranteed.
97101
Sending requests uses a [Promise](https://github.com/reactphp/promise)-based interface that makes it easy to react to when a request is fulfilled (i.e. either successfully resolved or rejected with an error):
@@ -107,6 +111,106 @@ $client->version()->then(
107111
});
108112
```
109113

114+
#### TAR streaming
115+
116+
The following API endpoints resolve with a string in the [TAR file format](https://en.wikipedia.org/wiki/Tar_%28computing%29):
117+
118+
```php
119+
$client->containerExport($container);
120+
$client->containerCopy($container, $config);
121+
```
122+
123+
Keep in mind that this means the whole string has to be kept in memory.
124+
This is easy to get started and works reasonably well for smaller files/containers.
125+
126+
For bigger containers it's usually a better idea to use a streaming approach,
127+
where only small chunks have to be kept in memory.
128+
This works for (any number of) files of arbitrary sizes.
129+
The following API endpoints complement the default Promise-based API and return
130+
a [`Stream`](https://github.com/reactphp/stream) instance instead:
131+
132+
```php
133+
$stream = $client->containerExportStream($image);
134+
$stream = $client->containerCopyStream($image, $config);
135+
```
136+
137+
Accessing individual files in the TAR file format string or stream is out of scope
138+
for this library.
139+
Several libraries are available, one that is known to work is [clue/tar-react](https://github.com/clue/php-tar-react).
140+
141+
See also the [copy example](examples/copy.php) and the [export example](examples/export.php).
142+
143+
#### JSON streaming
144+
145+
The following API endpoints take advantage of [JSON streaming](https://en.wikipedia.org/wiki/JSON_Streaming):
146+
147+
```php
148+
$client->imageCreate();
149+
$client->imagePush();
150+
```
151+
152+
What this means is that these endpoints actually emit any number of progress
153+
events (individual JSON objects).
154+
155+
The user-facing API hides this fact by resolving with an array of all individual
156+
progress events once the stream ends.
157+
158+
These progress events can also be accessed individually via the Promise
159+
progress handler like this:
160+
161+
```php
162+
$client->imageCreate('clue/streamripper')->then(
163+
function ($data) {
164+
// $data is an array of *all* elements in the JSON stream
165+
},
166+
function ($error) {
167+
// an error occurred (possibly after receiving *some* elements)
168+
},
169+
function ($element) {
170+
// will be invoked for *each* complete $element in the JSON stream
171+
}
172+
);
173+
```
174+
175+
Keep in mind that due to resolving with an array of all progress events,
176+
this API has to keep all event objects in memory until the Promise resolves.
177+
This is easy to get started and usually works reasonably well for the above
178+
API endpoints.
179+
180+
If you're dealing with lots of concurrent requests (100+),
181+
it could be a better idea to use a streaming approach,
182+
where only individual progress event objects have to be kept in memory.
183+
The following API endpoints complement the default Promise-based API and return
184+
a [`Stream`](https://github.com/reactphp/stream) instance instead:
185+
186+
```php
187+
$stream = $client->imageCreateStream();
188+
$stream = $client->imagePushStream();
189+
```
190+
191+
The resulting stream will emit the following events:
192+
193+
* `progress`: for *each* element in the update stream
194+
* `error`: once if an error occurs, will close() stream then
195+
* `close`: once the stream ends (either finished or after "error")
196+
197+
Please note that the resulting stream does not emit any "data" events, so
198+
you will not be able to pipe() its events into another `WritableStream`.
199+
200+
```php
201+
$stream = $client->imageCreateStream('clue/redis-benchmark');
202+
$stream->on('progress', function ($data) {
203+
// data will be emitted for *each* complete element in the JSON stream
204+
echo $data['status'] . PHP_EOL;
205+
});
206+
$stream->on('close', function () {
207+
// the JSON stream just ended, this could(?) be a good thing
208+
echo 'Ended' . PHP_EOL;
209+
});
210+
```
211+
212+
See also the [pull example](examples/pull.php) and the [push example](examples/push.php).
213+
110214
## Install
111215

112216
The recommended way to install this library is [through composer](http://getcomposer.org). [New to composer?](http://getcomposer.org/doc/00-intro.md)

src/Client.php

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,21 @@ public function containerChanges($container)
149149
/**
150150
* Export the contents of container id
151151
*
152+
* This resolves with a string in the TAR file format containing all files
153+
* in the container.
154+
*
155+
* Keep in mind that this means the whole string has to be kept in memory.
156+
* For bigger containers it's usually a better idea to use a streaming
157+
* approach, see containerExportStream() for more details.
158+
*
159+
* Accessing individual files in the TAR file format string is out of scope
160+
* for this library. Several libraries are available, one that is known to
161+
* work is clue/tar-react (see links).
162+
*
152163
* @param string $container container ID
153164
* @return Promise Promise<string> tar stream
154165
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#export-a-container
166+
* @link https://github.com/clue/php-tar-react library clue/tar-react
155167
* @see self::containerExportStream()
156168
*/
157169
public function containerExport($container)
@@ -162,12 +174,23 @@ public function containerExport($container)
162174
/**
163175
* Export the contents of container id
164176
*
177+
* This returns a stream in the TAR file format containing all files
178+
* in the container.
179+
*
180+
* This works for containers of arbitrary sizes as only small chunks have to
181+
* be kept in memory.
182+
*
183+
* Accessing individual files in the TAR file format stream is out of scope
184+
* for this library. Several libraries are available, one that is known to
185+
* work is clue/tar-react (see links).
186+
*
165187
* The resulting stream is a well-behaving readable stream that will emit
166188
* the normal stream events.
167189
*
168190
* @param string $container container ID
169191
* @return ReadableStreamInterface tar stream
170192
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#export-a-container
193+
* @link https://github.com/clue/php-tar-react library clue/tar-react
171194
* @see self::containerExport()
172195
*/
173196
public function containerExportStream($container)
@@ -294,10 +317,22 @@ public function containerRemove($container, $v = false, $force = false)
294317
/**
295318
* Copy files or folders of container id
296319
*
320+
* This resolves with a string in the TAR file format containing all files
321+
* specified in the $config array.
322+
*
323+
* Keep in mind that this means the whole string has to be kept in memory.
324+
* For bigger containers it's usually a better idea to use a streaming approach,
325+
* see containerCopyStream() for more details.
326+
*
327+
* Accessing individual files in the TAR file format string is out of scope
328+
* for this library. Several libraries are available, one that is known to
329+
* work is clue/tar-react (see links).
330+
*
297331
* @param string $container container ID
298332
* @param array $config resources to copy `array('Resource' => 'file.txt')` (see link)
299333
* @return Promise Promise<string> tar stream
300334
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#copy-files-or-folders-from-a-container
335+
* @link https://github.com/clue/php-tar-react library clue/tar-react
301336
* @see self::containerCopyStream()
302337
*/
303338
public function containerCopy($container, $config)
@@ -308,13 +343,24 @@ public function containerCopy($container, $config)
308343
/**
309344
* Copy files or folders of container id
310345
*
346+
* This returns a stream in the TAR file format containing all files
347+
* specified in the $config array.
348+
*
349+
* This works for (any number of) files of arbitrary sizes as only small chunks have to
350+
* be kept in memory.
351+
*
352+
* Accessing individual files in the TAR file format stream is out of scope
353+
* for this library. Several libraries are available, one that is known to
354+
* work is clue/tar-react (see links).
355+
*
311356
* The resulting stream is a well-behaving readable stream that will emit
312357
* the normal stream events.
313358
*
314359
* @param string $container container ID
315360
* @param array $config resources to copy `array('Resource' => 'file.txt')` (see link)
316361
* @return ReadableStreamInterface tar stream
317362
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#copy-files-or-folders-from-a-container
363+
* @link https://github.com/clue/php-tar-react library clue/tar-react
318364
* @see self::containerCopy()
319365
*/
320366
public function containerCopyStream($container, $config)
@@ -338,8 +384,11 @@ public function imageList($all = false)
338384
/**
339385
* Create an image, either by pulling it from the registry or by importing it
340386
*
341-
* Will resolve with an array of all progress events. These can also be
342-
* accessed via the Promise progress handler.
387+
* This is a JSON streaming API endpoint that resolves with an array of all
388+
* individual progress events.
389+
*
390+
* These progress events can also be accessed individually via the Promise
391+
* progress handler.
343392
*
344393
* Pulling a private image from a remote registry will likely require authorization, so make
345394
* sure to pass the $registryAuth parameter, see `self::authHeaders()` for
@@ -365,6 +414,8 @@ public function imageCreate($fromImage = null, $fromSrc = null, $repo = null, $t
365414
/**
366415
* Create an image, either by pulling it from the registry or by importing it
367416
*
417+
* This is a JSON streaming API endpoint that returns a stream instance.
418+
*
368419
* The resulting stream will emit the following events:
369420
* - progress: for *each* element in the update stream
370421
* - error: once if an error occurs, will close() stream then
@@ -423,8 +474,11 @@ public function imageHistory($image)
423474
/**
424475
* Push the image name on the registry
425476
*
426-
* Will resolve with an array of all progress events. These can also be
427-
* accessed via the Promise progress handler.
477+
* This is a JSON streaming API endpoint that resolves with an array of all
478+
* individual progress events.
479+
*
480+
* These progress events can also be accessed individually via the Promise
481+
* progress handler.
428482
*
429483
* Pushing to a remote registry will likely require authorization, so make
430484
* sure to pass the $registryAuth parameter, see `self::authHeaders()` for
@@ -448,6 +502,8 @@ public function imagePush($image, $tag = null, $registry = null, $registryAuth =
448502
/**
449503
* Push the image name on the registry
450504
*
505+
* This is a JSON streaming API endpoint that returns a stream instance.
506+
*
451507
* The resulting stream will emit the following events:
452508
* - progress: for *each* element in the update stream
453509
* - error: once if an error occurs, will close() stream then
@@ -465,7 +521,7 @@ public function imagePush($image, $tag = null, $registry = null, $registryAuth =
465521
* @param string|null $registry (optional) the registry to push to (e.g. `registry.acme.com:5000`)
466522
* @param array|null $registryAuth (optional) AuthConfig object (to send as X-Registry-Auth header)
467523
* @return ReadableStreamInterface stream of image push messages
468-
* @uses authHeaders()
524+
* @uses self::authHeaders()
469525
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#push-an-image-on-the-registry
470526
*/
471527
public function imagePushStream($image, $tag = null, $registry = null, $registryAuth = null)

0 commit comments

Comments
 (0)