Код
#статьи

Практика Docker: знакомимся с docker-maven-plugin

Олег Накрайников рассказал, как запускать внешние зависимости в Docker для интеграционных тестов в spring-boot-проекте.

Фото: Bloomberg / Getty Images

Олег Накрайников


об эксперте

Technical Lead. Любит GYM, путешествия и компьютерные игры. Пишет технические статьи и иногда технические треды в Twitter.


ссылки


Запускать интеграционные тесты можно по-разному, но в работе я ориентируюсь на следующие требования:

  • способ должен позволять запускать тесты и локально, и на CI;
  • развёртывание зависимостей не должно чрезмерно увеличивать время сборки;
  • не должно возникать проблем с поиском сборок зависимостей (баз данных, брокеров и так далее).

Поэтому я использую maven — это фреймворк для автоматизации сборки проектов от Apache, в котором структура проекта описывается на подмножестве XML, языке POM. Далее расскажу, как запускать интеграционные тесты с его помощью, и поделюсь конфигурациями плагинов.

Как запустить интеграционный тест в maven

Интеграционные тесты в maven запускаются одной строкой:

mvn verify -Docker_host = localhost

Теперь настроим maven. Если прописать свойство docker_host, то сборщик активирует профиль IT:

<profile>
    <id>it</id>
    <activation>
        <property>
            <name>docker_host</name>
        </property>
    </activation>

Профиль включает плагины maven-failsafe-plugin и docker-maven-plugin.

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

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goals>
                <goal>verify</goals>
            </goals>
        </execution>
    </executions>

А второй — как раз для запуска зависимостей в контейнерах Docker:

<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.38.0</version>

В конфигурации docker-maven-plugin необходимо указать образы нужных нам зависимостей:

<configuration>
  <dockerHost>tcp://${docker_host}:${docker_port}</dockerHost>
  <images>
    <image>
      <name>postgres:11</name>
      <alias>postgresql</alias>
      <run>
        <env>
          <POSTGRES_USER>postgres</POSTGRES_USER>
          <POSTGRES_PASSWORD>postgres</POSTGRES_PASSWORD>
          <POSTGRES_DB>postgres</POSTGRES_DB>
        </env>
        <ports>
          <port>${postgres_port}:5432</port>
        </ports>
        <wait>
          <log>(?s)database system is ready to accept connections.*database system is ready to accept connections</log>
          <time>10000</time>
        </wait>
      </run>
    </image>
  </images>
</configuration>

Также укажем, что перед проведением тестов контейнеры нужно собрать и запустить, а по завершении — остановить и удалить:

<executions>
  <execution>
    <id>start</id>
    <phase>pre-integration-test</phase>
    <goals>
      <goal>build</goals>
      <goal>start</goals>
    </goals>
  </execution>
  <execution>
    <id>stop</id>
    <phase>post-integration-test</phase>
    <goals>
      <goal>stop</goals>
    </goals>
  </execution>
<executions>

Зачем нужно свойство docker_host

<configuration>
  <dockerHost>tcp://${docker_host}:${docker_port}</dockerHost>
  <images>
    <image>

В docker_host указывается адрес, по которому расположен docker engine — на нём плагин и будет работать с контейнерами. Данное свойство позволит запускать интеграционные тесты как локально на машине разработчика, так и на CI.

Статья написана на основе треда Олега в Twitter.

Всё чаще в современных CI воркеры разворачиваются в виде docker-контейнеров. Поэтому для сборки нашего проекта необходимо развернуть два контейнера: maven и Docker in Docker (dind). В maven собирается проект и запускаются интеграционные тесты, а в dind — контейнеры с зависимостями. Адрес dind-контейнера как раз указывается в свойстве docker_host.

Что сделать, чтобы тесты добрались до зависимостей?

Через плагин maven-failsafe-plugin устанавливаем переменные окружения и прописываем настройки в application.yml:

<configuration>
  <environmentVariables>
    <spring.profiles.active>tests-remote</spring.profiles.active>
    <postgres_host>${docker_host}</postgres_host>
    <postgres_port>${docker_por}</postgres_port>
  </environmentVariables>
</configuration>
spring:
  profiles: 
    active: tests-local
external.url: http://localhost:8001
db:
  username: 'postgres'
  password: 'postgres'
  driverClassName: 'org.postgresql.Driver'
  minimumIdle: 5
  maximumPoolSize: 10
  connectionTimeout: 10000
  validationTimeout: 5000
  connectionsTestQuery: 'SELECT 1'
___
spring: 
  config:
    activate: 
      on-profile: tests-local
db:
  jdbcUrl: 'jdbc:postgresql://localhost:5432/postgres'
___
spring:
  config:
    activate:
      on-profile: test-remote
db:
  jdbc:postgresql://${postgres.host}:${postgres.port}/postgres'

Здесь on-profile: tests-local нужен для запуска тестов из IDE, а on-profile: tests-remote — через maven.

Чтобы писать и запускать тесты из IDE, придётся поднять зависимости вручную двумя командами:

mvn docker:start -Docker_host=localhost
mvn docker:stop -Docker_host=localhost

Изложенный подход обладает следующими преимуществами:

  1. Вы сможете запускать тесты и локально, и на CI.
  2. Контейнеры будут создаваться только перед тестами и удаляться сразу после их окончания.
  3. Через docker-maven-plugin можно строить достаточно сложное окружение с множеством контейнеров и сетью между ними.

Пример проекта, собранного с помощью docker-maven-plugin, можно посмотреть в моём GitHub-репозитории, а почитать документацию к плагину — здесь.

Изучайте IT на практике — бесплатно

Курсы за 2990 0 р.

Я не знаю, с чего начать
Научитесь: Профессия DevOps-инженер Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована