Panduan Docker untuk Java

1. Gambaran keseluruhan

Dalam artikel ini, kami melihat API khusus platform lain - Java API Client for Docker .

Sepanjang artikel ini, kami memahami cara menghubungkan dengan daemon Docker yang sedang berjalan dan jenis fungsi penting apa yang ditawarkan oleh API kepada pengembang Java.

2. Ketergantungan Maven

Pertama, kita perlu menambahkan kebergantungan utama ke dalam fail pom.xml kami :

 com.github.docker-java docker-java 3.0.14 

Pada masa menulis artikel, versi terbaru API adalah 3.0.14 . Setiap pelepasan dapat dilihat sama ada dari halaman pelepasan GitHub atau dari repositori Maven.

3. Menggunakan Pelanggan Docker

DockerClient adalah tempat kita dapat menjalin hubungan antara mesin / daemon Docker dan aplikasi kita.

Secara lalai, daemon Docker hanya dapat diakses di fail unix: ///var/run/docker.sock . Kami dapat berkomunikasi secara tempatan dengan mesin Docker yang mendengar pada soket Unix kecuali jika dikonfigurasikan sebaliknya .

Di sini, kami memohon ke kelas DockerClientBuilder untuk membuat sambungan dengan menerima tetapan lalai:

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

Begitu juga, kita boleh membuka sambungan dalam dua langkah:

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

Oleh kerana enjin boleh bergantung pada ciri-ciri lain, pelanggan juga dapat dikonfigurasi dengan keadaan yang berbeza.

Sebagai contoh, pembangun menerima URL pelayan, iaitu, kita dapat mengemas kini nilai sambungan jika enjin tersedia di port 2375 :

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

Perhatikan bahawa kita perlu menambahkan rentetan sambungan dengan unix: // atau tcp: // bergantung pada jenis sambungan.

Sekiranya kita melangkah lebih jauh, kita dapat memperoleh konfigurasi yang lebih maju menggunakan kelas 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();

Begitu juga, kita dapat menjalankan pendekatan yang sama dengan menggunakan 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();

Pilihan lain kecuali kita mengkonfigurasi tetapan mesin dalam kod sumber adalah menetapkan pemboleh ubah persekitaran yang sesuai sehingga kita hanya dapat mempertimbangkan instansiasi default dari DockerClient dalam projek:

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. Pengurusan Kontena

API membolehkan kami pelbagai pilihan mengenai pengurusan kontena. Mari kita perhatikan masing-masing.

4.1. Senarai Bekas

Sekarang kita mempunyai sambungan yang terjalin, kita dapat menyenaraikan semua kontena yang sedang berjalan di host Docker:

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

Dengan syarat menunjukkan bahawa wadah yang sedang berjalan tidak menarik kebutuhannya, kami dapat menggunakan pilihan yang ditawarkan untuk menanyakan kontainer.

Dalam kes ini, kami memaparkan bekas dengan status "keluar":

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

Ia setara dengan:

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

4.2. Buat Bekas

Membuat wadah dihidangkan dengan kaedah createContainerCmd . Kita boleh menyatakan deklarasi yang lebih kompleks menggunakan kaedah yang tersedia bermula dengan awalan "dengan" .

Mari kita anggap bahawa kita mempunyai perintah membuat docker yang menentukan wadah MongoDB yang bergantung pada host yang mendengar secara dalaman di 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

Kami dapat bootstrap bekas yang sama dengan konfigurasinya secara program:

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. Mulakan, Hentikan, dan Bunuh Kontena

Sebaik sahaja kita membuat bekas, kita boleh memulakan, menghentikan dan membunuhnya dengan nama atau id masing-masing:

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

4.4. Periksa Bekas

The inspectContainerCmd kaedah mengambil String hujah yang menunjukkan nama atau id sebuah bekas. Dengan kaedah ini, kita dapat melihat secara langsung metadata bekas:

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

4.5. Rakam Bekas

Sama dengan perintah docker komit , kita boleh membuat gambar baru menggunakan kaedah komitCmd .

Dalam contoh kami, senario tersebut , sebelumnya kami menjalankan wadah alpine: 3.6 yang idnya adalah "3464bb547f88" dan memasang git di atasnya.

Sekarang, kami ingin membuat snapshot gambar baru dari bekas:

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

Oleh kerana gambar baru kami yang digabungkan dengan git tetap ada di host, kami dapat mencarinya di host Docker:

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

5. Pengurusan Imej

Ada beberapa perintah yang berlaku yang kami berikan untuk menguruskan operasi gambar.

5.1. Senaraikan Imej

Untuk menyenaraikan semua gambar yang ada termasuk gambar yang menggantung di host Docker, kita perlu menggunakan kaedah listImagesCmd :

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

Sekiranya kita mempunyai dua gambar di Docker Host kita , kita harus mendapatkan objek Imej dari mereka pada waktu berjalan . Gambar yang kami cari adalah:

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

Di sebelah ini, untuk melihat gambar perantaraan, kita perlu memintanya secara eksplisit:

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

Sekiranya hanya memaparkan gambar yang menggantung adalah kasusnya, kaedah withDanglingFilter mesti dipertimbangkan:

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.

Semua contoh yang digambarkan dalam artikel ini boleh didapati di GitHub.