Ein Docker Guide für Java

Ein Docker-Handbuch für Java

1. Überblick

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 aktiven Docker-Daemon herstellen und welche wichtigen Funktionen die API für Java-Entwickler bietet.

2. Maven-Abhängigkeit

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


    com.github.docker-java
    docker-java
    3.0.14

Zum Zeitpunkt des Schreibens des Artikels warenthe latest version of the API is 3.0.14. Jede Version kann entweder vonthe GitHub release page oder vonthe Maven repository angezeigt werden.

3. Verwenden des Docker-Clients

InDockerClient 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 über die Dateiunix:///var/run/docker.sockzugegriffen werden. Wir können lokal mitthe Docker engine listening on the Unix socket unless otherwise configured kommunizieren.

Hier wenden wir auf die KlasseDockerClientBuilderan, um eine Verbindung herzustellen, indem wir die Standardeinstellungen akzeptieren:

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

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

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

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

Der Builder akzeptiert beispielsweise eine Server-URL, dhwe can update the connection value if the engine is available on port 2375:

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

Beachten Sie, dass wirthe connection string with unix:// or tcp:// depending on the connection type. voranstellen müssen

Wenn wir noch einen Schritt weiter gehen, können wir mit der KlasseDefaultDockerClientConfigeine erweiterte Konfiguration erhalten:

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

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

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

Eine andere Möglichkeit, sofern wir die Einstellungen der Engine nicht im Quellcode konfigurieren, besteht darin, entsprechende Umgebungsvariablen festzulegen, sodass wir nur die Standardinstanziierung vonDockerClient im Projekt berücksichtigen können:

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. Containermanagement

Die API ermöglicht uns eine Vielzahl von Optionen zum Containermanagement. Schauen wir uns jeden einzelnen an.

4.1. Container auflisten

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

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 nutzen.

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

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

Dies entspricht:

$ 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 MethodecreateContainerCmdbedient. Wir können eine komplexere Deklarationusingthe available methods starting with the “with” prefix deklarieren.

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

$ 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

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("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. Starten, Stoppen und Töten eines Containers

Sobald wir den Container erstellt haben, können wir ihn mit dem Namen oder der 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 MethodeinspectContainerCmd verwendet ein ArgumentString, 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 Befehldocker commit können wir mit der MethodecommitCmd ein neues Bild erstellen.

In unserem Beispiel ist das Szenario, we previously run an alpine:3.6 container whose id is “3464bb547f88” and installed git on top of it.

Nun wollen wir einen neuen Image-Snapshot aus dem Container erstellen:

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

Da unser neues mitgit 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, die wir zum Verwalten von Bildvorgängen erhalten.

5.1. Bilder auflisten

Um alle verfügbaren Bilder einschließlich der baumelnden Bilder auf dem Docker-Host aufzulisten, müssen wir die MethodelistImagesCmdanwenden:

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

Wenn wir zwei Bilder auf unserem Docker-Host haben,we should obtain the Image objects of them at run-time. Die Bilder, die wir suchen, sind:

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

Um die Zwischenbilder sehen zu können, müssen wir diese explizit anfordern:

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

Wenn nur die baumelnden Bilder angezeigt werden, muss die MethodewithDanglingFilterberücksichtigt werden:

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

5.2. Erstellen Sie ein Bild

Konzentrieren wir uns auf die Art und Weise, wie ein Image mithilfe der API erstellt wird. The buildImageCmd method builds Docker images from a Dockerfile. In unserem Projekt haben wir bereits ein Dockerfile, das ein alpines Image mit installiertem Git liefert:

FROM alpine:3.6

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

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

Das neue Image wird ohne Verwendung des Caches erstellt. Vor dem Start des Erstellungsprozesses versucht die Docker-Engine in jedem Fall, die neuere Version vonalpine:3.6 abzurufen. 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. Überprüfen Sie ein Bild

Dank derinspectImageCmd-Methode können wir die Informationen auf niedriger Ebene über ein Bild überprüfen:

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

5.4. Kennzeichnen Sie ein Bild

Das Hinzufügen eines Tags zu unserem Bild ist mit dem Befehldockertag recht einfach, sodass die API keine Ausnahme darstellt. Die gleiche Absicht können wir auch mit dertagImageCmd-Methode ausführen. 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();

Wir würden das neu erstellte Bild auflisten, und da ist es:

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

5.5. Schieben Sie ein Bild

Bevor Sie ein Image an einen Registrierungsdienst senden, muss der Docker-Client für die Zusammenarbeit mit dem Dienst konfiguriert sein, da die Arbeit mit Registrys vorab authentifiziert werden muss.

Da wir davon ausgehen, dass der Client mit Docker Hub konfiguriert wurde, können wir das Image vonexample/alpineauf das Beispiel-DockerHub-Konto übertragen:

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

We must abide by the duration of the process. Im Beispielwe are waiting 90 seconds.

5.6. Ziehen Sie ein Bild

Zum Herunterladen von Bildern von Registrierungsdiensten verwenden wir diepullImageCmd-Methode. Wenn das Image aus einer privaten Registrierung abgerufen wird, muss der Client außerdem unseren Berechtigungsnachweis kennen, da sonst der Prozess fehlschlägt. 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);

