This user manual is made to correspond to Docker's [API docs][1] (e.g. [API 1.18][2]).
- Creating a DockerClient
- Authentication to private registries
- Containers
- List containers
- Create a container
- Inspect a container
- List processes running inside a container
- Get container logs
- Inspect changes on a container's filesystem
- Export a container
- Get container stats based on resource usage
- Resize a container TTY
- Start a container
- Stop a container
- Restart a container
- Kill a container
- Rename a container
- Pause a container
- Unpause a container
- Attach to a container
- Wait a container
- Remove a container
- Copy files or folders from a container
- Secrets
- Images
- Volumes
- Miscellaneous
- Check auth configuration
- Display system-wide information
- Show the docker version information
- Ping the docker server
- Create a new image from a container’s changes
- Monitor Docker’s events
- Get a tarball containing all images in a repository
- Get a tarball containing all images.
- Load a tarball with a set of images and tags into docker
- Image tarball format
- Exec Create
- Exec Start
- Exec Resize
- Exec Inspect
- Mounting volumes in a container
- Troubleshooting
// Create a client based on DOCKER_HOST and DOCKER_CERT_PATH env vars
final DockerClient docker = new JerseyDockerClientBuilder().fromEnv().build();
// or use the builder
final DockerClient docker = new JerseyDockerClientBuilder
// Set various options
.build();
Both new JerseyDockerClientBuilder
and new JerseyDockerClientBuilder().fromEnv()
return a
DefaultDockerClient.Builder
. The builder can be used to configure and build clients with custom
timeouts, connection pool sizes, and other parameters.
Unix socket support is available on Linux since v2.5.0:
final DockerClient docker = new JerseyDockerClientBuilder().uri("unix:///var/run/docker.sock");
We can connect to HTTPS-secured Docker instances
with client-server authentication. The semantics are similar to using the DOCKER_CERT_PATH
environment variable:
final DockerClient docker = new JerseyDockerClientBuilder
.uri(URI.create("https://boot2docker:2376"))
.dockerCertificates(new DockerCertificates(Paths.get("/Users/rohan/.docker/boot2docker-vm/")))
.build();
We use the Apache HTTP client under the covers, with a shared connection pool per instance of the Docker client. The default size of this pool is 100 connections, so each instance of the Docker client can only have 100 concurrent requests in flight.
If you plan on waiting on more than 100 containers at a time (DockerClient.waitContainer
), or
otherwise need a higher number of concurrent requests, you can modify the connection pool size:
final DockerClient docker = new JerseyDockerClientBuilder().fromEnv()
.connectionPoolSize(SOME_LARGE_NUMBER)
.build()
Note that the connect timeout is also applied to acquiring a connection from the pool. If the pool
is exhausted and it takes too long to acquire a new connection for a request, we throw a
DockerTimeoutException
instead of just waiting forever on a connection becoming available.
Authentication info when building, pushing, or pulling images, or when using
Swarm, is provided by a RegistryAuthSupplier
class.
Docker-client is packaged with a few implementations of this interface
auth.ConfigFileRegistryAuthSupplier
, which reads authentication info from the the config files used by docker-cli (~/.dockercfg
or~/.docker/config.json
)auth.FixedRegistryAuthSupplier
which uses a fixed instance of theRegistryAuth
andRegistryConfigs
POJOsauth.MultiRegistryAuthSupplier
, which can be used to combine multiple other implementations
Users are encouraged to implement the RegistryAuthSupplier
interface
themselves to support custom authentication logic, and we would be happy to
review and accept pull requests to add support in the library for additional
schemes.
Since version 8.7.0, docker-client will automatically enable the
ConfigFileRegistryAuthSupplier
class in DefaultDockerClient
as long as none
of the other authentication-related methods in the
DefaultDockerClient.Builder
class (dockerAuth(boolean)
,
registryAuth(RegistryAuth)
, or registryAuthSupplier(RegistryAuthSupplier)
)
are used.
final List<Container> containers = docker.listContainers();
// List all containers. Only running containers are shown by default.
final List<Container> containers = docker.listContainers(ListContainersParam.allContainers());
final ContainerCreation container = docker.createContainer(ContainerConfig.builder().build());
final ContainerInfo info = docker.inspectContainer("containerID");
final TopResults topResults = docker.topContainer("containerID", "ps_args");
final String logs;
try (LogStream stream = client.logs("containerID", LogsParam.stdout(), LogsParam.stderr())) {
logs = stream.readFully();
}
final List<ContainerChange> changes = docker.inspectContainerChanges("containerId");
ImmutableSet.Builder<String> files = ImmutableSet.builder();
try (TarArchiveInputStream tarStream = new TarArchiveInputStream(docker.exportContainer(id))) {
TarArchiveEntry entry;
while ((entry = tarStream.getNextTarEntry()) != null) {
files.add(entry.getName());
}
}
final ContainerStats stats = docker.stats("containerID");
final int height = 10;
final int width = 10;
docker.resizeTty("containerID", height, width);
docker.startContainer("containerID");
docker.stopContainer("containerID", 10); // kill after 10 seconds
docker.restartContainer("containerID");
// or with a seconds to wait before restarting parameter
docker.restartContainer("containerID", 10);
docker.killContainer("containerID");
docker.renameContainer("oldContainerID", "newContainerID");
docker.pauseContainer("containerID");
docker.unpauseContainer("containerID");
final String logs;
try (LogStream stream = docker.attachContainer(volumeContainer,
AttachParameter.LOGS, AttachParameter.STDOUT,
AttachParameter.STDERR, AttachParameter.STREAM)) {
logs = stream.readFully();
}
final ContainerExit exit = docker.waitContainer("containerID");
docker.removeContainer("containerID");
NOTE: deprecated in favor of archive
ImmutableSet.Builder<String> files = ImmutableSet.builder();
try (TarArchiveInputStream tarStream =
new TarArchiveInputStream(docker.copyContainer(id, "/bin"))) {
TarArchiveEntry entry;
while ((entry = tarStream.getNextTarEntry()) != null) {
files.add(entry.getName());
}
}
try (final TarArchiveInputStream tarStream = new TarArchiveInputStream(docker.archiveContainer("containerID", "/file/path"))) {
TarArchiveEntry entry;
while ((entry = tarStream.getNextTarEntry()) != null) {
// Do stuff with the files in the stream
}
}
docker.copyToContainer(new java.io.File("/local/path").toPath(), "containerID", "/path/in/container");
docker.inspectNetwork("networkID");
NetworkConfig networkConfig = NetworkConfig.builder()
.checkDuplicate(true)
.attachable(true)
.name("newNetwork")
.build();
docker.createNetwork(networkConfig);
docker.removeNetwork("networkID");
This should be called before starting a container, but may fail silently if duplicate networks exist.
docker.connectToNetwork("containerID", "networkID");
docker.disconnectFromNetwork("containerID", "networkID");
final SecretSpec secret = SecretSpec.builder().name("asecret").data(base64encodeddata).build();
docker.createSecret(secret);
final List<Image> quxImages = docker.listImages(ListImagesParam.withLabel("foo", "qux"));
final AtomicReference<String> imageIdFromMessage = new AtomicReference<>();
final String returnedImageId = docker.build(
Paths.get(dockerDirectory), "test", new ProgressHandler() {
@Override
public void progress(ProgressMessage message) throws DockerException {
final String imageId = message.buildImageId();
if (imageId != null) {
imageIdFromMessage.set(imageId);
}
}
});
// By pulling
final RegistryAuth registryAuth = RegistryAuth.builder()
.email(AUTH_EMAIL)
.username(AUTH_USERNAME)
.password(AUTH_PASSWORD)
.build();
docker.pull("dxia2/scratch-private:latest", registryAuth);
// or by loading from a source
final File imageFile = new File("/path/to/image/file");
final String image = "busybox-test" + System.nanoTime();
try (InputStream imagePayload = new BufferedInputStream(new FileInputStream(imageFile))) {
docker.create(image, imagePayload);
}
final ImageInfo info = docker.inspectImage("imageID")
final List<ImageHistory> imageHistoryList = docker.history("imageID");
docker.push("imageID");
docker.pull("busybox:latest");
final String name = "testRepo/tagForce:sometag";
// Assign name to first image
docker.tag("busybox:latest", name);
// Force-re-assign tag to another image
docker.tag("busybox:buildroot-2014.02", name, true);
docker.removeImage("imageID");
final List<ImageSearchResult> searchResult = docker.searchImages("busybox");
final VolumeList volumeList = docker.listVolumes();
final List<String> warnings = volumeList.warnings();
final List<Volume> volumes = volumeList.volumes();
Create a volume with specified properties:
final Volume toCreate = Volume.builder()
.name("volumeName")
.driver("local")
.labels(ImmutableMap.of("foo", "bar"))
.build();
final Volume created = docker.createVolume(toCreate);
Or create an anonymous volume:
final Volume created = docker.createVolume();
final Volume volume = docker.inspectVolume("volumeName");
By name
docker.removeVolume("volumeName");
Or by object reference
docker.removeVolume(volume);
To mount a host directory into a container, create the container with a HostConfig
.
You can set the local path and remote path in the binds()
method on the
HostConfig.Builder
.
There are two ways to make a bind:
- Pass
binds()
a set of strings of the form"local_path:container_path"
for read/write or"local_path:container_path:ro"
for read only. - Create a
Bind
object and pass it tobinds()
When you create a Bind
, you are making a connection from outside the container
to inside; as such, you must give a Bind
object a from
and a to
. from
can be given either by a String
containing the path to a local file or directory,
or a pre-existing Volume
object. to
must be a String
containing the path to
be bound inside the container.
If you only need to create a volume to be mounted in a container, but you don't
need it to be bound to any particular directory on the host, you can use the
ContainerConfig.Builder.volumes("/path")
method. The path you give to this
method will be created inside the container, but does not correspond to anything
outside.
Bind bindA = Bind.from("/another/local/path")
.to("/another/remote/path")
.readOnly(true)
.build();
Bind bindB = Bind.from(aVolume)
.to("/yet/another/remote/path")
.readOnly(false)
.build();
Bind bindC = Bind.builder().from("/local/path").to("/remote/path").build();
final HostConfig hostConfig =
HostConfig.builder()
.binds(bindA, bindB, bindC)
.build();
final ContainerConfig volumeConfig =
ContainerConfig.builder()
.image("busybox:latest")
.volumes("/foo") // This volume will not mount any host directory
.hostConfig(hostConfig)
.build();
final RegistryAuth registryAuth = RegistryAuth.builder()
.email(AUTH_EMAIL)
.username(AUTH_USERNAME)
.password(AUTH_PASSWORD)
.build();
final int statusCode = docker.auth(registryAuth);
assertThat(statusCode, equalTo(200));
final Info info = docker.info();
final Version version = docker.version();
final String pingResponse = docker.ping();
assertThat(pingResponse, equalTo("OK"));
// Pull image
docker.pull("busybox:latest");
// Create container
final ContainerConfig config = ContainerConfig.builder()
.image("busybox:latest")
.build();
final String name = randomName();
final ContainerCreation creation = docker.createContainer(config, name);
final String id = creation.id();
final String tag = "foobar";
final ContainerCreation newContainer = docker.commitContainer(
id, "mosheeshel/busybox", tag, config, "CommitedByTest-" + tag, "newContainer");
final ImageInfo imageInfo = docker.inspectImage(newContainer.id());
assertThat(imageInfo.author(), is("newContainer"));
assertThat(imageInfo.comment(), is("CommitedByTest-" + "foobar"));
docker.pull("busybox:latest");
final EventStream eventStream = docker.events();
final ContainerConfig config = ContainerConfig.builder()
.image("busybox:latest")
.build();
final ContainerCreation container = docker.createContainer(config, randomName());
docker.startContainer(container.id());
final Event createEvent = eventStream.next();
assertThat(createEvent.status(), equalTo("create"));
assertThat(createEvent.id(), equalTo(container.id()));
assertThat(createEvent.from(), startsWith("busybox:"));
assertThat(createEvent.time(), notNullValue());
final Event startEvent = eventStream.next();
assertThat(startEvent.status(), equalTo("start"));
assertThat(startEvent.id(), equalTo(container.id()));
assertThat(startEvent.from(), startsWith("busybox:"));
assertThat(startEvent.time(), notNullValue());
eventStream.close();
final File imageFile = save(BUSYBOX);
assertTrue(imageFile.length() > 0);
final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
assertTrue("Temp directory " + tmpDir.getAbsolutePath() + " does not exist", tmpDir.exists());
final File imageFile = new File(tmpDir, "busybox-" + System.nanoTime() + ".tar");
imageFile.createNewFile();
imageFile.deleteOnExit();
final byte[] buffer = new byte[2048];
int read;
try (OutputStream imageOutput = new BufferedOutputStream(new FileOutputStream(imageFile))) {
try (InputStream imageInput = docker.save("busybox")) {
while ((read = imageInput.read(buffer)) > -1) {
imageOutput.write(buffer, 0, read);
}
}
}
try (InputStream imageInput = docker.saveMultiple("image0", "image1")) {
while ((read = imageInput.read(buffer)) > -1) {
// Do stuff with the tar stream of images
}
}
final File tarFileWithMultipleImages = new File("/path/to/tarball");
try (InputStream imagePayload = new BufferedInputStream(new FileInputStream(tarFileWithMultipleImages))) {
docker.load(InputStream imagePayload);
}
final String execId = docker.execCreate(containerId, new String[]{"sh", "-c", "exit 2"}).id();
try (final LogStream stream = docker.execStart(execId)) {
stream.readFully();
}
final ExecState state = docker.execInspect(execId);
assertThat(state.id(), is(execId));
assertThat(state.running(), is(false));
assertThat(state.exitCode(), is(2));
assertThat(state.openStdin(), is(true));
assertThat(state.openStderr(), is(true));
assertThat(state.openStdout(), is(true));
}
See example above.
final int height = 10;
final int width = 10;
docker.execResizeTty("execID", height, width);
See example above.
docker-client communicates with your local Docker daemon using the HTTP Remote API and any unexpected errors that the daemon encounters will be reported as a 500 Internal Server Error, which bubbles up from docker-client as an exception like:
Caused by: org.mandas.docker.client.shaded.javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
Check the Docker daemon log (typically at /var/log/docker.log
or
/var/log/upstart/docker.log
) for more details as to the root cause.