Docker cache gradle dependencies

I’m trying to deploy our java web application to aws elastic beanstalk using docker, the idea is to be able to run the container locally for development and testing and eventually push it up to production using git.

I’ve created a base image that has tomcat8 and java8 installed, the image that performs the gradle builds inherit from this base image, speeding up build process.

  • crontab does not get the log in log file
  • Live reload Node.js dev environment with Docker
  • EC2 Container Service Networking
  • Allow communication between two docker bridge networks using docker-compose
  • Trouble getting AWS ecs-cli to pull from private docker repo
  • Is it possible to define Docker data volume on S3?
  • All works well, except for the fact that the inheriting application container that gets built using docker doesn’t seem to cache the gradle dependencies, it downloads it every time, including gradlew. We build our web application using the following command:

    ./gradlew war

    Is there some way that i can cache the files in ~/.gradle this would speed my build up dramatically

    This isn’t so much of an issue on beanstalk but is a big problem for devs trying to build and run locally as this does take a lot of time, as you can imagine

    base image dockerfile:

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

    application image:

    FROM <tag name here for base image>
    
    RUN mkdir ~/.gradle
    # run some extra stuff here to add things to gradle.properties file
    
    # Add project Source
    ADD . /var/app/myapp
    
    # Compile 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"]
    

  • How to create a shared volume between docker host and container in Mac
  • Multiple dokku apps one domain
  • get docker images command's output with bash script
  • How to backup root-ca-only from UCP replica
  • How could I run nginx-naxsi in baseimage?
  • Database Fails to Start - Host Directory as a Data Volume
  • 3 Solutions collect form web for “Docker cache gradle dependencies”

    You might want to consider splitting your application image to two images: one for building the myapp.war and the other for running your application. That way, you can use docker volumes during the actual build and bind the host’s ~/.gradle folder into the container performing the build. Instead of only one step to run your application, you would have more steps, though. Example:

    builder image

    FROM <tag name here for base image including all build time dependencies>
    
    # 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/ 
    
    # Compile only
    CMD ["./gradlew", "war"]
    

    application image

    FROM <tag name here for application base image>
    
    ADD ./ROOT.war /opt/tomcat/webapps/ROOT.war
    
    # Start Tomcat
    CMD ["/opt/tomcat/bin/catalina.sh", "run"]
    

    How to use in your project root, assuming the builder Dockerfile is located there and the application Dockerfile is located at the webapp subfolder (or any other path you prefer):

    $ 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
    

    I haven’t tested the shown code, but I hope you get the idea. The example might even be improved by using data volumes for the .gradle/ cache, see the Docker user guide for details.

    I

    Add resolveDependencies task in build.gradle:

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

    and update 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

    Bellow is what I do now:

    build.gradle

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

    Dockerfile

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

    try changing the gradle user home directory

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

    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.