部署到Docker时将外部化Spring引导属性

在我的Spring Boot应用程序中,我希望外部化这些属性以在Docker容器中运行。 首次部署时,应用程序按预期加载和使用当前位于my-server/src/main/resources/application.yml中的属性。 一切正常。

但是,我的问题是,我需要这些属性可以根据需要更新,所以我需要在Docker容器上访问一次application.yml文件。 但是在这一点上,在运行buildDocker任务之前,它不包含在build/docker/ buildDocker build/docker/目录中,所以在第一次部署之后不会被复制或访问。

所以,我所尝试的是将Yaml文件复制到docker docker/ build目录中,将其复制到可访问的目录( /opt/meanwhileinhell/myapp/conf ),并使用spring.config.location属性传递configuration到我的Dockerfile中的jar子:

 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 

该文件指出:

当configuration自定义configuration位置时,除了默认位置之外,还会使用它们。 在默认位置之前search自定义位置。

我似乎无法弄清楚我在做什么错误或误解,但可能更重要的是,这是外部configuration这种types的Docker场景的正确方法?

如果你看看Springbuild议推出一个Spring Bootdocker集装箱的方式,那么你会发现:

 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优先于yml文件上的环境variables。

可以在你的docker命令中传递环境variables来启动你想要的configuration的容器。 最后,主要思想是拥有一个默认configuration的不可变的docker镜像,能够在运行时重写它,而不需要重build它。


编辑

在这里,您有一个示例,展示如何使用docker撰写一个简单的应用程序环境。 正如你所看到的,我在这里声明了spring.datasource.url属性作为一个环境variables,所以它覆盖了你的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 

也可以看看:

  • 我如何将环境variables传递给Docker容器?

所以我设法得到它的工作。 而不是将类path传递到我的DockerFile中的目录:

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

我试着传递文件的完整位置:

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

这现在更新重新启动Docker容器。

就我个人而言,我会使用Spring Cloud Config Server,而不是尝试在各处设置属性文件。

tl; dr它允许你在git(允许版本控制,分支等)在一个集中位置的每个环境/configuration文件级别保存属性,然后由REST提供。 Spring Boot对它有完整的支持; 实际上它只是另一个属性源,最终在你的环境中。

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

您的方法绝对是一个可行的解决scheme,但不build议这样做,因为这会使您的映像在不同的生产环境和开发环境之间无法移植。 容器应该是不可变的,所有的环境configuration都应该被外化。

对于弹簧启动,有非常强大的项目,允许您外部configuration。 它被称为Spring Cloud Config 。 configuration服务器允许您将环境特定的configuration保存在git存储库中,并将configuration提供给需要它的应用程序。 你基本上只是在git中保存相同的application.yml,并将configuration服务器指向存储库的位置。

遵循这种方法,您可以为不同的环境定义多个configuration文件,并使docker容器保持不变。

Xtreme Biker的答案的一个变种,这次是将Spring引导战争部署到docker化的TomCat中

我build议在你的应用application.yml中包含一个名义上的application.yml ,但是使用Docker环境variables来覆盖任何需要环境特定变体的个别键。

我推荐这种方法(使用Docker环境variables)的原因是:

  • 您的docker图像可以使用与您在本地开发中使用的完全相同的工件
  • 使用卷装是痛苦的; 你需要find一个地方让他们住在你的docker主机上 – 这将主机变成一个雪花
  • 使用docker机密是痛苦的; 图像或应用程序层需要更改,以明确从文件系统查找秘密

Spring Boot的外部化configuration文档解释了通过命令行提供环境的两种方法:

  • UN * X env vars(即SPRING_DATASOURCE_USERNAME=helloworld
  • Java选项(即-Dspring.datasource.username=helloworld

我更喜欢Java选项,因为它们expression了一个明确的意图:“这是为了下面的Java过程,而且为了Java过程”。

最后:我将使用TomCat的CATALINA_OPTS作为传递这些Java选项的机制。 来自catalina.sh文件:

(可选)执行“启动”,“运行”或“debugging”命令时使用的Java运行时选项。 包括在这里,而不是在JAVA_OPTS中的所有选项,这应该只被Tomcat本身使用,而不是由停止过程,版本命令等。例如堆大小,GC日志logging,JMX端口等。

因为CATALINA_OPTS比让Docker镜像负责创buildsetenv.sh并将适当的Docker env声明传递给它更容易。


像这样构build你的.war造物:

 ./gradlew war 

我们希望Gradle输出一个.warbuild/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"] 

像这样构buildDocker镜像:

 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 

一个docker-compose变体看起来像这样:

 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