Comment créer un conteneur docker pour une application Java


Ce que je veux faire, c'est créer une image docker pour mon application Java, mais les considérations suivantes devraient être vraies pour la plupart des langages compilés.

Problème

Sur mon serveur de construction, je souhaite produire une image docker pour mon application en tant que livrable. Pour cela, je dois compiler l'application à l'aide d'un outil de construction (généralement Gradle, Maven ou Ant), puis ajouter le fichier JAR créé à l'image docker. Comme je veux que l'image docker exécute simplement le Fichier JAR Je vais bien sûr commencer à partir d'une image de base avec Java déjà installé.

Il y a trois façons de le faire:

Laissez l'outil de construction contrôler le processus

Dans ce cas, mon outil de construction contrôle l'ensemble du processus. Il prépare donc le fichier JAR et après la création du fichier JAR, il appelle Docker pour créer l'image. Cela fonctionne car le JAR est créé à l'avance et Docker peut ignorer le processus de construction nécessaire pour créer le JAR.

Mais mon Dockerfile n'est pas plus autonome. Cela dépend des étapes à suivre en dehors de Docker pour que cela fonctionne. Dans mon Dockerfile, j'aurai une instruction COPY ou ADD censée copier le fichier JAR dans l'image. Cette instruction échouera lorsque le pot n'est pas créé au préalable. Donc, l'exécution du Dockerfile peut ne pas fonctionner. Cela devient un problème si vous souhaitez intégrer des services qui se construisent simplement en utilisant le Dockerfile actuel, comme la fonctionnalité de construction automatique sur DockerHub.

Laissez Docker contrôler le construire

Dans ce cas, toutes les étapes nécessaires pour créer l'image sont ajoutées au Dockerfile afin que l'image puisse être créée en exécutant simplement la construction Docker.

Le principal problème avec cette approche est qu'il n'y a aucun moyen d'ajouter à un Dockerfile des commandes qui doivent être exécutées en dehors de l'image docker en cours de création. Cela signifie que je dois ajouter mon code source et mes outils de construction à l'image docker et construire mon fichier JAR à l'intérieur de l'image. Cela aura pour résultat que mon image sera plus grande qu'elle doit être dû à tous les fichiers ajoutés qui seront inutiles à l'exécution. Cela ajoutera également des calques supplémentaires à mon image.

Modifier:

Comme @adrian-mouat l'a souligné si j'ajoutais les sources, construisais l'application et supprimais les sources dans une instruction RUN, je pourrais éviter d'ajouter des fichiers et des couches inutiles à l'image Docker. Cela signifierait créer une commande enchaînée insensée.

Deux constructions distinctes

Dans ce cas, nous divisons notre build en deux: nous créons d'abord le fichier JAR à l'aide de notre outil de construction et le télécharger dans un référentiel (Maven ou Ivy référentiel). Nous déclenchons ensuite une construction Docker distincte qui ajoute simplement le fichier JAR du référentiel.

Conclusion

À mon avis, la meilleure façon serait de laisser l'outil de construction contrôler le processus. Cela se traduira par une image docker propre et comme l'image est ce que nous voulons fournir, cela est important. Pour éviter d'avoir un Dockerfile potentiellement non fonctionnel qui traîne cela devrait être créé dans le cadre de la construction. Donc, personne ne l'utiliserait accidentellement pour démarrer une construction cassée.

Mais cela ne me permettra pas de m'intégrer à DockerHub.

Question

Y a-t-il une autre façon de me manquer?

Mise à jour juin 2020

Depuis que j'ai créé cette question, beaucoup de choses ont changé. À ce stade, je préconiserais d'utiliserL'outil de FLÈCHE de Googel . Il s'intègre avec les outils de construction Java les plus courants (Maven et Gradle) et vous permet de créer un conteneur directement à partir de votre construction. C'est beaucoup plus concis que les anciennes approches, j'ai considéré toutes ces années.

Author: Tobias Kremer, 2015-07-29

8 answers

Le hub de registre docker a une image Maven qui peut être utilisée pour créer des conteneurs java.

