在我的Spring Boot应用程序中,我想要将属性外部化以在Docker容器中运行。首次部署时,应用程序按预期加载和使用当前位于my-server/src/main/resources/application.yml
的属性。一切正常。
但是,我的问题是我需要根据需要更新这些属性,因此我需要在Docker容器上访问application.yml
文件一次。但此时,它在运行build/docker/
任务之前未包含在buildDocker
目录中,因此在首次部署后不会被复制或访问。
所以,我尝试过将Yaml文件复制到docker/
构建目录中,将其复制到可访问目录(/opt/meanwhileinhell/myapp/conf
),然后使用spring.config.location
属性传递在我的Dockerfile中配置到Jar的位置:
ENTRYPOINT ["java",\
...
"-jar", "/app.jar",\
"--spring.config.location=classpath:${configDirectory}"]
查看在Docker容器上运行的Command我可以看到这是预期的:
/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场景的配置外部化的正确方法吗?
答案 0 :(得分:24)
DOCKER IMAGE CONFIGURATION
如果你期待the way Spring recommends启动一个Spring Boot驱动的docker容器,那就是你找到的东西:
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文件environment variables take precedence开始提取它们。 / p>
环境变量也可以在docker命令中传递,以启动具有所需配置的容器。如果要为JVM内存设置一些限制,请参阅下面的链接。
DOCKER COMPOSE SAMPLE
这里有一个如何使用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 :(得分:6)
我个人使用Spring Cloud Config Server而不是尝试在整个地方设置属性文件。
tl; dr它允许您在集中位置的每个环境/配置文件级别保存git中的属性(允许版本控制,分支等),然后由REST提供。 Spring Boot完全支持它;实际上,它只是另一个属于你环境的财产来源。
答案 2 :(得分:3)
所以我设法让它运转起来。而不是将类路径传递给我的DockerFile中的目录:
"--spring.config.location=classpath:${configDirectory}"]
我尝试传递文件的完整位置:
"--spring.config.location=file:${configDirectory}/application.yml"]
现在,在重新启动Docker容器时会更新。
答案 3 :(得分:3)
Xtreme Biker的answer的一个变种,这次是将一个Spring启动战争部署到一个dockerized TomCat ......
我建议在您的应用中添加名义上的application.yml
,但使用Docker环境变量来覆盖需要特定于环境的变体的任何单个键。
我推荐这种方法(使用Docker环境变量)的原因是:
Spring Boot的Externalized Configuration docs解释了两种通过命令行提供环境的方法:
SPRING_DATASOURCE_USERNAME=helloworld
)-Dspring.datasource.username=helloworld
)我更喜欢Java选项,因为它们表达了一个明确的意图:“这是针对以下Java进程的,而仅针对该Java进程”。
最后:我会使用TomCat的CATALINA_OPTS
作为传递这些Java选项的机制。来自catalina.sh
的文档:
(可选)“start”时使用的Java运行时选项, 执行“run”或“debug”命令。 包括在这里,而不是在JAVA_OPTS中的所有选项,应该 仅由Tomcat本身使用,而不是由停止过程使用, 版本命令等 例如堆大小,GC日志记录,JMX端口等。
因为CATALINA_OPTS
比让Docker镜像负责创建setenv.sh
并将相应的Docker env声明传递给它更容易。
像这样构建你的.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"]
像这样构建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
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
答案 4 :(得分:2)
您的方法绝对是一个可行的解决方案,但不推荐使用,因为它会使您的图像在不同的生产环境和开发环境之间无法移植。容器应该是不可变的,并且所有环境配置都应该外部化。
对于spring boot,有一个非常强大的项目,允许您外部化配置。它被称为Spring Cloud Config。配置服务器允许您将特定于环境的配置保存在git存储库中,并将配置提供给需要它的应用程序。您基本上只需将相同的application.yml保存在git中,并将配置服务器指向存储库位置。
遵循此方法,您可以为不同的环境定义多个配置文件,并使您的docker容器保持不变。
答案 5 :(得分:0)
我个人会考虑两种选择:
使用环境变量
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",
}'