Un guide Docker pour Java

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 cet article, nous apprenons comment connecter un démon Docker en cours d'exécution et quel type de fonctionnalité importante l'API offre aux développeurs Java.

2. Dépendance Maven

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


    com.github.docker-java
    docker-java
    3.0.14

Au moment de la rédaction de l'article,the latest version of the API is 3.0.14. Chaque version peut être visualisée à partir dethe GitHub release page ou dethe Maven repository.

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 fichierunix:///var/run/docker.sock. Nous pouvons communiquer localement avecthe Docker engine listening on the Unix socket unless otherwise configured.

Ici, nous appliquons à la classeDockerClientBuilder 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();

Les moteurs pouvant s’appuyer sur d’autres caractéristiques, le client est également configurable avec différentes conditions.

Par exemple, le générateur accepte une URL de serveur, c'est-à-direwe can update the connection value if the engine is available on port 2375:

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

Notez que nous devons ajouterthe connection string with unix:// or tcp:// depending on the connection type.

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

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

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

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

Properties properties = new Properties();
properties.setProperty("registry.email", "[email protected]");
properties.setProperty("registry.password", "example");
properties.setProperty("registry.username", "baaldung");
properties.setProperty("DOCKER_CERT_PATH", "/home/example/.docker/certs");
properties.setProperty("DOCKER_CONFIG", "/home/example/.docker/");
properties.setProperty("DOCKER_TLS_VERIFY", "1");
properties.setProperty("DOCKER_HOST", "tcp://docker.example.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 deDockerClient dans le projet:

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

4. Gestion des conteneurs

L'API nous permet une variété de choix en matière de gestion de conteneurs. Regardons chacun d’eux.

4.1. Liste des conteneurs

Maintenant que la connexion est établie, nous pouvons répertorier tous les conteneurs en cours d’exécution situés sur l’hôte Docker:

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

Dans la mesure où 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 “quitté”:

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éthodecreateContainerCmd. Nous pouvons déclarer une déclaration plus complexeusingthe available methods starting with the “with” prefix.

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

$ docker create --name mongo \
  --hostname=example \
  -e MONGO_LATEST_VERSION=3.6 \
  -p 9999:27017 \
  -v /Users/example/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 programmation:

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

4.3. Démarrer, arrêter et tuer un conteneur

Une fois le conteneur créé, 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éthodeinspectContainerCmd prend un argumentString qui indique le nom ou l'ID d'un conteneur. En utilisant cette méthode, nous pouvons observer les métadonnées d'un conteneur directement:

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

4.5. Instantané d'un conteneur

Similaire à la commandedocker commit, nous pouvons créer une nouvelle image en utilisant la méthodecommitCmd.

Dans notre exemple, le scénario est, we previously run an alpine:3.6 container whose id is “3464bb547f88” and installed git on top of it.

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

String snapshotId = dockerClient.commitCmd("3464bb547f88")
  .withAuthor("example <[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 avecgit 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

Quelques commandes applicables nous sont données pour gérer les opérations sur les images.

5.1. Liste des images

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

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

Si nous avons deux images sur notre hôte Docker,we should obtain the Image objects of them at run-time. Les images que nous recherchons sont:

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

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

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

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

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

5.2. Créer une image

Concentrons-nous sur la manière de créer une image à l'aide de l'API. The buildImageCmd method builds Docker images from a Dockerfile. Dans notre projet, nous avons déjà un fichier Docker qui fournit une image Alpine avec git installé:

FROM alpine:3.6

RUN apk --update add git openssh && \
  rm -rf /var/lib/apt/lists/* && \
  rm /var/cache/apk/*

ENTRYPOINT ["git"]
CMD ["--help"]

La nouvelle image sera construite sans utiliser de cache et avant de commencer le processus de construction, dans tous les cas, le moteur Docker tentera d'extraire la nouvelle version dealpine: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. Inspecter une image

Nous pouvons inspecter les informations de bas niveau sur une image grâce à la méthodeinspectImageCmd:

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

5.4. Marquer une image

Ajouter une balise à notre image est assez simple en utilisant la commandedockertag, donc l'API ne fait pas exception. Nous pouvons également réaliser la même intention avec la méthodetagImageCmd. To tag a Docker image with id 161714540c41 into the example/alpine repository with git:

String imageId = "161714540c41";
String repository = "example/alpine";
String tag = "git";

dockerClient.tagImageCmd(imageId, repository, tag).exec();

Nous listerions l’image nouvellement créée, et la voici:

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

5.5. Pousser une image

Avant d'envoyer une image à un service de registre, le client docker doit être configuré pour coopérer avec le service, car le travail avec des registres doit être authentifié à l'avance.

Puisque nous supposons que le client a été configuré avec Docker Hub, nous pouvons pousser l'imageexample/alpine vers l'exemple de compte DockerHub:

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

We must abide by the duration of the process. Dans l'exemple,we are waiting 90 seconds.

5.6. Tirez une image

Pour télécharger des images à partir des services de registre, nous utilisons la méthodepullImageCmd. De plus, si l'image extraite d'un registre privé, le client doit connaître nos informations d'identification, sans quoi le processus aboutira à un échec. Same as the pulling an image, we specify a callback along with a fixed period to pull an image:

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

Pour vérifier si l'image mentionnée existe sur l'hôte Docker après l'avoir extraite:

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

5.7. Supprimer une image

Une autre fonction simple parmi les autres est la méthoderemoveImageCmd. Nous pouvons supprimer une image avec son identifiant court ou long:

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

5.8. Rechercher dans le registre

Pour rechercher une image à partir de Docker Hub, le client est livré avec la méthodesearchImagesCmd prenant une valeur String qui indique un terme. Ici, nous explorons les images liées à un nom contenant «Java' dans Docker Hub:

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

La sortie renvoie les 25 premières images associées dans une liste d'objetsSearchItem.

6. Gestion du volume

Si les projets Java doivent interagir avec Docker pour les volumes, vous devez également prendre en compte cette section. Briefly, we look at the fundamental techniques of volumes provided by the Docker Java API.

6.1. Lister les volumes

Tous les volumes disponibles, nommés et non nommés, sont répertoriés avec:

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

6.2. Inspecter un volume

La méthodeinspectVolumeCmd est le formulaire pour afficher les informations détaillées d'un volume. Nous inspectons le volume en spécifiant son identifiant court:

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

6.3. Créer un volume

L'API sert deux options différentes pour créer un volume. La méthode non-argcreateVolumeCmd crée un volume dont le nom est donné par Docker:

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

Plutôt que d'utiliser le comportement par défaut, la méthode d'assistance appeléewithName nous permet de donner un nom à un volume:

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

6.4. Supprimer un volume

Nous pouvons supprimer intuitivement un volume de l'hôte Docker en utilisant la méthoderemoveVolumeCmd. What is important to note that we cannot delete a volume if it is in use from a container. Nous supprimons le volume,myNamedVolume, de la liste des volumes:

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

7. La gestion du réseau

Notre dernière section concerne la gestion des tâches réseau avec l’API.

7.1. Répertorier les réseaux

Nous pouvons afficher la liste des unités réseau avec l'une des méthodes API conventionnelles commençant parlist:

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

7.2. Créer un réseau

L'équivalent de la commandedocker network create est exécuté avec la méthodecreateNetworkCmd. Si nous avons un pilote réseau trente parties ou personnalisé, la méthodewithDriver peut les accepter en plus des pilotes intégrés. Dans notre cas, créons un réseau pont dont le nom estexample:

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

De plus, la création d’une unité réseau avec les paramètres par défaut ne résout pas le problème, nous pouvons demander d’autres méthodes d’assistance pour construire un réseau avancé. Ainsi,to override the default subnetwork with a custom value:

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

La même commande que nous pouvons exécuter avec la commandedocker est:

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

7.3. Inspecter un réseau

L'affichage des détails de bas niveau d'un réseau est également couvert par l'API:

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

7.4. Supprimer un réseau

Nous pouvons supprimer en toute sécurité une unité réseau avec son nom ou son identifiant en utilisant la méthoderemoveNetworkCmd:

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

8. Conclusion

Dans ce didacticiel détaillé, nous avons exploré les diverses fonctionnalités desJava Docker API Client, ainsi que plusieurs approches d'implémentation pour les scénarios de déploiement et de gestion.

Tous les exemples illustrés dans cet article peuvent être trouvésover on GitHub.