Skip to content

Latest commit

 

History

History
679 lines (520 loc) · 19.9 KB

user_manual.md

File metadata and controls

679 lines (520 loc) · 19.9 KB

User Manual

This user manual is made to correspond to Docker's API docs (e.g. API 1.18).

Creating a docker-client

// Create a client based on DOCKER_HOST and DOCKER_CERT_PATH env vars
final DockerClient docker = DefaultDockerClient.fromEnv().build();

// or use the builder
final DockerClient docker = DefaultDockerClient.builder()
  // Set various options
  .build();

Both DefaultDockerClient.builder() and DefaultDockerClient.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

Unix socket support is available on Linux since v2.5.0:

final DockerClient docker = new DefaultDockerClient("unix:///var/run/docker.sock");

HTTPS support

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 = DefaultDockerClient.builder()
    .uri(URI.create("https://boot2docker:2376"))
    .dockerCertificates(new DockerCertificates(Paths.get("/Users/rohan/.docker/boot2docker-vm/")))
    .build();

Connection pooling

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 = DefaultDockerClient.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 to private registries

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.NoOpRegistryAuthSupplier which uses a fixed instance of the RegistryAuth and RegistryConfigs POJOs
  • auth.gcr.ContainerRegistryAuthSupplier, which programmatically fetches access tokens for use with Google Container Registry based on given Gogole Cloud account credentials
  • auth.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.

Containers

List containers

final List<Container> containers = docker.listContainers();

// List all containers. Only running containers are shown by default.
final List<Container> containers = docker.listContainers(ListContainersParam.allContainers());

Create a container

final ContainerCreation container = docker.createContainer(ContainerConfig.builder().build());

Inspect a container

final ContainerInfo info = docker.inspectContainer("containerID");

List processes running inside a container

final TopResults topResults = docker.topContainer("containerID", "ps_args");

Get container logs

final String logs;
try (LogStream stream = client.logs("containerID", LogsParam.stdout(), LogsParam.stderr())) {
  logs = stream.readFully();
}

Inspect changes on a container's filesystem

final List<ContainerChange> changes = docker.inspectContainerChanges("containerId");

Export a container

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());
  }
}

Get container stats based on resource usage

final ContainerStats stats = docker.stats("containerID");

Resize a container TTY

final int height = 10;
final int width = 10;
docker.resizeTty("containerID", height, width);

Start a container

docker.startContainer("containerID");

Stop a container

docker.stopContainer("containerID", 10); // kill after 10 seconds

Restart a container

docker.restartContainer("containerID");
// or with a seconds to wait before restarting parameter
docker.restartContainer("containerID", 10);

Kill a container

docker.killContainer("containerID");

Rename a container

docker.renameContainer("oldContainerID", "newContainerID");

Pause a container

docker.pauseContainer("containerID");

Unpause a container

docker.unpauseContainer("containerID");

Attach to a container

final String logs;
try (LogStream stream = docker.attachContainer(volumeContainer,
      AttachParameter.LOGS, AttachParameter.STDOUT,
      AttachParameter.STDERR, AttachParameter.STREAM)) {
  logs = stream.readFully();
}

Attach to a container (websocket)

Not implemented. PRs welcome.

Wait a container

final ContainerExit exit = docker.waitContainer("containerID");

Remove a container

docker.removeContainer("containerID");

Copy files or folders from a container

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());
  }
}

Retrieving information about files and folders in a container

Not implemented. PRs welcome.

Get an archive of a filesystem resource in a container

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
  }
}

Extract an archive of files or folders to a directory in a container

docker.copyToContainer("/local/path", "containerID", "/path/in/container");

Secrets

Create secret

final SecretSpec secret = SecretSpec.builder().name("asecret").data(base64encodeddata).build();
docker.createSecret(secret);

Images

List images

final List<Image> quxImages = docker.listImages(ListImagesParam.withLabel("foo", "qux"));

Build image from a Dockerfile

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);
        }
      }
    });

Create an image

// 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);
}

Inspect an image

final ImageInfo info = docker.inspectImage("imageID")

Get the history of an image

final List<ImageHistory> imageHistoryList = docker.history("imageID");

Push an image on the registry

docker.push("imageID");

Tag an image into a repository

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);

Remove an image

docker.removeImage("imageID");

Search images

final List<ImageSearchResult> searchResult = docker.searchImages("busybox");

Miscellaneous

Check auth configuration

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));

Display system-wide information

final Info info = docker.info();

Show the docker version information

final Version version = docker.version();

Ping the docker server

final String pingResponse = docker.ping();
assertThat(pingResponse, equalTo("OK"));

Create a new image from a container's changes

// 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"));

Monitor Docker's events

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();

Get a tarball containing all images in a repository

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);
    }
  }
}

Get a tarball containing all images.

try (InputStream imageInput = docker.saveMultiple("image0", "image1")) {
    while ((read = imageInput.read(buffer)) > -1) {
      // Do stuff with the tar stream of images
    }
}

Load a tarball with a set of images and tags into docker

final File tarFileWithMultipleImages = new File("/path/to/tarball");
try (InputStream imagePayload = new BufferedInputStream(new FileInputStream(tarFileWithMultipleImages))) {
  docker.load(InputStream imagePayload);
}

Exec Create

final String execId = docker.execCreate(containerId, new String[]{"sh", "-c", "exit 2"});

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));
}

Exec Start

See example above.

Exec Resize

final int height = 10;
final int width = 10;
docker.execResizeTty("execID", height, width);

Exec Inspect

See example above.

Volumes

List volumes

final VolumeList volumeList = docker.listVolumes();
final List<String> warnings = volumeList.warnings();
final List<Volume> volumes = volumeList.volumes();

Create a volume

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();

Inspect a volume

final Volume volume = docker.inspectVolume("volumeName");

Remove a volume

By name

docker.removeVolume("volumeName");

Or by object reference

docker.removeVolume(volume);

Going Further

Mounting directories in a container

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:

  1. 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.
  2. Create a Bind object and pass it to binds() (or appendBinds() if you want to incrementally add multiple Binds).

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.

final HostConfig hostConfig =
  HostConfig.builder()
    .appendBinds("/local/path:/remote/path")
    .appendBinds(Bind.from("/another/local/path")
               .to("/another/remote/path")
               .readOnly(true)
               .build())
    .appendBinds(Bind.from(aVolume)
               .to("/yet/another/remote/path")
               .readOnly(false)
               .build())
    .build();
final ContainerConfig volumeConfig =
  ContainerConfig.builder()
    .image("busybox:latest")
    .volumes("/foo")   // This volume will not mount any host directory
    .hostConfig(hostConfig)
    .build();

A note on mounts

Be aware that, starting with API version 1.20 (docker version 1.8.x), information about a container's volumes is returned with the key "Mounts", not "Volumes". As such, the ContainerInfo.volumes() method is deprecated. Instead, use ContainerInfo.mounts().

Troubleshooting

HTTP 500 errors returned from the Docker Remote API

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: com.spotify.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.