部署到Docker时外部化Spring Boot属性

Mea*_*ell 22 docker spring-boot dockerfile spring-boot-configuration

在我的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属性将配置的位置传递给我的Dockerfile中的Jar:

ENTRYPOINT  ["java",\
...
"-jar", "/app.jar",\
"--spring.config.location=classpath:${configDirectory}"]
Run Code Online (Sandbox Code Playgroud)

看看在Docker容器上运行的Command我可以看到这是预期的:

/app.jar --spring.config.location=classpath:/opt/meanwhileinhell/myapp/conf]
Run Code Online (Sandbox Code Playgroud)

但是,当我更新此文件中的属性并重新启动Docker容器时,它没有获取更改.文件权限是:

-rw-r--r-- 1 root root  618 Sep  5 13:59 application.yml
Run Code Online (Sandbox Code Playgroud)

文件规定:

配置自定义配置位置时,除默认位置外,还会使用它们.在默认位置之前搜索自定义位置.

我似乎无法弄清楚我做错了什么或错误解释,但更重要的是,这是将这种类型的Docker场景的配置外部化的正确方法吗?

Xtr*_*ica 30

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"]
Run Code Online (Sandbox Code Playgroud)

这意味着您的图像扩展了openjdk,您的容器也有自己的环境.如果您正在这样做,那么声明要覆盖的内容作为环境属性并且Spring Boot将获取它们就足够了,因为环境变量优先于yml文件.

环境变量也可以在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
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 这个答案有点过时了。“使用Docker引导”指南现在使用Java作为入口点,而不是sh:`ENTRYPOINT [“ java”,“......。此外,现在可以将JDK_JAVA_OPTIONS(JDK-8170832)环境变量用于VM选项。 (4认同)

Raf*_*den 19

我个人会考虑两种选择:

  1. 每个配置使用一个环境变量

    app:
      image: my-app:latest
      ports:
        - "8080:8080"
      environment:
         SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/table
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用 SPRING_APPLICATION_JSON

    app:
      image: my-app:latest
      ports:
        - "8080:8080"
      environment:
        SPRING_APPLICATION_JSON: '{
          "spring.datasource.url": "jdbc:mysql://db:3306/table",
        }'
    
    Run Code Online (Sandbox Code Playgroud)


Bir*_*abs 7

Xtreme Biker答案的变体,这次是将 Spring Boot War 部署到 dockerized TomCat 中……

我建议application.yml在您的应用程序中包含一个标称值,但使用 Docker 环境变量来覆盖任何需要特定于环境的变化的单个键。

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

  • 您的 docker 镜像可以使用与您用于本地开发的完全相同的人工制品
  • 使用卷挂载很痛苦;你需要找到一个地方让他们住在你的 docker 主机上——这把主机变成了雪花
  • 使用 docker secrets 很痛苦;需要更改图像或应用程序层以从文件系统中显式查找机密

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

  • UN*X 环境变量(即SPRING_DATASOURCE_USERNAME=helloworld
  • Java 选项(即-Dspring.datasource.username=helloworld

我更喜欢 Java 选项,因为它们表达了一个明确的意图:“这用于以下 Java 进程,并且用于该 Java 进程”。

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

(可选)执行“开始”、“运行”或“调试”命令时使用的 Java 运行时选项。包括在这里而不是在 JAVA_OPTS 中的所有选项,这些选项应该只由 Tomcat 本身使用,而不是由停止进程、版本命令等使用。示例是堆大小、GC 日志记录、JMX 端口等。

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


.war像这样构建你的人工制品:

./gradlew war
Run Code Online (Sandbox Code Playgroud)

我们期望.warGradle 将人工制品输出到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"]
Run Code Online (Sandbox Code Playgroud)

像这样构建你的 Docker 镜像:

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"]
Run Code Online (Sandbox Code Playgroud)

CATALINA_OPTS像这样传递给你的容器:

docker build . --tag=my-api
Run Code Online (Sandbox Code Playgroud)

docker-compose 变体如下所示:

docker run -it \
-p 8080:8080 \
-e CATALINA_OPTS="\
-Dspring.datasource.url='jdbc:mysql://mydatabase.stackoverflow.com:3306' \
-Dspring.datasource.username=myuser \
" \
my-api
Run Code Online (Sandbox Code Playgroud)


Pau*_*NUK 6

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

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

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


Mea*_*ell 5

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

"--spring.config.location=classpath:${configDirectory}"]
Run Code Online (Sandbox Code Playgroud)

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

 "--spring.config.location=file:${configDirectory}/application.yml"]
Run Code Online (Sandbox Code Playgroud)

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


yam*_*enk 5

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

对于 spring boot,有一个非常强大的项目,可以让你外部化配置。它叫做Spring Cloud Config。配置服务器允许您将特定于环境的配置保存在 git 存储库中,并将配置提供给需要它的应用程序。您基本上只需在 git 中保存相同的 application.yml 并将配置服务器指向存储库位置。

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