En utilisant cette approche, la machine de construction n'a pas besoin d'avoir Java ou Maven préinstallé, Docker contrôle l'ensemble du processus de construction.

Exemple

├── Dockerfile
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── org
                └── demo
                    └── AppTest.java

L'image est construite comme suit:

docker build -t my-maven .

Et exécuter comme suit:

$ docker run -it --rm my-maven
0    [main] INFO  org.demo.App  - hello world

Dockerfile

FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

Mise à jour

Si vous vouliez optimiser votre image pour exclure la source que vous pourrait créer un Dockerfile qui inclut uniquement le jar construit:

FROM java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

Et construire l'image en deux étapes:

docker run -it --rm -w /opt/maven \
   -v $PWD:/opt/maven \
   -v $HOME/.m2:/root/.m2 \
   maven:3.3-jdk-8 \
   mvn clean install

docker build -t my-app .

__

Mise à jour (2017-07-27)

Docker a maintenant une capacitéde construction en plusieurs étapes . Cela permet à Docker de créer une image contenant les outils de génération mais uniquement les dépendances d'exécution.

L'exemple suivant illustre ce concept, notez comment le jar est copié à partir du répertoire cible de la première phase de construction

FROM maven:3.3-jdk-8-onbuild 

FROM java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["java","-jar","/opt/demo.jar"]
 32
Author: Mark O'Connor, 2019-10-02 09:45:07

Structure de l'application java

Demo
└── src
|    ├── main
|    │   ├── java
|    │   │   └── org
|    │   │       └── demo
|    │   │           └── App.java
|    │   └── resources
|    │       └── application.properties
|    └── test
|         └── java
|               └── org
|                   └── demo
|                         └── App.java  
├──── Dockerfile
├──── pom.xml

Contenu de Dockerfile

FROM java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["java","-jar","demo.jar"]

Commandes pour construire et exécuter l'image

  • Allez dans le répertoire du projet.Disons D:/Demo
$ cd D/demo
$ mvn clean install
$ docker build demo .
$ docker run -p 8080:8080 -t demo

Vérifiez que le conteneur est en cours d'exécution ou non

$ docker ps

, La sortie sera

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
55c11a464f5a        demo1               "java -jar demo.jar"   21 seconds ago      Up About a minute   0.0.0.0:8080->8080/tcp   cranky_mayer
 7
Author: Riddhi Gohil, 2016-04-04 09:02:49

Le moyen le plus simple est de laisser l'outil de construction contrôler le processus. Sinon, vous devez maintenir votre outil de génération de génération de fichier (pom.xml Maven ou build.gradle pour Gradle) ainsi qu'un Dockerfile.

Un moyen simple de construire un conteneur Docker pour votre application Java est d'utiliser Foc, qui est disponible en Maven et Gradle les plugins.

Par exemple, si vous utilisez Maven et que vous souhaitez construire votre conteneur sur votre exécution Démon Docker, vous pouvez simplement exécuter cette commande:

mvn compile com.google.cloud.tools:jib-maven-plugin:0.9.2:dockerBuild

Vous pouvez également construire directement dans un registre Docker avec Jib sans avoir besoin d'installer docker, exécutez un démon Docker (qui nécessite des privilèges root), ou écrivez un Dockerfile. Il est également plus rapide et construit des images de manière reproductible.

En savoir plus sur Jib dans son dépôt Github: https://github.com/GoogleContainerTools/jib

 4
Author: Qingyang Chen, 2018-07-09 13:01:13

Nous avons utilisé le Plugin Spotify Docker Maven pendant un certain temps. Le plugin vous permet de lier une construction Docker à une phase du cycle de vie Maven.

Un exemple: Exécutez la génération Docker après avoir empaqueté (phase: package) votre application en configurant le plugin pour ajouter votre application construite en tant que ressource au contexte de génération Docker. Dans la phase de déploiement, exécutez l'objectif Docker push pour pousser votre image Docker vers un registre. Cela peut s'exécuter à côté du plugin de déploiement normal, qui publie le artefact dans un référentiel comme Nexus.

