部署到Docker

时间:2017-09-05 14:37:03

标签: docker spring-boot dockerfile spring-boot-configuration

在我的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

documentation州:

  

配置自定义配置位置时,会另外使用它们   到默认位置。在搜索之前搜索自定义位置   默认位置。

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

6 个答案:

答案 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完全支持它;实际上,它只是另一个属于你环境的财产来源。

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

答案 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解释了两种通过命令行提供环境的方法:

  • UN * X env vars(即SPRING_DATASOURCE_USERNAME=helloworld
  • Java选项(即-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)

我个人会考虑两种选择:

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