So überprüfen Sie, ob das erwähnte Image auf dem Docker-Host vorhanden ist, nachdem Sie es gezogen haben:

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

5.7. Entfernen Sie ein Bild

Eine weitere einfache Funktion ist unter anderem dieremoveImageCmd-Methode. Wir können ein Bild mit seiner kurzen oder langen ID entfernen:

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

5.8. Suche in der Registrierung

Um ein Bild von Docker Hub aus zu durchsuchen, wird dem Client die MethodesearchImagesCmdmit einem String-Wert geliefert, der einen Begriff angibt. Hier untersuchen wir Bilder, die sich auf einen Namen beziehen, derJava'in Docker Hub enthält:

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

Die Ausgabe gibt die ersten 25 verwandten Bilder in einer Liste vonSearchItem Objekten zurück.

6. Volume Management

Wenn Java-Projekte mit Docker für Volumes interagieren müssen, sollten Sie diesen Abschnitt ebenfalls berücksichtigen. Briefly, we look at the fundamental techniques of volumes provided by the Docker Java API.

6.1. Bände auflisten

Alle verfügbaren Volumes, einschließlich benannter und unbenannter Volumes, werden aufgelistet mit:

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

6.2. Überprüfen Sie ein Volumen

DieinspectVolumeCmd-Methode ist das Formular zum Anzeigen der detaillierten Informationen eines Volumes. Wir untersuchen das Volume, indem wir seine kurze ID angeben:

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

6.3. Erstellen Sie ein Volume

Die API bietet zwei verschiedene Optionen zum Erstellen eines Volumes. Die Methode non-argcreateVolumeCmderstellt ein Volume, in dem der Name von Docker angegeben wird:

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

Anstatt das Standardverhalten zu verwenden, können wir mit der HilfsmethodewithName einen Namen für ein Volume festlegen:

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

6.4. Entfernen Sie ein Volume

Mit der MethoderemoveVolumeCmdkönnen wir ein Volume intuitiv vom Docker-Host löschen. What is important to note that we cannot delete a volume if it is in use from a container. Wir entfernen das VolumemyNamedVolume aus der Volume-Liste:

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

7. Netzwerk Management

In unserem letzten Abschnitt geht es um die Verwaltung von Netzwerkaufgaben mit der API.

7.1. Netzwerke auflisten

Wir können die Liste der Netzwerkeinheiten mit einer der herkömmlichen API-Methoden anzeigen, beginnend mitlist:

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

7.2. Erstellen Sie ein Netzwerk

Das Äquivalent des Befehlsdocker network create wird mit der MethodecreateNetworkCmd ausgeführt. Wenn wir einen 30-Parteien- oder einen benutzerdefinierten Netzwerktreiber haben, kann diewithDriver-Methode diese neben den integrierten Treibern akzeptieren. In unserem Fall erstellen wir ein Brückennetzwerk mit dem Namenexample:

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

Darüber hinaus löst das Erstellen einer Netzwerkeinheit mit den Standardeinstellungen das Problem nicht. Wir können auch andere Hilfsmethoden anwenden, um ein erweitertes Netzwerk aufzubauen. Somit istto 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();

Der gleiche Befehl, den wir mit dem Befehldockerausführen können, lautet:

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

7.3. Überprüfen Sie ein Netzwerk

Das Anzeigen der Details eines Netzwerks auf niedriger Ebene wird auch in der API behandelt:

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

7.4. Entfernen Sie ein Netzwerk

Mit der MethoderemoveNetworkCmdkönnen wir eine Netzwerkeinheit mit ihrem Namen oder ihrer ID sicher entfernen:

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

8. Fazit

In diesem umfangreichen Lernprogramm haben wir die verschiedenen Funktionen vonJava Docker API Clientowie verschiedene Implementierungsansätze für Bereitstellungs- und Verwaltungsszenarien untersucht.

Alle in diesem Artikel dargestellten Beispiele sindover on GitHub.