Download gradle plugin on Docker build and use without network during Docker run

Viewed 449

I am working on a Spring boot project where the deployment happens in Kubernetes. The gradle and docker configurations are such that it downloads all the dependencies into the docker image's libs directory during docker build and get the dependencies from libs during docker run.

This setting makes the docker run (which executes gradle build again) successful, even if I cut internet during this process.

build.gradle

plugins {
  id 'java'
}

ext {
    skipDownload = project.hasProperty('skipDownload') ? project.getProperty('skipDownload') as boolean : false
}

repositories {
    mavenLocal()
    if (skipDownload) {
        flatDir {
            dirs 'libs'
        }
    } else {
        mavenCentral()
    }
}

dependencies {
  if (skipDownload) {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation fileTree(dir: 'testlibs', include: ['*.jar'])
  } else {
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.6.3'
  }
}

task getDeps(type: Copy) {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    from configurations.compileClasspath into "libs/"
    from configurations.runtimeClasspath into "libs/"
}

task getTestDeps(type: Copy) {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    from configurations.testCompileClasspath into "testlibs/"
    from configurations.testRuntimeClasspath into "testlibs/"
}

Dockerfile

FROM gradle:7.3-jdk11
WORKDIR /app
COPY . .
RUN gradle --no-daemon test getDeps getTestDeps
CMD ["sh", "gradle bootRun"] // for this testing I will later change to gradle build during docker run command

Docker build

docker build -t service-test .

Docker run - AFTER CUTTING THE INTERNET

docker run --rm -it service-test gradle build -PskipDownload=true

These steps has been successful as expected. But when I add another plugin,as shown below, to support gradle booRun the step "Docker run - AFTER CUTTING THE INTERNET" is failing with the following error.

plugins {
  id 'org.springframework.boot' version '2.6.3'
  id 'java'
}

Plugin [id: 'org.springframework.boot', version: '2.6.3'] was not found in any of the following sources:

  • Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
  • Plugin Repositories (could not resolve plugin artifact 'org.springframework.boot:org.springframework.boot.gradle.plugin:2.6.3') Searched in the following repositories: Gradle Central Plugin Repository

Please direct me to fix this issue. I need to run the container offline.

1 Answers

The issue you have is that you override only the dependency repository, not the plugin repository. These are handled separately. In the case of the java plugin, this is part of gradles core plugins and is available locally through gradle itself.

Third-party plugins like spring need to be downloaded from a plugin repository. By default, this is the Gradle plugin repository. You can override this in a settings.gradle file.

For example:

pluginManagement {
    repositories {
        gradlePluginPortal()
        flatDir {
            dirs 'lib'
        }
        ...
    }
}

But you probably don't even have to change this. You could just download the plugins in your first (online) build cycle and then copy the gradle cache inside the docker. You should also use the --offline flag for your second build cycle to indicate that no network access is allowed.

The default cache location is ~/.gradle/caches/. In my case, all dependencies (including plugins) cached by gradle were under ~/.gradle/caches/modules-2/files-2.1/.

Some helpful links:
Plugin Management
Plugin vs. Build Repos
Repository Types
Execution Options (--offline)
sync gradle dependencies to local maven reposity

Related