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



在我的Spring Boot应用中,我想将属性外部化以在Docker容器中运行。首次部署时,应用程序当前当前属于my-server/src/main/resources/application.yml中的属性会按预期加载和使用。一切都很好。

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

因此,我尝试的是将yaml文件复制到docker/构建目录中,将其复制到可访问目录(/opt/meanwhileinhell/myapp/conf),然后使用spring.config.location属性将配置的位置传递给我的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

文档指出:

配置自定义配置位置时,它们还会加上它们 到默认位置。自定义位置在 默认位置。

我似乎无法弄清楚我在做什么错或误解,但更重要的是,这是将这种类型的Docker方案外部化的正确方法?

docker Image Configuration

如果您寻找Spring推荐启动Spring Boot驱动的Docker容器的方式,那就是您发现的:

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构成样本

在这里,您有一个示例,说明了我如何使用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

另请参阅:

  • 如何将环境变量传递给Docker容器?
  • 限制Docker容器中的JVM内存消耗

我个人会考虑两个选项:

  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:latest
      ports:
        - "8080:8080"
      environment:
        SPRING_APPLICATION_JSON: '{
          "spring.datasource.url": "jdbc:mysql://db:3306/table",
        }'
    

我个人会使用Spring Cloud Config Server,而不是尝试在整个地方设置属性文件。

tl; dr允许您在集中位置中以每个环境/配置文件级别的git(允许版本控制,分支等)保持属性,然后通过静止来提供。Spring Boot对此有全力支持;实际上,这只是另一个最终在您的环境中的属性来源。

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

,所以我设法使它正常工作。而不是将class路径传递给我的dockerfile中的目录:

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

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

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

现在,此docker容器的重新启动。

xtreme骑自行车的答案的变体,这次是将弹簧靴战争部署到dockerized tomcat ………

我建议您在您的应用中包含名义application.yml,但请使用Docker环境变量覆盖任何需要特定环境变化的单个键。

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

  • 您的Docker映像可以使用恰好与您可能用于本地开发相同的人工制品
  • 使用音量安装很痛苦;您需要在某个地方找到他们在码头主持人上生活的地方 - 这将那个主机变成雪花
  • 使用Docker Secrets很痛苦;图像或应用程序层需要更改以从文件系统明确查找秘密

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

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

我更喜欢Java选项,因为它们表达了一个明确的意图:"这是针对以下Java过程的,并且仅针对该Java过程

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

(可选)Java运行时选项在"开始"时使用 执行"运行"或"调试"命令。 在此处包含所有选项,而不是在Java_opts中 仅由Tomcat本身使用,而不是由停止过程使用 版本命令等 示例是堆尺寸,GC记录,JMX端口等。

因为CATALINA_OPTS比使您的Docker映像负责创建setenv.sh并将适当的Docker env声明传递到其中更容易。


构建您的 .war伪像这样:

./gradlew war

我们期望gradle输出.war CC_19。

使用这样的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

您的方法绝对是一个可行的解决方案,但是不建议这样做,因为它使您的图像无法在不同的生产和开发环境之间移动。容器应该是不可变的,所有环境配置都应被外部化。

对于Spring Boot,有非常强大的项目,可让您外部化配置。它称为Spring Cloud Config。配置服务器允许您将特定于环境的配置保存在GIT存储库中,并将配置提供给需要它的应用程序。您基本上只是保存相同的应用程序。

遵循此方法,您可以为不同环境定义多个配置文件,并使您的Docker容器不变。

spring.config.additional-location设置为entrypoint(以/结束)在 dockerfile 上,将卷安装到 application.yml的主机文件夹

dockerfile

RUN mkdir /opt/meanwhileinhell/myapp/conf
  (...)
ENTRYPOINT ["java", "-Dspring.config.additional-location=/opt/meanwhileinhell/myapp/conf/", "-jar", "/opt/meanwhileinhell/myapp/app.jar"]

当我们要指定目录位置时默认值。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 上的环境:...环境:-spring.config.Additional-Location =/opt/opt/opt/myapp/conf/conf/conf/conf/conf/conf/conf/卷: - My-Server/src/main/resources:/opt/opt/yywhileinhell/myapp/conf...

Spring<2.x 使用spring.config.location代替spring.config.additional-location

最新更新