Externalising Spring Boot properties when deploying to Docker

前端 未结 6 1947
天命终不由人
天命终不由人 2020-12-01 04:20

In my Spring Boot app I want to externalise the properties to run in a Docker container. When first deployed, the properties that are currently in my-server/src/main/

6条回答
  •  既然无缘
    2020-12-01 05:07

    A variation on Xtreme Biker's answer, this time for deployment of a Spring boot war into a dockerized TomCat

    I recommend including a nominal application.yml in your app, but use Docker environment variables to override any individual keys which need environment-specific variation.

    The reason I recommend this approach (using Docker environment variables) is:

    • your docker image can use exactly the same artefact as you might use for local development
    • using volume-mounts is painful; you need to find somewhere for them to live on your docker host — which turns that host into a snowflake
    • using docker secrets is painful; image or application layer need to be changed to explicitly lookup secrets from the filesystem

    Spring Boot's Externalized Configuration docs explain two ways to supply environment via command-line:

    • UN*X env vars (i.e. SPRING_DATASOURCE_USERNAME=helloworld)
    • Java options (i.e. -Dspring.datasource.username=helloworld)

    I prefer Java options, because they express an explicit intent: "this is intended for the following Java process, and only for that Java process".

    Finally: I would use TomCat's CATALINA_OPTS as the mechanism for passing those Java options. Documentation from catalina.sh:

    (Optional) Java runtime options used when the "start", "run" or "debug" command is executed. Include here and not in JAVA_OPTS all options, that should only be used by Tomcat itself, not by the stop process, the version command etc. Examples are heap size, GC logging, JMX ports etc.

    Because CATALINA_OPTS is an easier route than making your Docker image responsible for creating a setenv.sh and passing the appropriate Docker env declarations into it.


    Build your .war artefact like so:

    ./gradlew war
    

    We expect a .war artefact to be output by Gradle to build/libs/api-0.0.1-SNAPSHOT.war.

    Use such a 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"]
    

    Build your Docker image like so:

    docker build . --tag=my-api
    

    Pass CATALINA_OPTS to your container like so:

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

    And a docker-compose variant looks like this:

    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
    

提交回复
热议问题