Ein Docker-Handbuch für Java

1. Übersicht

In diesem Artikel werfen wir einen Blick auf eine andere gut etablierte plattformspezifische API - Java API Client for Docker .

In diesem Artikel erfahren Sie, wie Sie eine Verbindung zu einem laufenden Docker-Daemon herstellen und welche wichtigen Funktionen die API Java-Entwicklern bietet.

2. Maven-Abhängigkeit

Zuerst müssen wir die Hauptabhängigkeit in unsere Datei pom.xml einfügen :

 com.github.docker-java docker-java 3.0.14 

Zum Zeitpunkt des Schreibens des Artikels ist die neueste Version der API 3.0.14 . Jede Version kann entweder auf der GitHub-Veröffentlichungsseite oder im Maven-Repository angezeigt werden.

3. Verwenden des Docker-Clients

In DockerClient können wir eine Verbindung zwischen einer Docker-Engine / einem Docker-Daemon und unserer Anwendung herstellen.

Standardmäßig kann auf den Docker-Dämon nur unter der Datei unix: ///var/run/docker.sock zugegriffen werden. Sofern nicht anders konfiguriert, können wir lokal mit der Docker-Engine kommunizieren, die den Unix-Socket überwacht .

Hier wenden wir auf die DockerClientBuilder- Klasse an, um eine Verbindung herzustellen, indem wir die Standardeinstellungen akzeptieren:

DockerClient dockerClient = DockerClientBuilder.getInstance().build();

Ebenso können wir eine Verbindung in zwei Schritten öffnen:

DefaultDockerClientConfig.Builder config = DefaultDockerClientConfig.createDefaultConfigBuilder(); DockerClient dockerClient = DockerClientBuilder .getInstance(config) .build();

Da sich Motoren auf andere Eigenschaften stützen können, kann der Client auch unter anderen Bedingungen konfiguriert werden.

Der Builder akzeptiert beispielsweise eine Server-URL. Das heißt, wir können den Verbindungswert aktualisieren, wenn die Engine an Port 2375 verfügbar ist :

DockerClient dockerClient = DockerClientBuilder.getInstance("tcp://docker.baeldung.com:2375").build();

Beachten Sie, dass wir der Verbindungszeichenfolge je nach Verbindungstyp Unix: // oder TCP: // voranstellen müssen .

Wenn wir noch einen Schritt weiter gehen, können wir mit der DefaultDockerClientConfig- Klasse eine erweiterte Konfiguration erhalten :

DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withRegistryEmail("[email protected]") .withRegistryPassword("baeldung") .withRegistryUsername("baeldung") .withDockerCertPath("/home/baeldung/.docker/certs") .withDockerConfig("/home/baeldung/.docker/") .withDockerTlsVerify("1") .withDockerHost("tcp://docker.baeldung.com:2376").build(); DockerClient dockerClient = DockerClientBuilder.getInstance(config).build();

Ebenso können wir den gleichen Ansatz mit Eigenschaften ausführen :

Properties properties = new Properties(); properties.setProperty("registry.email", "[email protected]"); properties.setProperty("registry.password", "baeldung"); properties.setProperty("registry.username", "baaldung"); properties.setProperty("DOCKER_CERT_PATH", "/home/baeldung/.docker/certs"); properties.setProperty("DOCKER_CONFIG", "/home/baeldung/.docker/"); properties.setProperty("DOCKER_TLS_VERIFY", "1"); properties.setProperty("DOCKER_HOST", "tcp://docker.baeldung.com:2376"); DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withProperties(properties).build(); DockerClient dockerClient = DockerClientBuilder.getInstance(config).build();

Eine andere Möglichkeit, sofern wir die Einstellungen der Engine nicht im Quellcode konfigurieren, besteht darin, entsprechende Umgebungsvariablen festzulegen, sodass nur die Standardinstanziierung von DockerClient im Projekt berücksichtigt werden kann :

export DOCKER_CERT_PATH=/home/baeldung/.docker/certs export DOCKER_CONFIG=/home/baeldung/.docker/ export DOCKER_TLS_VERIFY=1 export DOCKER_HOST=tcp://docker.baeldung.com:2376

4. Containerverwaltung

Die API ermöglicht uns eine Vielzahl von Möglichkeiten zur Containerverwaltung. Schauen wir uns jeden einzelnen an.

4.1. Container auflisten

Nachdem wir eine Verbindung hergestellt haben, können wir alle laufenden Container auf dem Docker-Host auflisten:

List containers = dockerClient.listContainersCmd().exec();

Sofern das Anzeigen der laufenden Container nicht den Anforderungen entspricht, können wir die angebotenen Optionen zum Abfragen von Containern verwenden.

In diesem Fall zeigen wir Container mit dem Status "Beendet" an:

List containers = dockerClient.listContainersCmd() .withShowSize(true) .withShowAll(true) .withStatusFilter("exited").exec()

Es ist ein Äquivalent von:

$ docker ps -a -s -f status=exited # or $ docker container ls -a -s -f status=exited

4.2. Erstellen Sie einen Container

