Вывод на экран свойств 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
Смотрите также:
Я лично рассмотрел бы два варианта:
Использование переменной среды
app: image: my-app:latest ports: - "8080:8080" environment: SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/table
С помощью
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 имеет полную поддержку для этого; по сути, это просто еще один источник свойств, который попадает в вашу среду.
Вариант ответа 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