Руководство по Docker для Java

Руководство по докеру для Java

1. обзор

В этой статье мы рассмотрим другой хорошо зарекомендовавший себя API для конкретной платформы -Java API Client for Docker.

На протяжении всей статьи мы понимаем, как подключиться к работающему демону Docker и какие важные функции API предлагает разработчикам Java.

2. Maven Dependency

Во-первых, нам нужно добавить основную зависимость в наш файлpom.xml:


    com.github.docker-java
    docker-java
    3.0.14

На момент написания статьиthe latest version of the API is 3.0.14. Каждый выпуск можно просмотреть либо изthe GitHub release page, либо изthe Maven repository.

3. Использование клиента Docker

DockerClient - это место, где мы можем установить соединение между движком / демоном Docker и нашим приложением.

По умолчанию демон Docker доступен только в файлеunix:///var/run/docker.sock. Мы можем локально общаться сthe Docker engine listening on the Unix socket unless otherwise configured.

Здесь мы применяем классDockerClientBuilder для создания соединения, принимая настройки по умолчанию:

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

Аналогично, мы можем открыть соединение в два этапа:

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

Поскольку двигатели могут полагаться на другие характеристики, клиент также настраивается с другими условиями.

Например, построитель принимает URL-адрес сервера, то естьwe can update the connection value if the engine is available on port 2375:

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

Обратите внимание, что нам нужно добавитьthe connection string with unix:// or tcp:// depending on the connection type.

Если мы пойдем на один шаг дальше, мы сможем получить более продвинутую конфигурацию с использованием классаDefaultDockerClientConfig:

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

Точно так же мы можем реализовать тот же подход, используяProperties:

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

Другой вариант, если мы не настроим параметры движка в исходном коде, - это установить соответствующие переменные среды, чтобы мы могли рассматривать только экземплярDockerClient по умолчанию в проекте:

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. Управление контейнерами

API предоставляет нам различные варианты управления контейнерами. Давайте посмотрим на каждую из них.

4.1. Список контейнеров

Теперь, когда у нас установлено соединение, мы можем перечислить все запущенные контейнеры, расположенные на хосте Docker:

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

Если показ запущенных контейнеров не вызывает необходимости, мы можем использовать предлагаемые параметры для запроса контейнеров.

В этом случае мы отображаем контейнеры со статусом «выход»:

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

Это эквивалент:

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

4.2. Создать контейнер

Создание контейнера обслуживается методомcreateContainerCmd. Мы можем объявить более сложное объявлениеusingthe available methods starting with the “with” prefix.

Предположим, что у нас есть командаdockercreate, определяющая зависимый от хоста контейнер MongoDB, внутренне прослушивающий порт 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

Мы можем программно загрузить тот же контейнер вместе с его конфигурациями:

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. Запуск, остановка и уничтожение контейнера

Создав контейнер, мы можем запустить, остановить и уничтожить его по имени или идентификатору соответственно:

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

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

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

4.4. Осмотрите контейнер

МетодinspectContainerCmd принимает аргументString, который указывает имя или идентификатор контейнера. Используя этот метод, мы можем наблюдать метаданные контейнера напрямую:

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

4.5. Снимок контейнера

Подобно командеdocker commit, мы можем создать новое изображение, используя методcommitCmd.

В нашем примере сценарий, we previously run an alpine:3.6 container whose id is “3464bb547f88” and installed git on top of it.

Теперь мы хотим создать новый снимок изображения из контейнера:

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

Поскольку наш новый образ, связанный сgit, остается на хосте, мы можем искать его на хосте Docker:

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

5. Управление изображениями

Есть несколько применимых команд, которые нам даны для управления операциями с изображениями.

5.1. Список изображений

Чтобы перечислить все доступные образы, включая «висячие» на хосте Docker, нам нужно применить методlistImagesCmd:

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

Если у нас есть два образа на нашем хосте Docker,we should obtain the Image objects of them at run-time. Изображения, которые мы ищем:

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

Кроме того, чтобы увидеть промежуточные изображения, нам нужно явно запросить это:

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

Если имеет место только отображение висящих изображений, следует рассмотреть методwithDanglingFilter:

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

5.2. Создать изображение