Das Erstellen eines Containers wird mit der Methode createContainerCmd bereitgestellt . Wir können komplexere Deklarationen mit den verfügbaren Methoden deklarieren , beginnend mit dem Präfix " with" .

Nehmen wir an, wir haben einen Docker- Erstellungsbefehl , der einen hostabhängigen MongoDB-Container definiert, der intern Port 27017 überwacht:

$ docker create --name mongo \ --hostname=baeldung \ -e MONGO_LATEST_VERSION=3.6 \ -p 9999:27017 \ -v /Users/baeldung/mongo/data/db:/data/db \ mongo:3.6 --bind_ip_all

Wir können denselben Container zusammen mit seinen Konfigurationen programmgesteuert booten:

CreateContainerResponse container = dockerClient.createContainerCmd("mongo:3.6") .withCmd("--bind_ip_all") .withName("mongo") .withHostName("baeldung") .withEnv("MONGO_LATEST_VERSION=3.6") .withPortBindings(PortBinding.parse("9999:27017")) .withBinds(Bind.parse("/Users/baeldung/mongo/data/db:/data/db")).exec();

4.3. Starten, Stoppen und Töten eines Containers

Sobald wir den Container erstellt haben, können wir ihn nach Namen bzw. ID starten, stoppen und beenden:

dockerClient.startContainerCmd(container.getId()).exec(); dockerClient.stopContainerCmd(container.getId()).exec(); dockerClient.killContainerCmd(container.getId()).exec();

4.4. Untersuchen Sie einen Behälter

Die inspectContainerCmd- Methode verwendet ein String- Argument, das den Namen oder die ID eines Containers angibt. Mit dieser Methode können wir die Metadaten eines Containers direkt beobachten:

InspectContainerResponse container = dockerClient.inspectContainerCmd(container.getId()).exec();

4.5. Schnappschuss eines Containers

Ähnlich wie beim Befehl docker commit können wir mit der Methode commitCmd ein neues Image erstellen .

In unserem Beispiel haben wir zuvor einen alpine: 3.6-Container mit der ID "3464bb547f88" ausgeführt und git darüber installiert .

Jetzt möchten wir einen neuen Bildschnappschuss aus dem Container erstellen:

String snapshotId = dockerClient.commitCmd("3464bb547f88") .withAuthor("Baeldung <[email protected]>") .withEnv("SNAPSHOT_YEAR=2018") .withMessage("add git support") .withCmd("git", "version") .withRepository("alpine") .withTag("3.6.git").exec();

Da unser neues mit git gebündeltes Image auf dem Host verbleibt, können wir es auf dem Docker-Host suchen:

$ docker image ls alpine --format "table {{.Repository}} {{.Tag}}" REPOSITORY TAG alpine 3.6.git

5. Bildverwaltung

Es gibt einige anwendbare Befehle zum Verwalten von Bildoperationen.

5.1. Bilder auflisten

Um alle verfügbaren Bilder einschließlich der baumelnden Bilder auf dem Docker-Host aufzulisten, müssen Sie die Methode listImagesCmd anwenden :

List images = dockerClient.listImagesCmd().exec();

Wenn wir zwei Images auf unserem Docker-Host haben, sollten wir die Image- Objekte zur Laufzeit abrufen . Die Bilder, nach denen wir suchen, sind:

$ docker image ls --format "table {{.Repository}} {{.Tag}}" REPOSITORY TAG alpine 3.6 mongo 3.6

Um die Zwischenbilder zu sehen, müssen wir sie explizit anfordern:

List images = dockerClient.listImagesCmd() .withShowAll(true).exec();

Wenn nur die baumelnden Bilder angezeigt werden sollen, muss die withDanglingFilter- Methode berücksichtigt werden:

List images = dockerClient.listImagesCmd() .withDanglingFilter(true).exec();

5.2. Build an Image

Let's focus on the way of building an image using the API. The buildImageCmd method builds Docker images from a Dockerfile. In our project, we already have one Dockerfile which gives an Alpine image with git installed:

