Вывод на экран свойств Spring Boot при развертывании в Docker

В моем приложении Spring Boot я хочу, чтобы внешние свойства запускались в контейнере Docker. При первом развертывании свойства, которые в данный момент находятся в my-server/src/main/resources/application.yml загружаются и используются приложением, как и ожидалось. Все работает отлично.

Однако моя проблема заключается в том, что мне нужно, чтобы эти свойства могли обновляться по мере необходимости, поэтому мне нужен доступ к application.yml файл один раз в контейнере Docker. Но на данный момент он не включен в build/docker/ каталог перед запуском buildDocker задача, поэтому не будет скопирована или доступна после первого развертывания.

Итак, я попытался скопировать файл Yaml в docker/ построить каталог, скопировать его в доступный каталог (/opt/meanwhileinhell/myapp/conf) и использовать spring.config.location Свойство передать расположение конфига в Jar в моем Dockerfile:

ENTRYPOINT  ["java",\
...
"-jar", "/app.jar",\
"--spring.config.location=classpath:${configDirectory}"]

Глядя на команду, выполняющуюся в контейнере Docker, я вижу, что это так, как и ожидалось:

/app.jar --spring.config.location=classpath:/opt/meanwhileinhell/myapp/conf]

Однако, когда я обновляю свойство в этом файле и перезапускаю контейнер Docker, он не фиксирует изменения. Права доступа к файлам:

-rw-r--r-- 1 root root  618 Sep  5 13:59 application.yml

В документации говорится:

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

Похоже, я не могу понять, что я делаю неправильно или неправильно истолковал, но, возможно, более важно, является ли это правильным способом вывода конфигурации для сценария Docker этого типа?

7 ответов

Решение

КОНФИГУРАЦИЯ ИЗОБРАЖЕНИЯ DOCKER

Если вы посмотрите на то, как Spring рекомендует запустить докерский контейнер с питанием Spring Boot, вот что вы найдете:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD target/gs-spring-boot-docker-0.1.0.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

Это означает, что ваше изображение расширяет openjdk, а ваш контейнер имеет свою собственную среду. Если вы делаете это, было бы достаточно объявить то, что вы хотите переопределить, в качестве свойств среды, и Spring Boot будет их извлекать, поскольку переменные среды имеют приоритет над файлами yml.

Переменные среды также могут быть переданы в вашей команде docker, чтобы запустить контейнер с желаемой конфигурацией. Если вы хотите установить какой-либо предел для памяти JVM, см. Ссылку ниже.


ОБРАЗЕЦ ДОКЕРА

Здесь у вас есть пример того, как я запускаю простую среду приложений с помощью docker compose. Как видите, я объявляю spring.datasource.url свойство здесь как переменная окружения, поэтому оно переопределяет все, что у вас есть в вашем application.yml файл.

version: '2'
services:
    myapp:
        image: mycompany/myapp:1.0.0
        container_name: myapp
        depends_on:
        - mysql
        environment:
            - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/myapp?useUnicode=true&characterEncoding=utf8&useSSL=false
        ports:
            - 8080:8080

    mysql:
        image: mysql:5.7.19
        container_name: mysql
        volumes:
            - /home/docker/volumes/myapp/mysql/:/var/lib/mysql/
        environment:
            - MYSQL_USER=root
            - MYSQL_ALLOW_EMPTY_PASSWORD=yes
            - MYSQL_DATABASE=myapp
        command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8

Смотрите также:

Я лично рассмотрел бы два варианта:

  1. Использование переменной среды

    app:
      image: my-app:latest
      ports:
        - "8080:8080"
      environment:
         SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/table
    
  2. С помощью SPRING_APPLICATION_JSON

    app:
      image: my-app:latests
      ports:
        - "8080:8080"
      environment:
        SPRING_APPLICATION_JSON: '{
          "spring.datasource.url": "jdbc:mysql://db:3306/table",
        }'
    

Лично я бы использовал Spring Cloud Config Server вместо того, чтобы пытаться настроить файлы свойств повсюду.

tl; dr позволяет вам хранить свойства в git (что позволяет управлять версиями, ветвлениями и т. д.) на уровне среды / профиля в централизованном месте, которые затем обслуживаются REST. Spring Boot имеет полную поддержку для этого; по сути, это просто еще один источник свойств, который попадает в вашу среду.

https://spring.io/guides/gs/centralized-configuration/

Вариант ответа Xtreme Biker, на этот раз для развертывания Spring boot war в докернизированный TomCat

Я рекомендую в том числе именные application.yml в вашем приложении, но используйте переменные окружения Docker для переопределения любых отдельных ключей, которые нуждаются в изменении среды.

