Un guide Docker pour Java

1. Vue d'ensemble

Dans cet article, nous examinons une autre API spécifique à une plate-forme bien établie: Java API Client for Docker .

Tout au long de l'article, nous comprenons comment se connecter à un démon Docker en cours d'exécution et quel type de fonctionnalités importantes l'API offre aux développeurs Java.

2. Dépendance de Maven

Tout d'abord, nous devons ajouter la dépendance principale dans notre fichier pom.xml :

 com.github.docker-java docker-java 3.0.14 

Au moment de la rédaction de l'article, la dernière version de l'API est la 3.0.14 . Chaque version peut être consultée à partir de la page de publication de GitHub ou du référentiel Maven.

3. Utilisation du client Docker

DockerClient est l'endroit où nous pouvons établir une connexion entre un moteur / démon Docker et notre application.

Par défaut, le démon Docker ne peut être accessible que dans le fichier unix: ///var/run/docker.sock . Nous pouvons communiquer localement avec le moteur Docker en écoute sur le socket Unix, sauf configuration contraire .

Ici, nous appliquons à la classe DockerClientBuilder pour créer une connexion en acceptant les paramètres par défaut:

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

De même, nous pouvons ouvrir une connexion en deux étapes:

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

Étant donné que les moteurs peuvent s'appuyer sur d'autres caractéristiques, le client est également configurable avec différentes conditions.

Par exemple, le constructeur accepte une URL de serveur, c'est-à-dire que nous pouvons mettre à jour la valeur de connexion si le moteur est disponible sur le port 2375 :

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

Notez que nous devons ajouter au début de la chaîne de connexion unix: // ou tcp: // selon le type de connexion.

Si nous allons plus loin, nous pouvons nous retrouver avec une configuration plus avancée en utilisant la classe DefaultDockerClientConfig :

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

De même, nous pouvons réaliser la même approche en utilisant Properties :

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

Un autre choix, sauf si nous configurons les paramètres du moteur dans le code source, est de définir les variables d'environnement correspondantes afin que nous ne puissions considérer que l'instanciation par défaut de DockerClient dans le projet:

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. Gestion des conteneurs

L'API nous permet une variété de choix concernant la gestion des conteneurs. Regardons chacun d'eux.

4.1. Liste des conteneurs

Maintenant que nous avons une connexion établie, nous pouvons lister tous les conteneurs en cours d'exécution situés sur l'hôte Docker:

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

À condition que l'affichage des conteneurs en cours d'exécution ne répond pas aux besoins, nous pouvons utiliser les options proposées pour interroger les conteneurs.

Dans ce cas, nous affichons les conteneurs avec le statut «sorti»:

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

C'est l'équivalent de:

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

4.2. Créer un conteneur

La création d'un conteneur est servie avec la méthode createContainerCmd . Nous pouvons déclarer une déclaration plus complexe en utilisant les méthodes disponibles en commençant par le préfixe « avec» .

Supposons que nous ayons une commande docker create définissant un conteneur MongoDB dépendant de l'hôte écoutant en interne sur le port 27017:

$ 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

Nous sommes en mesure de démarrer le même conteneur avec ses configurations par programme:

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. Démarrer, arrêter et tuer un conteneur

Une fois que nous avons créé le conteneur, nous pouvons le démarrer, l'arrêter et le tuer par son nom ou son identifiant respectivement:

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

4.4. Inspecter un conteneur

La méthode inspectContainerCmd prend un argument String qui indique le nom ou l'ID d'un conteneur. En utilisant cette méthode, nous pouvons observer directement les métadonnées d'un conteneur:

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

4.5. Instantané d'un conteneur

Semblable à la commande docker commit , nous pouvons créer une nouvelle image à l'aide de la méthode commitCmd .

Dans notre exemple, le scénario est , nous avons précédemment exécuté un conteneur alpine: 3.6 dont l'id est «3464bb547f88» et installé git par-dessus.

Maintenant, nous voulons créer un nouvel instantané d'image à partir du conteneur:

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

Puisque notre nouvelle image fournie avec git reste sur l'hôte, nous pouvons la rechercher sur l'hôte Docker:

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

5. Gestion des images

Il existe quelques commandes applicables qui nous sont données pour gérer les opérations sur les images.

5.1. Liste des images

Pour répertorier toutes les images disponibles, y compris les images pendantes sur l'hôte Docker, nous devons appliquer à la méthode listImagesCmd :

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

Si nous avons deux images sur notre hôte Docker, nous devrions en obtenir les objets Image au moment de l'exécution . Les images que nous recherchons sont:

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

À côté de cela, pour voir les images intermédiaires, nous devons le demander explicitement:

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

Si seulement l'affichage des images pendantes est le cas, la méthode withDanglingFilter doit être considérée:

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.

Tous les exemples illustrés dans cet article se trouvent à l'adresse over sur GitHub.