Внешние Spring Свойства загрузки при развертывании в 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

Документация documentation гласит:

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

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

Ответ 1

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

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

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-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

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

Ответ 2

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

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

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

Ответ 3

Вариант на Xtreme Biker answer, на этот раз для развертывания w860 > загрузочной войны в докционированный TomCat...

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

Я рекомендую этот подход (используя переменные среды Docker):

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

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

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

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

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

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

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


Создайте артефакт .war следующим образом:

./gradlew war

Мы ожидаем, что артефакт .war будет выводиться с помощью Gradle в build/libs/api-0.0.1-SNAPSHOT.war.

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

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.stackoverflow.com:3306' \
-Dspring.datasource.username=myuser \
" \
my-api

И вариант сокета для докеров выглядит следующим образом:

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

  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",
        }'