web-dev-qa-db-ja.com

Dockerにデプロイする際のSpring Bootプロパティの外部化

私の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シナリオの構成を外部化する正しい方法ですか?

13
MeanwhileInHell

DOCKER IMAGE CONFIGURATION

Springが推奨する方法 を見て、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ファイルよりも。

環境変数を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

以下も参照してください:

19
Xtreme Biker

個人的には、あちこちにプロパティファイルを設定しようとする代わりに、Spring Cloud Config Serverを使用します。

tl; drにより、一元化された場所で環境/プロファイルレベルごとにgit(バージョン管理、分岐などを許可)でプロパティを保持し、RESTによって提供されます。 Spring Bootはそれを完全にサポートしています。実際には、環境内で終わる別のプロパティソースにすぎません。

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

6
PaulNUK

だから私はそれを機能させることができた。クラスパスをDockerFileのディレクトリに渡すのではなく:

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

代わりに、ファイルの完全な場所を渡そうとしました。

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

これは、Dockerコンテナの再起動時に更新されるようになりました。

3
MeanwhileInHell

Xtreme Bikerのバリエーション answer 、今回はSpringブート戦争をドッキングされたTomcatに展開するためのものです

アプリに公称application.ymlを含めることをお勧めしますが、Docker環境変数を使用して、環境固有のバリエーションを必要とする個々のキーをオーバーライドします。

私がこのアプローチを推奨する理由(Docker環境変数を使用)は次のとおりです。

  • dockerイメージは、ローカル開発に使用するのと同じアーティファクトをexactly使用できます
  • ボリュームマウントの使用は苦痛です。あなたは彼らがあなたの港湾労働者のホストに住むためのどこかを見つける必要があります-それはそのホストをスノーフレークに変えます
  • dockerシークレットを使用するのは苦痛です。ファイルシステムからシークレットを明示的に検索するには、画像またはアプリケーション層を変更する必要があります

Spring Bootの Externalized Configuration docs コマンドライン経由で環境を提供する2つの方法を説明します。

  • UN * X env vars(つまりSPRING_DATASOURCE_USERNAME=helloworld
  • Javaオプション(つまり-Dspring.datasource.username=helloworld

私はJavaオプションを好みます。なぜなら、それらは明示的な意図を表現するからです。 "これは、次のJavaプロセス、およびそのためのonlyJava process "。

最後に、TomcatのCATALINA_OPTSを、これらのJavaオプション。catalina.shからのドキュメントを渡すためのメカニズムとして使用します。

(オプション)Java「start」、「run」、または「debug」コマンドの実行時に使用されるランタイムオプション。Java_OPTSには含めず、Tomcatのみが使用するすべてのオプションをここに含めます。停止プロセス、バージョンコマンドなどによるものではありません。例としては、ヒープサイズ、GCロギング、JMXポートなどがあります。

CATALINA_OPTSは、setenv.shを作成して適切なDocker env宣言を渡すDockerイメージを作成するよりも簡単なルートだからです。


.warアーティファクトを次のようにビルドします。

./gradlew war

Gradleにより.warbuild/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
2
Birchlabs

あなたのアプローチは間違いなく実行可能なソリューションですが、推奨されません。異なる本番環境と開発環境間でイメージを移植できないためです。コンテナは不変であり、すべての環境設定は外部化される必要があります。

スプリングブートの場合、構成を外部化できる非常に強力なプロジェクトがあります。その名前は Spring Cloud Config です。構成サーバーを使用すると、環境固有の構成をgitリポジトリに保存し、それを必要とするアプリケーションに構成を提供できます。基本的には、同じapplication.ymlをgitに保存し、設定サーバーにリポジトリの場所を指定するだけです。

このアプローチに従って、異なる環境用に複数の構成ファイルを定義し、Dockerコンテナーを不変に保つことができます。

2
yamenk

私は個人的に2つのオプションを検討します。

  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",
        }'
    
0
Rafal Enden