web-dev-qa-db-fra.com

Comment créer un conteneur Docker pour une application Java

Ce que je veux faire est de construire une image de menu fixe pour mon application Java, mais les considérations suivantes doivent être respectées pour la plupart des langages compilés.

problème

Sur mon serveur de génération, je souhaite produire une image de menu fixe 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 du menu fixe. Comme je veux que l'image du menu fixe 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:

laisser l'outil de construction contrôler le processus

Dans ce cas, mon outil de construction contrôle l’ensemble du processus. Donc, il prépare le fichier JAR et, une fois le JAR créé, appelle Docker pour créer l'image. Cela fonctionne lorsque le fichier JAR est créé à l'avance et que Docker peut ignorer le processus de création requis pour créer le fichier JAR.

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

laisser Docker contrôler la construction

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

Le principal problème de cette approche est qu’il n’ya aucun moyen d’ajouter à une commande Dockerfile à exécuter en dehors de l’image de docker en cours de création. Cela signifie que je dois ajouter mon code source et mes outils de génération à l'image du menu fixe et créer mon fichier JAR à l'intérieur de l'image. Cela aura pour résultat que mon image sera plus grande que nécessaire en raison de tous les fichiers ajoutés qui seront inutiles au moment de l'exécution. Cela va également ajouter des couches supplémentaires à mon image.

Modifier:

Comme @ adrian-mouat m'a fait remarquer que si j'ajoutais les sources, construisais l'application et supprimait les sources dans une seule instruction RUN, je pouvais éviter d'ajouter des fichiers et des calques inutiles à l'image Docker. Cela voudrait dire créer une commande enchaînée insensée. 

deux constructions distinctes

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

conclusion

A mon avis, le meilleur moyen serait de laisser l'outil de compilation contrôler le processus . Cela donnera une image propre du docker et, comme l’image est ce que nous voulons offrir, c’est important. Pour éviter d'avoir un fichier Docker potentiellement inopérant, vous devez le créer 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 d'intégrer DockerHub.

question

Y a-t-il un autre moyen qui me manque?

37
Tobias Kremer

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

En utilisant cette approche, il n'est pas nécessaire que Java ou Maven soit pré-installé sur la machine de génération. Docker contrôle tout le processus de construction.

Exemple

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

Le conteneur est construit comme suit:

docker build -t my-maven .

Et courez 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"]

Mettre à jour

Si vous souhaitez optimiser votre conteneur pour exclure la source, vous pouvez créer un fichier Docker contenant uniquement le fichier 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 construisez le conteneur 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é construction en plusieurs étapes . Cela permet à Docker de créer un conteneur avec une image contenant les outils de construction, mais de générer une image contenant uniquement les dépendances d'exécution. 

L'exemple suivant illustre ce concept. Notez comment le fichier jar est copié à partir du répertoire cible de la première phase de génération.

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"]
25
Mark O'Connor

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
5
Riddhi Gohil

Le moyen le plus simple consiste à laisser l'outil de génération contrôler le processus. Sinon, vous devrez conserver le fichier de construction de votre outil de génération (tel que pom.xml pour Maven ou build.gradle pour Gradle), ainsi qu'une Dockerfile.

Un moyen simple de créer un conteneur Docker pour votre application Java consiste à utiliser Jib , disponible sous la forme Maven et Gradle . plugins.

Par exemple, si vous utilisez Maven et souhaitez créer votre conteneur pour votre démon Docker en cours d'exécution, vous pouvez simplement exécuter cette commande:

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

Vous pouvez également créer directement sur un registre Docker avec Jib sans avoir à installer docker, exécuter un démon Docker (qui requiert des privilèges root) ou écrire une Dockerfile. C'est aussi plus rapide et construit des images reproductibles.

En savoir plus sur Jib dans son référentiel Github: https://github.com/GoogleContainerTools/jib _

2
Qingyang Chen

Un certain nombre de choses:

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

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

1
Adrian Mouat

il existe des utilisations alternatives pour exécuter des paquets jar ou war

  • ajouter un pot dans l'image. 
  • définir heapsize pour Java 
  • lancer la commande jar via entrypoint

échantillon 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 plus exemple de déploiement de paquet sur Tomcat 

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

Construire des 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
pmoksuz

Conteneurisez votre application Java à l'aide de l'outil Jib sans écrire le fichier dockerfile

Jib est un outil open source Java mis à jour par Google pour la construction d'images Docker d'applications Java. Cela simplifie la conteneurisation car avec elle, nous n’avons pas besoin d’écrire un fichier de docker . Et en fait, nous n’avons même pas besoin d’installer un menu fixe pour créer et publier les images du menu fixe nous-mêmes.

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

Conteneurisez votre application Java à l'aide du projet Maven

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

Conteneurisez votre application Java à l'aide du projet Gradle

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

0
anandchaugule

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

  • Construisez la guerre/le pot localement avec Maven 
  • Copiez-le dans un dossier Docker local
  • Exécuter plug-in Intellij Docker qui crée une image de menu fixe contenant le fichier war/jar, lance le serveur d'applications et le déploie sur le serveur Docker distant

J'espère que ça aide.

0
Eyal.Dahari

Nous avons utilisé le Spotify Docker Maven Plugin pendant un moment. Le plug-in vous permet de lier un Docker à une phase du cycle de vie de Maven.

Exemple: Exécutez la construction de Docker après le conditionnement (phase: package) de votre application en configurant le plug-in pour ajouter votre application construite en tant que ressource au contexte de construction de Docker. Au cours de la phase de déploiement, exécutez l’objectif Docker Push pour transmettre l’image Docker à un registre. Cela peut s'exécuter à côté du plug-in deploy normal, qui publie l'artefact dans un référentiel tel que Nexus.

Plus tard, nous avons divisé la construction en deux tâches distinctes sur le serveur CI. Étant donné que Docker n’est qu’un moyen unique d’exécuter votre application (nous avons parfois besoin de la version finale sur différents environnements, et pas seulement de Docker), la construction Maven ne doit pas s’appuyer sur Docker.

Le premier travail libère donc l'application dans Nexus (via Maven deploy). Le second travail (qui peut être une dépendance en aval du premier travail) télécharge le dernier artefact de version, effectue la génération Docker et envoie l'image au registre. Pour télécharger la dernière version, nous utilisons le Versions Maven Plugin (versions: use-latest-releases) ainsi que le Maven Dependency Plugin (dépendance: get et dépendance: copie).

Le second travail peut également être démarré pour une version spécifique de l'application afin de (re) construire l'image Docker pour une version antérieure. De plus, vous pouvez utiliser un pipeline de génération (sur Jenkins), qui exécute les deux tâches et transmet la version ou l'artefact de version à la génération Docker.

0
gclaussn