Plus tard, nous avons divisé la build en deux tâches distinctes sur le serveur CI. Puisque Docker n'est qu'un moyen unique d'exécuter votre application (parfois, nous avons besoin de l'application publiée sur différents environnements, pas seulement Docker), la version Maven ne doit pas compter sur Docker.

Ainsi, le premier travail libère l'application dans Nexus (via Maven deploy). Le deuxième travail (qui peut être une dépendance en aval du premier travail) télécharge la dernière version artefact, effectue la construction Docker et pousse l'image dans le registre. Pour télécharger la dernière version, nous utilisons la Versions de Maven Plugin (versions:utilisez-les dernières versions) ainsi que les Dépendance Maven Plugin (dépendance:obtenir et de la dépendance:copie).

Le deuxième travail peut également être démarré pour une version spécifique de l'application pour (re)construire l'image Docker pour une version plus ancienne. De plus, vous pouvez utiliser un pipeline de construction (sur Jenkins), qui exécute à la fois les travaux et les passes la version release ou l'artefact release de la build Docker.

 2
Author: gclaussn, 2017-07-27 18:33:31

Quelques choses:

  • Si vous supprimez des fichiers dans la même instruction que vous les ajoutez, ils ne consomment de l'espace dans l'image. Si vous regardez certains des Dockerfiles pour les images officielles, vous verrez qu'ils téléchargent la source, la construisent et la suppriment toutes dans la même étape (par exemple https://github.com/docker-library/python/blob/0fa3202789648132971160f686f5a37595108f44/3.5/slim/Dockerfile). Cela signifie que vous devez faire de la gymnastique ennuyeuse, mais c'est parfaitement faisable.

  • Je ne vois pas le problème avec deux Dockerfiles. La bonne chose à ce sujet est que vous pouvez utiliser le JRE plutôt que le JDK pour héberger votre jar.

 1
Author: Adrian Mouat, 2016-07-08 16:17:37

Il existe d'autres utilisations pour exécuter des paquets jar ou war

  • ajouter jar dans l'image.
  • définir heapsize pour java
  • exécuter la commande jar via entrypoint

Exemple de fichier dockerfile

FROM base
ADD sample.jar renamed.jar
ENV HEAP_SIZE 256m
ENTRYPOINT exec java -Xms$HEAP_SIZE -Xmx$HEAP_SIZE -jar renamed.jar

En outre exemple de déploiement de package sur tomcat

FROM tomcat7
ADD sample.war ${CATALINA_HOME}/webapps/ROOT.war
CMD ${CATALINA_HOME}/bin/catalina.sh run

Construire des fichiers dockerfiles en tant qu'image

cp tomcat.dockerfile /workingdir/Dockerfile
docker build -t name /workingdir/Dockerfile .

Liste des images

docker images

Utiliser l'image pour créer un conteneur

docker run --name cont_name --extra-vars var1=val1 var2=val2 imagename
 0
Author: pmoksuz, 2015-12-26 22:16:11

Ici je décris comment je le fais dans mon environnement de développement.

  • Construire le war / jar localement avec Maven
  • Copiez-le dans un dossier Docker local
  • Exécutez Intellij Docker plugin qui crée une image docker contenant le war/jar, exécutez le serveur d'applications et le déploie sur le serveur Docker distant

J'espère que ça aide.

 0
Author: Eyal.Dahari, 2017-05-23 11:55:04

Conteneurisez votre application java à l'aide de l'outil Jib sans écrire dockerfile

Jib est un outil Java open-source maintenu par Google pour créer des images Docker d'applications Java. Cela simplifie la conteneurisation car avec elle, nous n'avons pas besoin d'écrire un dockerfile. Et en fait, nous n'avons même pas besoin que docker soit installé pour créer et publier nous-mêmes les images docker.

Google publie Jib en tant que Maven et Gradle plugin. https://github.com/GoogleContainerTools/jib

Conteneuriser votre application java à l'aide du projet Maven

Https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart

Conteneuriser votre application java à l'aide du projet Gradle

Https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#quickstart

 0
Author: anandchaugule, 2019-04-12 09:37:14