Давайте сосредоточимся на способе создания изображения с помощью API. The buildImageCmd method builds Docker images from a Dockerfile. В нашем проекте у нас уже есть один Dockerfile, который дает образ Alpine с установленным git:

FROM alpine:3.6

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

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

Новый образ будет построен без использования кеша, и перед запуском процесса сборки в любом случае движок Docker попытается получить более новую версию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. Осмотрите изображение

Мы можем проверить низкоуровневую информацию об изображении благодаря методуinspectImageCmd:

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

5.4. Отметить изображение

Добавить тег к нашему изображению довольно просто с помощью командыdockertag, поэтому API не является исключением. Мы можем осуществить то же самое с методомtagImageCmd. 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();

Мы бы перечислили вновь созданное изображение, и вот оно:

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

5.5. Нажать изображение

Перед отправкой образа в службу реестра необходимо настроить док-клиент для взаимодействия со службой, поскольку для работы с реестрами необходимо заранее пройти проверку подлинности.

Поскольку мы предполагаем, что клиент был настроен с помощью Docker Hub, мы можем отправить образexample/alpine в пример учетной записи DockerHub:

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

We must abide by the duration of the process. В этом примереwe are waiting 90 seconds.

5.6. Вытяните изображение

Для загрузки образов из служб реестра мы используем методpullImageCmd. Кроме того, если изображение извлекается из частного реестра, клиент должен знать наши учетные данные, в противном случае процесс завершается с ошибкой. 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);

Чтобы проверить, существует ли упомянутое изображение на хосте Docker после его извлечения:

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

5.7. Удалить изображение

Еще одна простая функция среди остальных - это методremoveImageCmd. Мы можем удалить изображение с его коротким или длинным идентификатором:

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

5.8. Искать в реестре

Для поиска изображения в Docker Hub у клиента есть методsearchImagesCmd, принимающий строковое значение, которое указывает термин. Здесь мы исследуем изображения, связанные с именем, содержащим ‘Java', в Docker Hub:

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

Вывод возвращает первые 25 связанных изображений в списке объектовSearchItem.

6. Управление томом

Если Java-проектам необходимо взаимодействовать с Docker для томов, мы также должны принять во внимание этот раздел. Briefly, we look at the fundamental techniques of volumes provided by the Docker Java API.с

6.1. Список томов

Все доступные тома, включая именованные и неназванные, перечислены с:

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

6.2. Осмотрите том

МетодinspectVolumeCmd - это форма для отображения подробной информации о томе. Мы проверяем объем, указав его короткий идентификатор:

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

6.3. Создать том

API предоставляет два разных варианта создания тома. Не-argcreateVolumeCmd метод создает том, имя которого задает Docker:

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

Вместо того, чтобы использовать поведение по умолчанию, вспомогательный методwithName позволяет нам задать имя для тома:

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

6.4. Удалить том

Мы можем интуитивно удалить том с хоста Docker с помощью методаremoveVolumeCmd. What is important to note that we cannot delete a volume if it is in use from a container. Удаляем томmyNamedVolume из списка томов:

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

7. Управление сетью

Наш последний раздел посвящен управлению сетевыми задачами с помощью API.

7.1. Список сетей

Мы можем отобразить список сетевых устройств одним из стандартных методов API, начиная сlist:

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

7.2. Создать сеть

Эквивалент командыdocker network create выполняется методомcreateNetworkCmd. Если у нас есть тридцать партий или пользовательский сетевой драйвер, методwithDriver может принимать их помимо встроенных драйверов. В нашем случае давайте создадим мостовую сеть с именемexample:

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

Более того, создание сетевого модуля с настройками по умолчанию не решает проблему, мы можем применить другие вспомогательные методы для построения расширенной сети. Таким образом,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();

Та же самая команда, которую мы можем запустить с командойdocker:

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

7.3. Осмотрите сеть

Отображение низкоуровневых деталей сети также рассматривается в API:

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

7.4. Удалить сеть

Мы можем безопасно удалить сетевой модуль с его именем или идентификатором, используя методremoveNetworkCmd:

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

8. Заключение

В этом обширном руководстве мы исследовали различные разнообразные функцииJava Docker API Client, а также несколько подходов к реализации для сценариев развертывания и управления.

Все примеры, проиллюстрированные в этой статье, можно найтиover on GitHub.

Related