Статьи

Dockerizing Spring Boot Application

Докер здесь, Докер там, я вижу докеров везде

В этом посте я опишу процесс переноса приложения Spring Boot в Docker. Мы начнем с изменения файла сборки, затем создадим Dockerfile, чтобы он мог запускаться локально. Наконец мы опубликуем наше изображение в DockerHub .

Вступление

Несколько месяцев назад я начал новый личный проект под названием JVM Bloggers с целью помочь польским программистам распространять новости о своих новых постах в блоге. Первоначально это приложение Spring Boot было размещено на моей локальной машине, затем я перенес его в бесплатный аккаунт на Heroku .

И в первые недели я был удовлетворен: приложение не должно быть подключено к Интернету 24 часа в сутки, поэтому сон в течение 8 часов в день (ограничение бесплатной учетной записи Heroku) не был большой проблемой, ограничение памяти в 500 МБ меня тоже не ограничивало. Но по мере роста блоггеров JVM у меня возникали странные проблемы с использованием памяти: приложение начинало использовать 500-550 МБ, и было очень трудно найти источник такого поведения. Я даже оставил приложение запущенным на моей локальной машине с подключенным профилировщиком, но все еще не нашел ничего подозрительного.

Проблемы с объемом памяти стали раздражать, так как мне приходилось следить за приложением и перезапускать его каждые 1-2 дня, и из-за природы Heroku я не мог просто подключиться к серверу через ssh и отладить или подключить профилировщик к запущенному процессу. Стало ясно, что если я собираюсь добавить больше функций в блоггеры JVM, мне нужно перенести их на что-то более гибкое — машину Linux с Docker.

докер

В настоящее время Docker является очень популярной темой среди многих разработчиков, особенно в проектах, переходящих на архитектуру микросервисов. Но наиболее интересной особенностью с точки зрения моей проблемы является возможность создавать стандартизированный образ моего приложения и запускать его в других средах, не беспокоясь о различиях. Один образ можно развернуть либо локально, либо практически на любой машине с Linux, поэтому с помощью Docker я смог бы протестировать свое приложение локально, развернуть его на AWS или где-то еще без особых хлопот.

миграция

Сначала мы должны добавить некоторые новые зависимости и задачи в наш скрипт build.gradle :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
buildscript {
    // ...
    dependencies {
        // ...
        classpath('se.transmode.gradle:gradle-docker:1.2')
    }
}
 
// ...
 
group = 'tdziurko' // this will be my login at DockerHub (more about it later in this post)
 
task buildDocker(type: Docker, dependsOn: build) {      // this task will build our Docker image
    push = true
    applicationName = jar.baseName
    dockerfile = file('src/main/docker/Dockerfile')
    doFirst {
        copy {
            from jar
            into stageDir
        }
    }
}

В строке 17 мы указали местоположение нашего Dockerfile, так что теперь пришло время создать его там.

Создание Dockerfile

Dockerfile — это файл конфигурации, который определяет, как создать наш образ Docker, который мы можем развернуть позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
FROM java:8
MAINTAINER email@example.com
VOLUME /tmp
EXPOSE 8080
 
ENV USER_NAME blogger
ENV APP_HOME /home/$USER_NAME/app
 
RUN useradd -ms /bin/bash $USER_NAME
RUN mkdir $APP_HOME
 
ADD jvm-bloggers-0.5.0.jar $APP_HOME/jvm-bloggers.jar
RUN chown $USER_NAME $APP_HOME/jvm-bloggers.jar
 
USER $USER_NAME
WORKDIR $APP_HOME
RUN bash -c 'touch jvm-bloggers.jar'
 
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","jvm-bloggers.jar"]

