Dépendances du dégradé de cache Docker

J’essaie de déployer notre application Web java sur aws, un haricot élastique utilisant docker. L’idée est de pouvoir exécuter le conteneur localement à des fins de développement et de test, puis de le faire passer à la production avec git.

J’ai créé une image de base sur laquelle tomcat8 et java8 sont installés, l’image qui exécute les générations de dégradé héritées de cette image de base, accélérant ainsi le processus de construction.

Tout fonctionne bien, à l’exception du fait que le conteneur d’applications hérité construit à l’aide de docker ne semble pas mettre en cache les dépendances de gradle, il est téléchargé à chaque fois, y compris gradlew. Nous construisons notre application Web en utilisant la commande suivante:

./gradlew war

Existe-t-il un moyen de mettre en cache les fichiers dans ~/.gradle ce qui accélèrerait considérablement mon accumulation?

Ce n’est pas vraiment un problème sur beanstalk, mais un gros problème pour les développeurs qui essaient de construire et d’exécuter localement car cela prend beaucoup de temps, comme vous pouvez l’imaginer.

Le fichier docker image de base:

 FROM phusion/baseimage EXPOSE 8080 RUN apt-get update RUN add-apt-repository ppa:webupd8team/java RUN apt-get update RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections RUN apt-get -y install oracle-java8-installer RUN java -version ENV TOMCAT_VERSION 8.0.9 RUN wget --quiet --no-cookies http://archive.apache.org/dist/tomcat/tomcat-8/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz -O /tmp/catalina.tar.gz # Unpack RUN tar xzf /tmp/catalina.tar.gz -C /opt RUN mv /opt/apache-tomcat-${TOMCAT_VERSION} /opt/tomcat RUN ln -s /opt/tomcat/logs /var/log/tomcat RUN rm /tmp/catalina.tar.gz # Remove unneeded apps RUN rm -rf /opt/tomcat/webapps/examples RUN rm -rf /opt/tomcat/webapps/docs RUN rm -rf /opt/tomcat/webapps/ROOT ENV CATALINA_HOME /opt/tomcat ENV PATH $PATH:$CATALINA_HOME/bin ENV CATALINA_OPTS $PARAM1 # Start Tomcat CMD ["/opt/tomcat/bin/catalina.sh", "run"] 

