部署到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对它有完整的支持; 实际上它只是另一个属性源,最终在你的环境中。
您的方法绝对是一个可行的解决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输出一个.war
来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"]
像这样构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