Итак, позвольте мне объяснить этот файл шаг за шагом:

  • ОТ java: 8 : наше базовое изображение, это что-то вроде ключевого слова extension в Java. Здесь мы хотим опираться на образ с установленной Java 8
  • VOLUME / tmp : смонтированный каталог, в котором наше приложение может записать что-либо на диск
  • EXPOSE 8080 : номер порта, наше приложение будет запущено, оно будет доступно снаружи контейнера Docker
  • ENV USER_NAME blogger : вспомогательная переменная с именем пользователя, которое мы будем использовать для запуска нашего приложения
  • ENV APP_HOME / home / $ USER_NAME / app : следующая вспомогательная переменная с каталогом, в котором будет находиться наше приложение
  • RUN useradd -ms / bin / bash $ USER_NAME : создать пользователя с именем, определенным в $ USER_NAME
  • RUN mkdir $ APP_HOME : создать каталог приложения
  • ДОБАВИТЬ jvm-bloggers-0.5.0.jar $ APP_HOME / jvm-bloggers.jar : добавить fat-jar к нашему изображению и поместить его в $ APP_HOME
  • RUN chown $ USER_NAME $ APP_HOME / jvm-bloggers.jar : все предыдущие команды были выполнены как ROOT, поэтому нам нужно изменить владельца нашего jar-файла на $ USER_NAME . Обычно использование ROOT в Docker считается неправильным подходом из-за безопасности.
  • USER $ USER_NAME; WORKDIR $ APP_HOME : измените пользовательский и рабочий каталог на те, которые мы хотим использовать для запуска нашего приложения
  • RUN bash -c ‘touch jvm-bloggers.jar’ : коснитесь нашего файла, чтобы у него было время модификации
  • ENTRYPOINT [«java», «- Djava.security.egd = file: / dev /./ urandom», «- jar», «jvm-bloggers.jar»] : выполнить наш fat-jar (urandom для источника Tomcat энтропия)

Запуск образа Docker локально

Теперь у нас есть все для сборки и запуска нашего образа Docker.

1
./gradlew clean build buildDocker

Отклик:

1
2
3
4
5
6
7
8
9
:buildDocker FAILED
 
FAILURE: Build failed with an exception.
 
* What went wrong:
Execution failed for task ':buildDocker'.
> Docker execution failed
  Command line [docker push tdziurko/jvm-bloggers:latest] returned:
  unauthorized: access to the requested resource is not authorized

Не удалось выполнить задачу buildDocker, так как у вас нет учетной записи на DockerHub или вы не вошли в систему. но если вы проверите местные изображения

1
docker images

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

1
2
REPOSITORY                  TAG                             IMAGE ID            CREATED             VIRTUAL SIZE
tdziurko/jvm-bloggers       latest                          a09f884c5aa9        11 minutes ago      785.6 MB

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

1
docker run -p 8080:8080 --add-host=database:<your_local_db_host> -e jasypt.encryptor.password="<secretPassword>" -e spring.profiles.active="dev" tdziurko/jvm-bloggers:latest

Опять же, некоторые фрагменты требуют более подробного объяснения:

  • —Add-host = database: <your_local_db_host> : добавляет адрес в / etc / hosts в контейнере, база данных var должна быть адресом нашей базы данных, например, 192.168.0.101
  • -e jasypt.encryptor.password = « »: пароль Jasypt для расшифровки некоторых значений из файлов * .properties, -e добавляет его в качестве переменной env в контейнер
  • -e spring.profiles.active = «dev» : профиль весенней загрузки. dev используется для локального запуска приложения

Через несколько секунд вы увидите, что наше приложение запущено и работает в контейнере Docker.

Публикация в DockerHub

Наличие образа Docker, доступного локально, — это нормально, если вы планируете играть с ним только на своем компьютере, но, поскольку мы стремимся к развертыванию AWS, нам нужно опубликовать наш образ в DockerHub, чтобы он был доступен с любого компьютера Linux.

Сначала нужно создать учетную запись там (в моем случае это tdziurko ) и войти в систему с помощью клиента Docker, чтобы мы могли опубликовать его.

1
2
3
4
5
6
$ docker login
Username: tdziurko
Password:
Email: tomek@example.com
WARNING: login credentials saved in /Users/tomek/.docker/config.json
Login Succeeded

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

1
./gradlew clean build buildDocker

Через несколько минут мы увидим сообщение BUILD SUCCESSFUL, и если вы зайдете на страницу общедоступного профиля DockerHub, вы увидите нечто похожее:

docker_hub_image

Это означает, что наш образ Docker с приложением находится в ожидании развертывания на машине AWS EC2. Но это материал для другого поста в блоге 🙂

Резюме

В нескольких шагах я описал, как добавить возможности Docker в ваш проект Java, как настроить изображение и опубликовать его в DockerHub. Весь процесс не очень сложен, и давайте подготовим приложение к развертыванию на каждом компьютере Linux или сервере, поддерживающем Docker.

Ссылка: Dockerizing Spring Boot Application от нашего партнера JCG Томаша Дзюрко в блоге Code Hard Go Pro .