Dans mon application Spring Boot, je souhaite externaliser les propriétés à exécuter dans un conteneur Docker. Lors du premier déploiement, les propriétés actuellement dans my-server/src/main/resources/application.yml
sont chargées et utilisées par l'application comme prévu. Tout fonctionne bien.
Cependant, mon problème est que j'ai besoin que ces propriétés puissent être mises à jour si nécessaire. J'ai donc besoin d'accéder au fichier application.yml
une fois sur le conteneur Docker. Mais à ce stade, il n'est pas inclus dans le répertoire build/docker/
avant l'exécution de la tâche buildDocker
. Par conséquent, il ne sera ni copié ni accessible après le premier déploiement.
Donc, ce que j'ai essayé, c'est de copier le fichier Yaml dans le répertoire de construction docker/
, de le copier dans un répertoire accessible (/opt/meanwhileinhell/myapp/conf
) et d'utiliser la propriété spring.config.location
pour transmettre un emplacement de la configuration au fichier Jar de mon fichier Docker:
ENTRYPOINT ["Java",\
...
"-jar", "/app.jar",\
"--spring.config.location=classpath:${configDirectory}"]
En regardant la commande en cours d'exécution sur le conteneur Docker, je peux voir que c'est comme prévu:
/app.jar --spring.config.location=classpath:/opt/meanwhileinhell/myapp/conf]
Cependant, lorsque je mets à jour une propriété dans ce fichier et que je redémarre le conteneur Docker, les modifications ne sont pas prises en compte. Les autorisations de fichier sont:
-rw-r--r-- 1 root root 618 Sep 5 13:59 application.yml
La documentation indique:
Lorsque les emplacements de configuration personnalisés sont configurés, ils sont également utilisés aux emplacements par défaut. Les emplacements personnalisés sont recherchés avant le emplacements par défaut.
Je n'arrive pas à comprendre ce que je fais de mal ou de mal interpréter, mais ce qui est probablement plus important, est-ce la bonne façon d'extérioriser la configuration pour ce type de scénario Docker?
CONFIGURATION D'IMAGE DU DOCKER
Si vous regardez comme le recommande Spring pour lancer un conteneur de dockers alimenté par Spring Boot, vous trouverez ceci:
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" ]
Cela signifie que votre image s'étend à openjdk et que votre conteneur possède son propre environnement. Si vous procédez ainsi, il vous suffira de déclarer ce que vous souhaitez écraser en tant que environment properties. Spring Boot les récupérera, car les variables d'environnement ont priorité sur les fichiers yml.
Des variables d'environnement peuvent également être passées dans votre commande docker pour lancer le conteneur avec la configuration souhaitée. Si vous souhaitez définir une limite pour la mémoire de la machine virtuelle Java, voir le lien ci-dessous.
DOCKER COMPOSE ECHANTILLON
Ici, vous avez un exemple de la façon dont je lance un environnement d’application simple avec docker compose. Comme vous le voyez, je déclare la propriété spring.datasource.url
ici en tant que variable d'environnement. Elle remplace donc tout ce que vous avez dans votre fichier 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
Voir également:
Personnellement, j'utilisais Spring Cloud Config Server au lieu d'essayer de configurer des fichiers de propriétés partout.
cela vous permet de conserver les propriétés dans git (ce qui permet le contrôle de version, la création de branches, etc.) au niveau de l’environnement/du profil dans un emplacement centralisé, qui sont ensuite servies par REST. Spring Boot a un support complet pour cela; en réalité, il s’agit simplement d’une autre source de propriétés qui aboutit dans votre environnement.
Alors j'ai réussi à le faire fonctionner. Plutôt que de passer le classpath au répertoire de mon fichier Docker:
"--spring.config.location=classpath:${configDirectory}"]
J'ai plutôt essayé de passer l'emplacement complet du fichier:
"--spring.config.location=file:${configDirectory}/application.yml"]
Ceci est maintenant mis à jour lors du redémarrage du conteneur Docker.
Une variante de answer de Xtreme Biker, cette fois pour le déploiement d'une guerre des bottes de printemps dans un Tomcat dockerisé…
Je recommande d'inclure un application.yml
nominal dans votre application, mais d'utiliser des variables d'environnement Docker pour remplacer toutes les clés individuelles nécessitant une variation spécifique à l'environnement.
La raison pour laquelle je recommande cette approche (à l'aide de variables d'environnement Docker) est la suivante:
La documentation de Spring Boot Externalized Configuration explique deux manières de fournir un environnement via une ligne de commande:
SPRING_DATASOURCE_USERNAME=helloworld
)-Dspring.datasource.username=helloworld
)Je préfère les options Java, car elles expriment une intention explicite: "ceci est destiné au processus Java suivant, et uniquement pour ce processus Java".
Enfin: J'utiliserais le CATALINA_OPTS
de Tomcat comme mécanisme pour transmettre ces options Java. Documentation de catalina.sh
:
(Facultatif) Options d'exécution Java utilisées lorsque "démarrer", La commande "run" ou "debug" est exécutée . Incluez ici et non dans Java_OPTS toutes les options, cela devrait être utilisé uniquement par Tomcat lui-même, et non par le processus d'arrêt, la commande de version etc . Les exemples sont la taille de tas, la journalisation GC, les ports JMX, etc.
Parce que CATALINA_OPTS
est un itinéraire plus facile que de rendre votre image Docker responsable de la création d'un setenv.sh
et de la transmission des déclarations env Docker appropriées.
Construisez votre artefact .war
comme ceci:
./gradlew war
Nous nous attendons à ce que Gradle produise un artefact .war
dans build/libs/api-0.0.1-SNAPSHOT.war
.
Utilisez un tel fichier 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"]
Construisez votre image Docker comme ceci:
docker build . --tag=my-api
Passez CATALINA_OPTS
à votre conteneur comme suit:
docker run -it \
-p 8080:8080 \
-e CATALINA_OPTS="\
-Dspring.datasource.url='jdbc:mysql://mydatabase.stackoverflow.com:3306' \
-Dspring.datasource.username=myuser \
" \
my-api
Et une variante docker-compose ressemble à ceci:
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
Votre approche est sans aucun doute une solution viable, mais elle n’est pas recommandée car elle rend votre image non portable entre différents environnements de production et de développement. Les conteneurs doivent être immuables et toute la configuration de l'environnement doit être externalisée.
Pour le démarrage du printemps, il existe un projet très puissant qui vous permet d’externaliser la configuration. Son appelé Spring Cloud Config . Le serveur de configuration vous permet de sauvegarder la configuration spécifique à votre environnement dans un référentiel git et de la transmettre aux applications qui en ont besoin. En gros, vous venez de sauvegarder le même fichier application.yml dans git et de diriger le serveur de configuration vers l’emplacement du référentiel.
En suivant cette approche, vous pouvez définir plusieurs fichiers de configuration pour différents environnements et conserver votre conteneur docker immuable.
Personnellement, je considérerais deux options:
Utiliser une variable d'environnement
app:
image: my-app:latest
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/table
Utiliser SPRING_APPLICATION_JSON
app:
image: my-app:latests
ports:
- "8080:8080"
environment:
SPRING_APPLICATION_JSON: '{
"spring.datasource.url": "jdbc:mysql://db:3306/table",
}'