FROM alpine:3.6 RUN apk --update add git openssh && \ rm -rf /var/lib/apt/lists/* && \ rm /var/cache/apk/* ENTRYPOINT ["git"] CMD ["--help"]

The new image will be built without using cache and before starting the building process, in any case, Docker engine will attempt to pull the newer version of alpine:3.6. If everything goes well, we should eventually see the image with the given name,alpine:git:

String imageId = dockerClient.buildImageCmd() .withDockerfile(new File("path/to/Dockerfile")) .withPull(true) .withNoCache(true) .withTag("alpine:git") .exec(new BuildImageResultCallback()) .awaitImageId();

5.3. Inspect an Image

We can inspect the low-level information about an image thanks to the inspectImageCmd method:

InspectImageResponse image = dockerClient.inspectImageCmd("161714540c41").exec();

5.4. Tag an Image

Adding a tag to our image is quite simple using the dockertag command, so the API is no exception. We can carry out the same intention with the tagImageCmd method as well. To tag a Docker image with id 161714540c41 into the baeldung/alpine repository with git:

String imageId = "161714540c41"; String repository = "baeldung/alpine"; String tag = "git"; dockerClient.tagImageCmd(imageId, repository, tag).exec();

We would list the newly created image, and there it is:

$ docker image ls --format "table {{.Repository}} {{.Tag}}" REPOSITORY TAG baeldung/alpine git

5.5. Push an Image

Before sending out an image to a registry service, the docker client must be configured to cooperate with the service because working with registries need to be authenticated in advance.

Since we assume that the client was configured with Docker Hub, we can push the baeldung/alpine image to the baeldung DockerHub account:

dockerClient.pushImageCmd("baeldung/alpine") .withTag("git") .exec(new PushImageResultCallback()) .awaitCompletion(90, TimeUnit.SECONDS);

We must abide by the duration of the process. In the example, we are waiting 90 seconds.

5.6. Pull an Image

To download images from registry services, we make use of the pullImageCmd method. In addition, if the image being pulled from a private registry, the client must know our credential otherwise the process ends up with a failure. Same as the pulling an image, we specify a callback along with a fixed period to pull an image:

dockerClient.pullImageCmd("baeldung/alpine") .withTag("git") .exec(new PullImageResultCallback()) .awaitCompletion(30, TimeUnit.SECONDS);

To check out whether the mentioned image exists on the Docker host after pulling it:

$ docker images baeldung/alpine --format "table {{.Repository}} {{.Tag}}" REPOSITORY TAG baeldung/alpine git

5.7. Remove an Image

Another simple function among the rest is the removeImageCmd method. We can remove an image with its short or long ID:

dockerClient.removeImageCmd("beaccc8687ae").exec();

5.8. Search in Registry

To search an image from Docker Hub, the client comes with the searchImagesCmd method taking a String value which indicates a term. Here, we explore images related to a name containing ‘Java' in Docker Hub:

List items = dockerClient.searchImagesCmd("Java").exec();

The output returns first 25 related images in a list of SearchItem objects.

6. Volume Management

If Java projects need to interact with Docker for volumes, we should also take into account this section. Briefly, we look at the fundamental techniques of volumes provided by the Docker Java API.

6.1. List Volumes

All of the available volumes including named and unnamed are listed with:

ListVolumesResponse volumesResponse = dockerClient.listVolumesCmd().exec(); List volumes = volumesResponse.getVolumes();

6.2. Inspect a Volume

The inspectVolumeCmd method is the form to show the detailed information of a volume. We inspect the volume by specifying its short id:

InspectVolumeResponse volume = dockerClient.inspectVolumeCmd("0220b87330af5").exec();

6.3. Create a Volume

The API serves two different options to create a volume. The non-arg createVolumeCmd method creates a volume where the name is given by Docker:

CreateVolumeResponse unnamedVolume = dockerClient.createVolumeCmd().exec();

Rather than using the default behavior, the helper method called withName lets us set a name to a volume:

CreateVolumeResponse namedVolume = dockerClient.createVolumeCmd().withName("myNamedVolume").exec();

6.4. Remove a Volume

We can intuitively delete a volume from the Docker host using the removeVolumeCmd method. What is important to note that we cannot delete a volume if it is in use from a container. We remove the volume, myNamedVolume, from the volume list:

dockerClient.removeVolumeCmd("myNamedVolume").exec();

7. Network Management

Our last section is about managing network tasks with the API.

7.1. List Networks

We can display the list of network units with one of the conventional API methods starting with list:

List networks = dockerClient.listNetworksCmd().exec();

7.2. Create a Network

The equivalent of the docker network create command is conducted with the createNetworkCmd method. If we have a thirty party or a custom network driver, the withDriver method can accept them besides the built-in drivers. In our case, let's create a bridge network whose name is baeldung:

CreateNetworkResponse networkResponse = dockerClient.createNetworkCmd() .withName("baeldung") .withDriver("bridge").exec();

Furthermore, creating a network unit with the default settings doesn't solve the problem, we can apply for other helper methods to construct an advanced network. Thus, to override the default subnetwork with a custom value:

CreateNetworkResponse networkResponse = dockerClient.createNetworkCmd() .withName("baeldung") .withIpam(new Ipam() .withConfig(new Config() .withSubnet("172.36.0.0/16") .withIpRange("172.36.5.0/24"))) .withDriver("bridge").exec();

The same command we can run with the docker command is:

$ docker network create \ --subnet=172.36.0.0/16 \ --ip-range=172.36.5.0/24 \ baeldung

7.3. Inspect a Network

Displaying the low-level details of a network is also covered in the API:

Network network = dockerClient.inspectNetworkCmd().withNetworkId("baeldung").exec();

7.4. Remove a Network

We can safely remove a network unit with its name or id using the removeNetworkCmd method:

dockerClient.removeNetworkCmd("baeldung").exec();

8. Conclusion

In this extensive tutorial, we explored the various diverse functionality of the Java Docker API Client, along with several implementation approaches for deployment and management scenarios.

Alle in diesem Artikel dargestellten Beispiele finden Sie auf GitHub.