L’application dockerfile:

 FROM  RUN mkdir ~/.gradle # run some extra stuff here to add things to gradle.properties file # Add project Source ADD . /var/app/myapp # Comstack and Deploy Application, this is what is downloading gradlew and all the maven dependencies every time, if only there was a way to take the changes it makes to ~/.gradle and persist it as a cache layer RUN cd /var/app/myapp/ && ./gradlew war RUN mv /var/app/myapp/build/libs/myapp.war /opt/tomcat/webapps/ROOT.war # Start Tomcat CMD ["/opt/tomcat/bin/catalina.sh", "run"] 

    je

    Ajouter une tâche resolutependencies dans build.gradle:

     task resolveDependencies { doLast { project.rootProject.allprojects.each { subProject -> subProject.buildscript.configurations.each { configuration -> configuration.resolve() } subProject.configurations.each { configuration -> configuration.resolve() } } } } 

    et mettre à jour Dockerfile:

     ADD build.gradle /opt/app/ WORKDIR /opt/app RUN gradle resolveDependencies ADD . . RUN gradle build -x test --parallel && \ touch build/libs/api.jar 

    II

    Voici ce que je fais maintenant:

    build.gradle

     ext { speed = project.hasProperty('speed') ? project.getProperty('speed') : false offlineComstack = new File("$buildDir/output/lib") } dependencies { if (speed) { comstack fileTree(dir: offlineComstack, include: '*.jar') } else { // ...dependencies } } task downloadRepos(type: Copy) { from configurations.all into offlineComstack } 

    Dockerfile

     ADD build.gradle /opt/app/ WORKDIR /opt/app RUN gradle downloadRepos ADD . /opt/app RUN gradle build -Pspeed=true 

    Vous pouvez envisager de diviser l’image de votre application en deux images: l’une pour créer le fichier myapp.war et l’autre pour exécuter votre application. De cette façon, vous pouvez utiliser les volumes docker lors de la génération réelle et lier le dossier ~/.gradle l’hôte au conteneur effectuant la génération. Au lieu d’une seule étape pour exécuter votre application, vous auriez plus d’étapes, cependant. Exemple:

    image de constructeur

     FROM  # Add project Source # -> you can use a project specific gradle.properties in your project root # in order to override global/user gradle.properties ADD . /var/app/myapp RUN mkdir -p /root/.gradle ENV HOME /root # declare shared volume path VOLUME /root/.gradle WORKDIR /var/app/myapp/ # Comstack only CMD ["./gradlew", "war"] 

    image d’application

     FROM  ADD ./ROOT.war /opt/tomcat/webapps/ROOT.war # Start Tomcat CMD ["/opt/tomcat/bin/catalina.sh", "run"] 

    Comment utiliser dans la racine de votre projet, en supposant que le générateur Dockerfile se trouve à cet emplacement et que l’application Dockerfile se trouve dans le sous-dossier webapp (ou tout autre chemin que vous préférez):

     $ docker build -t builder . $ docker run --name=build-result -v ~/.gradle/:/root/.gradle/ builder $ docker cp build-result:/var/app/myapp/myapp.war webapp/ROOT.war $ cd webapp $ docker build -t application . $ docker run -d -P application 

    Je n’ai pas testé le code indiqué, mais j’espère que vous avez compris l’idée. Cet exemple pourrait même être amélioré en utilisant des volumes de données pour .gradle / cache. Consultez le guide de l’utilisateur de Docker pour plus de détails.

    J’ai fait face à ce problème. Comme vous en conviendrez peut-être, il est recommandé de télécharger les dépendances seules en tant qu’étape distincte lors de la création de l’image du menu fixe. Cela devient un peu délicat avec gradle car il n’existe pas de support direct pour le téléchargement de dépendances.

    Option 1: utilisation de l’image Docker-Docker


    Nous pouvons utiliser une image de docker Gradle pré-construite pour créer l’application. Cela garantit qu’il ne s’agit pas d’une version système locale, mais d’une génération effectuée sur une image propre du menu fixe.

     docker volume create --name gradle-cache docker run --rm -v gradle-cache:/home/gradle/.gradle -v "$PWD":/home/gradle/project -w /home/gradle/project gradle:4.7.0-jdk8-alpine gradle build ls -ltrh ./build/libs 
    • gradle cache est chargé ici en tant que volume. Ainsi, les versions ultérieures réutiliseront les dépendances téléchargées.
    • Après cela, nous pourrions avoir un fichier Dockerfile pour prendre cet artefact et générer une image spécifique à l’application pour exécuter l’application.
    • De cette façon, l’image de générateur n’est pas requirejse. Le stream de construction de l’application et le stream d’exécution de l’application sont séparés.
    • Étant donné que le volume gradle-cache est monté, nous pouvons réutiliser les dépendances téléchargées dans différents projets de gradle.

    Option 2: construction en plusieurs étapes


    —– Dockerfile —–

     FROM openjdk:8 AS TEMP_BUILD_IMAGE ENV APP_HOME=/usr/app/ WORKDIR $APP_HOME COPY build.gradle settings.gradle gradlew $APP_HOME COPY gradle $APP_HOME/gradle RUN ./gradlew build || return 0 COPY . . RUN ./gradlew build FROM openjdk:8 ENV ARTIFACT_NAME=your-application.jar ENV APP_HOME=/usr/app/ WORKDIR $APP_HOME COPY --from=TEMP_BUILD_IMAGE $APP_HOME/build/libs/$ARTIFACT_NAME . EXPOSE 8080 CMD ["java","-jar",$ARTIFACT_NAME] 

    Dans le Dockerfile ci-dessus

    • Nous essayons d’abord de copier les fichiers de gradles du projet, tels que build.gradle, gradlew, etc.,
    • Ensuite, nous copions le répertoire de gradation lui-même
    • Et ensuite, nous essayons de lancer la construction. À ce stade, il n’existe aucun autre fichier de code source dans le répertoire. Donc, la construction échouera. Mais avant cela, il téléchargera les dépendances.
    • Puisque nous nous attendons à ce que la construction échoue, j’ai essayé une technique simple pour renvoyer 0 et permettre au docker de continuer l’exécution.
    • cela accélérera les stream de construction ultérieurs, car toutes les dépendances sont téléchargées et docker met en cache cette couche. Comparativement, le assembly en volume du répertoire de cache Gradle rest la meilleure approche.
    • L’exemple ci-dessus présente également la création d’ images de docker à plusieurs étapes , ce qui évite de créer plusieurs fichiers de docker.

    essayez de changer le répertoire de base de l’utilisateur gradle

    RUN mkdir -p /opt/gradle/.gradle
    ENV GRADLE_USER_HOME = / opt / gradle / .gradle