Причина, по которой я рекомендую этот подход (с использованием переменных среды Docker):

  • ваш образ докера может использовать точно такой же артефакт, который вы можете использовать для локальной разработки
  • использование объемных креплений болезненно; вам нужно найти где-нибудь, чтобы они жили на вашем хосте докера - который превращает этот хост в снежинку
  • использование секретов докера болезненно; слой изображения или приложения необходимо изменить для явного поиска секретов из файловой системы

Документы по внешней конфигурации Spring Boot объясняют два способа предоставления среды через командную строку:

  • UN * X env vars (т.е. SPRING_DATASOURCE_USERNAME=helloworld)
  • Параметры Java (т.е. -Dspring.datasource.username=helloworld)

Я предпочитаю опции Java, потому что они выражают явное намерение: "это предназначено для следующего процесса Java и только для этого процесса Java".

Наконец: я бы использовал TomCat's CATALINA_OPTS в качестве механизма для передачи этих параметров Java. Документация от catalina.sh:

(Необязательно) Параметры времени выполнения Java, используемые при выполнении команды "start", "run" или "debug". Включите сюда, а не в JAVA_OPTS все параметры, которые должны использоваться только самим Tomcat, а не процессом остановки, командой версии и т. Д. Примерами являются размер кучи, ведение журнала GC, порты JMX и т. Д.

Так как CATALINA_OPTS это более простой путь, чем сделать свой образ Docker ответственным за создание setenv.sh и передачи соответствующих деклараций Docker env в него.


Создайте свой .war артефакт вроде так:

./gradlew war

Мы ожидаем .war артефакт для вывода Gradle в build/libs/api-0.0.1-SNAPSHOT.war,

Используйте такой Dockerfile:

FROM tomcat:8.5.16-jre8-alpine

EXPOSE 8080

COPY build/libs/api-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/v1.war

CMD ["catalina.sh", "run"]

Создайте свой образ Docker следующим образом:

docker build . --tag=my-api

Проходить CATALINA_OPTS к вашему контейнеру вот так:

docker run -it \
-p 8080:8080 \
-e CATALINA_OPTS="\
-Dspring.datasource.url='jdbc:mysql://mydatabase.stackru.com:3306' \
-Dspring.datasource.username=myuser \
" \
my-api

И вариант docker-compose выглядит так:

version: '3.2'
services:
  web:
    image: my-api
    ports:
      - "8080:8080"
    environment:
      - >
        CATALINA_OPTS=
        -Dspring.datasource.url='jdbc:mysql://mydatabase.stackru.com:3306'
        -Dspring.datasource.username=myuser

Так что мне удалось заставить его работать. Вместо того, чтобы передавать classpath в каталог в моем DockerFile:

"--spring.config.location=classpath:${configDirectory}"]

Вместо этого я попытался передать полное местоположение файла:

 "--spring.config.location=file:${configDirectory}/application.yml"]

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

Ваш подход, безусловно, является жизнеспособным решением, однако он не рекомендуется, поскольку он делает ваш образ не переносимым между различными производственными средами и средами разработки. Контейнеры должны быть неизменными, а вся конфигурация среды должна быть внешней.

Для весенней загрузки существует очень мощный проект, который позволяет вывести конфигурацию на внешний уровень. Его называют Spring Cloud Config. Конфигурационный сервер позволяет вам сохранять конфигурацию, специфичную для вашей среды, в git-репозитории и предоставлять конфигурацию приложениям, которым это необходимо. Вы просто сохраняете тот же файл application.yml в git и указываете сервер конфигурации на расположение хранилища.

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

Установите значение ENTRYPOINT (оканчивающееся на /) в Dockerfile и смонтируйте том в папку хоста, где находится

Докерфайл

      RUN mkdir /opt/meanwhileinhell/myapp/conf
  (...)
ENTRYPOINT ["java", "-Dspring.config.additional-location=/opt/meanwhileinhell/myapp/conf/", "-jar", "/opt/meanwhileinhell/myapp/app.jar"]

Когда мы хотим указать местоположение каталога, мы должны убедиться, что значение Spring.config.location заканчивается на / (например, Spring.config.location=classpath:/config/) и что имя файла конфигурации является именем по умолчанию. https://springframework.guru/spring-external-configuration-data/

Для изменения при перезапуске нужно этоapplication.ymlбудет расположен на хост-компьютере, ссылаясь на него с помощью тома

docker-compose.yml

      ...
volumes:
     - my-server/src/main/resources:/opt/meanwhileinhell/myapp/conf
...

Другой альтернативой является среда в docker-compose.yml : ... /mean whileinhell/myapp/conf ...

Для Spring < 2.x используйтеspring.config.locationвместоspring.config.additional-location

Другие вопросы по тегам