You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2021/01/27 17:33:32 UTC

[lucene-solr] 09/10: SOLR-15075: Solr docker gradle improvements (#2197)

This is an automated email from the ASF dual-hosted git repository.

houston pushed a commit to branch reference_impl_dev
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 241994f4d07858fa509f76437e328d89dfe51c49
Author: Houston Putman <ho...@apache.org>
AuthorDate: Tue Jan 26 10:22:50 2021 -0500

    SOLR-15075: Solr docker gradle improvements (#2197)
    
    * Removed docker plugin from gradle builds.
    * Removed package docker image.
    * Tasks now have correct inputs/outputs/dependencies.
    * Move gradle help text to docker folder.
    * Reduce duplicated Docker layer by doing file removal and chmod in another stage.
    
    Co-authored-by: David Smiley <ds...@apache.org>
---
 .github/workflows/docker-test.yml                  |   2 +
 build.gradle                                       |   2 +-
 gradle/help.gradle                                 |   2 +-
 help/docker.txt                                    |  58 ------
 settings.gradle                                    |   2 -
 solr/docker/Dockerfile                             |  38 ++--
 solr/docker/README.md                              |   2 +-
 solr/docker/build.gradle                           | 210 +++++++++++++++------
 solr/docker/gradle-help.txt                        |  80 ++++++++
 solr/docker/package/Dockerfile.local-package       |   3 -
 solr/docker/package/Dockerfile.release-package     |  74 --------
 solr/docker/package/build.gradle                   |  36 ----
 .../{include => }/scripts/docker-entrypoint.sh     |   0
 solr/docker/{include => }/scripts/init-var-solr    |   0
 solr/docker/{include => }/scripts/oom_solr.sh      |   0
 solr/docker/{include => }/scripts/precreate-core   |   0
 solr/docker/{include => }/scripts/run-initdb       |   0
 solr/docker/{include => }/scripts/solr-create      |   0
 solr/docker/{include => }/scripts/solr-demo        |   0
 solr/docker/{include => }/scripts/solr-fg          |   0
 solr/docker/{include => }/scripts/solr-foreground  |   0
 solr/docker/{include => }/scripts/solr-precreate   |   0
 solr/docker/{include => }/scripts/start-local-solr |   0
 solr/docker/{include => }/scripts/stop-local-solr  |   0
 solr/docker/{include => }/scripts/wait-for-solr.sh |   0
 .../{include => }/scripts/wait-for-zookeeper.sh    |   0
 solr/docker/tests/cases/gosu/test.sh               |   2 +-
 27 files changed, 256 insertions(+), 255 deletions(-)

diff --git a/.github/workflows/docker-test.yml b/.github/workflows/docker-test.yml
index 76fa714..d331df9 100644
--- a/.github/workflows/docker-test.yml
+++ b/.github/workflows/docker-test.yml
@@ -38,6 +38,8 @@ jobs:
         restore-keys: |
           ${{ runner.os }}-gradle-docker-
           ${{ runner.os }}-gradle-
+    - name: Initialize gradle settings
+      run: ./gradlew localSettings
     - name: Build Docker image with Gradle
       run: ./gradlew solr:docker:docker
     - name: Run tests on Docker image
diff --git a/build.gradle b/build.gradle
index 9efac5b..ada78df 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,7 +25,7 @@ plugins {
   id 'de.thetaphi.forbiddenapis' version '3.0.1' apply false
   id "de.undercouch.download" version "4.0.2" apply false
   id "net.ltgt.errorprone" version "1.2.1" apply false
-  id "com.palantir.docker" version "0.25.0" apply false
+  id 'com.diffplug.spotless' version "5.8.2" apply false
 }
 
 apply from: file('gradle/defaults.gradle')
diff --git a/gradle/help.gradle b/gradle/help.gradle
index 4c1bf7e..6be1ae7 100644
--- a/gradle/help.gradle
+++ b/gradle/help.gradle
@@ -29,7 +29,7 @@ configure(rootProject) {
       ["Git", "help/git.txt", "Git assistance and guides."],
       ["ValidateLogCalls", "help/validateLogCalls.txt", "How to use logging calls efficiently."],
       ["IDEs", "help/IDEs.txt", "IDE support."],
-      ["Docker", "help/docker.txt", "Building Solr Docker images."],
+      ["Docker", "solr/docker/gradle-help.txt", "Building Solr Docker images."],
   ]
 
   helpFiles.each { section, path, sectionInfo ->
diff --git a/help/docker.txt b/help/docker.txt
deleted file mode 100644
index c86572c..0000000
--- a/help/docker.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-Docker Images for Solr
-======================
-
-Solr docker images are built using Palantir's Docker Gradle plugin, https://github.com/palantir/gradle-docker.
-
-Common Inputs
--------------
-
-The docker image and its tag can be customized via the following options, all accepted via both Environment Variables and Gradle Properties.
-
-Docker Image Repository:
-   Default: "apache/solr"
-   EnvVar: SOLR_DOCKER_IMAGE_REPO
-   Gradle Property: -Psolr.docker.imageRepo
-
-Docker Image Tag:
-   Default: the Solr version, e.g. "9.0.0-SNAPSHOT"
-   EnvVar: SOLR_DOCKER_IMAGE_TAG
-   Gradle Property: -Psolr.docker.imageTag
-
-Docker Image Name: (Use this to explicitly set a whole image name. If given, the image repo and image version options above are ignored.)
-   Default: {image_repo}/{image_tag} (both options provided above, with defaults)
-   EnvVar: SOLR_DOCKER_IMAGE_NAME
-   Gradle Property: -Psolr.docker.imageName
-
-Building
---------
-
-In order to build the Solr Docker image, run:
-
-gradlew docker
-
-The docker build task accepts the following inputs, in addition to the common inputs listed above:
-
-Base Docker Image: (The docker image used for the "FROM" in the Solr Dockerfile)
-   Default: "openjdk:11-jre-slim"
-   EnvVar: SOLR_DOCKER_BASE_IMAGE
-   Gradle Property: -Psolr.docker.baseImage
-
-Github URL or Mirror: (The URL of github or a mirror of github releases. This is of use when building the docker image behind a firewall that does not have access to external Github.)
-   Default: "github.com"
-   EnvVar: SOLR_DOCKER_GITHUB_URL
-   Gradle Property: -Psolr.docker.githubUrl
-
-Testing
--------
-
-To test the docker image, run:
-
-gradlew dockerTest
-
-If a custom docker image name was used, via one of the common inputs described above, then the same input must be used while testing.
-
-You can also specify an explicit list of tests to run, or an explicit list of tests to ignore.
-Both inputs are optional, and by default all tests will be run.
-
-gradlew testDocker --tests create_core,demo
-gradlew testDocker --ignore demo-tini,initdb
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 069d126..28b0868 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -73,7 +73,6 @@ include "solr:example"
 
 include "solr:packaging"
 include "solr:docker"
-include "solr:docker:package"
 
 include "solr:benchmark"
 
@@ -91,4 +90,3 @@ include "solr:benchmark"
 
 
 include "solr:benchmark"
-
diff --git a/solr/docker/Dockerfile b/solr/docker/Dockerfile
index 0e7157e..d1a0db1 100644
--- a/solr/docker/Dockerfile
+++ b/solr/docker/Dockerfile
@@ -1,9 +1,21 @@
-ARG SOLR_PACKAGE_IMAGE
 ARG BASE_IMAGE=openjdk:11-jre-slim
 
-FROM $SOLR_PACKAGE_IMAGE as solr_package
+FROM $BASE_IMAGE as input
+ARG SOLR_VERSION
+
+# ADD extracts tgz !
+ADD /releases/solr-$SOLR_VERSION.tgz /opt/
+COPY /scripts /scripts
 
-FROM $BASE_IMAGE as runtime
+# remove what we don't want; ensure permissions are right
+#  TODO; arguably these permissions should have been set correctly previously in the TAR
+RUN set -ex; \
+  rm -Rf /opt/solr-$SOLR_VERSION/docs /opt/solr-$SOLR_VERSION/dist/{solr-solrj-$SOLR_VERSION.jar,solrj-lib,solr-test-framework-$SOLR_VERSION.jar,test-framework}; \
+  find "/opt/solr-$SOLR_VERSION" -type d -print0 | xargs -0 chmod 0755; \
+  find "/opt/solr-$SOLR_VERSION" -type f -print0 | xargs -0 chmod 0644; \
+  chmod -R 0755 /scripts "/opt/solr-$SOLR_VERSION/bin" "/opt/solr-$SOLR_VERSION/contrib/prometheus-exporter/bin/solr-exporter" "/opt/solr-$SOLR_VERSION/server/scripts/cloud-scripts"
+
+FROM $BASE_IMAGE
 
 LABEL maintainer="The Apache Lucene/Solr Project"
 LABEL repository="https://github.com/apache/lucene-solr"
@@ -13,7 +25,7 @@ ARG GITHUB_URL=github.com
 
 RUN set -ex; \
     apt-get update; \
-    apt-get -y install acl dirmngr gpg lsof procps wget netcat gosu tini; \
+    apt-get -y install acl dirmngr lsof procps wget netcat gosu tini; \
     rm -rf /var/lib/apt/lists/*; \
     cd /usr/local/bin; wget -nv https://${GITHUB_URL}/apangin/jattach/releases/download/v1.5/jattach; chmod 755 jattach; \
     echo >jattach.sha512 "d8eedbb3e192a8596c08efedff99b9acf1075331e1747107c07cdb1718db2abe259ef168109e46bd4cf80d47d43028ff469f95e6ddcbdda4d7ffa73a20e852f9  jattach"; \
@@ -35,31 +47,25 @@ RUN set -ex; \
   groupadd -r --gid "$SOLR_GID" "$SOLR_GROUP"; \
   useradd -r --uid "$SOLR_UID" --gid "$SOLR_GID" "$SOLR_USER"
 
-COPY --chown=0:0 scripts /opt/docker-solr/scripts
+COPY --from=input scripts /opt/docker-solr/scripts
 
 ARG SOLR_VERSION
 
-COPY --from=solr_package "/opt/solr-$SOLR_VERSION.tgz" "/opt/solr-$SOLR_VERSION.tgz"
+# Used by solr-fg
+ENV SOLR_VERSION $SOLR_VERSION
+
+COPY --from=input /opt/solr-$SOLR_VERSION /opt/solr-$SOLR_VERSION
 
 RUN set -ex; \
-  tar -C /opt --extract --file "/opt/solr-$SOLR_VERSION.tgz" && \
-  rm "/opt/solr-$SOLR_VERSION.tgz"; \
   (cd /opt; ln -s "solr-$SOLR_VERSION" solr); \
-  rm -Rf /opt/solr/docs/ /opt/solr/dist/{solr-solrj-$SOLR_VERSION.jar,solrj-lib,solr-test-framework-$SOLR_VERSION.jar,test-framework}; \
-  mkdir -p /opt/solr/server/solr/lib /docker-entrypoint-initdb.d /opt/docker-solr; \
-  chown -R 0:0 "/opt/solr-$SOLR_VERSION"; \
-  find "/opt/solr-$SOLR_VERSION" -type d -print0 | xargs -0 chmod 0755; \
-  find "/opt/solr-$SOLR_VERSION" -type f -print0 | xargs -0 chmod 0644; \
-  chmod -R 0755 "/opt/solr-$SOLR_VERSION/bin" "/opt/solr-$SOLR_VERSION/contrib/prometheus-exporter/bin/solr-exporter" /opt/solr-$SOLR_VERSION/server/scripts/cloud-scripts; \
+  mkdir -p /opt/solr/server/solr/lib /docker-entrypoint-initdb.d; \
   cp /opt/solr/bin/solr.in.sh /etc/default/solr.in.sh; \
   mv /opt/solr/bin/solr.in.sh /opt/solr/bin/solr.in.sh.orig; \
   mv /opt/solr/bin/solr.in.cmd /opt/solr/bin/solr.in.cmd.orig; \
-  chown root:0 /etc/default/solr.in.sh; \
   chmod 0664 /etc/default/solr.in.sh; \
   mkdir -p -m0770 /var/solr; \
   sed -i -e "s/\"\$(whoami)\" == \"root\"/\$(id -u) == 0/" /opt/solr/bin/solr; \
   sed -i -e 's/lsof -PniTCP:/lsof -t -PniTCP:/' /opt/solr/bin/solr; \
-  chown -R "0:0" /opt/solr-$SOLR_VERSION /docker-entrypoint-initdb.d /opt/docker-solr; \
   chown -R "$SOLR_USER:0" /var/solr;
 
 VOLUME /var/solr
diff --git a/solr/docker/README.md b/solr/docker/README.md
index 3356419..abd155e 100644
--- a/solr/docker/README.md
+++ b/solr/docker/README.md
@@ -76,7 +76,7 @@ If you want to persist the data, mount a volume or directory on `/var/solr`.
 Solr expects some files and directories in `/var/solr`; if you use your own directory or volume you can either pre-populate them, or let Solr docker copy them for you. See [init-var-solr](scripts/init-var-solr).
 If you want to use custom configuration, mount it in the appropriate place. See below for examples.
 
-The Solr docker distribution adds [scripts](include/scripts) in `/opt/docker-solr/scripts` to make it easier to use under Docker, for example to create cores on container startup.
+The Solr docker distribution adds [scripts](scripts) in `/opt/docker-solr/scripts` to make it easier to use under Docker, for example to create cores on container startup.
 
 ## Creating cores
 
diff --git a/solr/docker/build.gradle b/solr/docker/build.gradle
index d6e80ac..723f664 100644
--- a/solr/docker/build.gradle
+++ b/solr/docker/build.gradle
@@ -18,106 +18,192 @@
 import com.google.common.base.Preconditions
 import com.google.common.base.Strings
 
-apply plugin: 'base'
-apply plugin: 'com.palantir.docker'
-
-subprojects {
-  apply plugin: 'base'
-  apply plugin: 'com.palantir.docker'
-}
-
 description = 'Solr Docker image'
 
-def dockerPackage = project(':solr:docker:package')
-
-dependencies {
-  docker dockerPackage
-}
+apply plugin: 'base'
 
+// Solr Docker inputs
 def dockerImageRepo = propertyOrEnvOrDefault("solr.docker.imageRepo", "SOLR_DOCKER_IMAGE_REPO", "apache/solr")
 def dockerImageTag = propertyOrEnvOrDefault("solr.docker.imageTag", "SOLR_DOCKER_IMAGE_TAG", "${version}")
 def dockerImageName = propertyOrEnvOrDefault("solr.docker.imageName", "SOLR_DOCKER_IMAGE_NAME", "${dockerImageRepo}:${dockerImageTag}")
 def baseDockerImage = propertyOrEnvOrDefault("solr.docker.baseImage", "SOLR_DOCKER_BASE_IMAGE", 'openjdk:11-jre-slim')
 def githubUrlOrMirror = propertyOrEnvOrDefault("solr.docker.githubUrl", "SOLR_DOCKER_GITHUB_URL", 'github.com')
 
-docker {
-  name = dockerImageName
-  files file('include')
-  buildArgs(['BASE_IMAGE' : baseDockerImage, 'SOLR_PACKAGE_IMAGE' : 'apache/solr-build:local-package', 'SOLR_VERSION': "${version}", 'GITHUB_URL': githubUrlOrMirror])
+// Build directory locations
+def dockerBuildDistribution = "$buildDir/distributions"
+def imageIdFile = "$buildDir/image-id"
+
+configurations {
+  packaging {
+    canBeResolved = true
+  }
+  dockerImage {
+    canBeResolved = true
+  }
+}
+
+dependencies {
+  packaging project(path: ":solr:packaging", configuration: 'archives')
+
+  dockerImage files(imageIdFile) {
+    builtBy 'dockerBuild'
+  }
 }
 
-tasks.docker {
-  // In order to create the solr docker image, the solr package image must be created first.
-  dependsOn(dockerPackage.tasks.docker)
+task dockerTar(type: Tar) {
+  group = 'Docker'
+  description = 'Package docker context to prepare for docker build'
+
+  dependsOn configurations.packaging
+  into('scripts') {
+    from file('scripts')
+    fileMode 755
+  }
+  into('releases') {
+    from configurations.packaging
+    include '*.tgz'
+  }
+  from file('Dockerfile')
+  destinationDirectory = file(dockerBuildDistribution)
+  extension 'tgz'
+  compression = Compression.GZIP
+}
+
+task dockerBuild(dependsOn: tasks.dockerTar) {
+  group = 'Docker'
+  description = 'Build Solr docker image'
+
+  // Ensure that the docker image is rebuilt on build-arg changes or changes in the docker context
+  inputs.properties([
+          baseDockerImage: baseDockerImage,
+          githubUrlOrMirror: githubUrlOrMirror,
+          version: version
+  ])
+  inputs.dir(dockerBuildDistribution)
+
+  doLast {
+    exec {
+      standardInput = tasks.dockerTar.outputs.files.singleFile.newDataInputStream()
+      commandLine "docker", "build",
+              "--iidfile", imageIdFile,
+              "--build-arg", "BASE_IMAGE=${inputs.properties.baseDockerImage}",
+              "--build-arg", "SOLR_VERSION=${version}",
+              "--build-arg", "GITHUB_URL=${inputs.properties.githubUrlOrMirror}",
+              "-"
+    }
+  }
 
   // Print information on the image after it has been created
   doLast {
+    def dockerImageId = file(imageIdFile).text
     project.logger.lifecycle("Solr Docker Image Created")
-    project.logger.lifecycle("\tName: $dockerImageName")
-    project.logger.lifecycle("\tBase Image: $baseDockerImage")
+    project.logger.lifecycle("\tID: \t$dockerImageId")
+    project.logger.lifecycle("\tBase Image: \t$baseDockerImage")
+    project.logger.lifecycle("\tSolr Version: \t$version")
   }
+
+  outputs.files(imageIdFile)
 }
 
-abstract class DockerTestSuite extends DefaultTask {
-  private String solrImageName = null;
-  private List<String> tests = new ArrayList<>();
-  private List<String> ignore = new ArrayList<>();
+task dockerTag(dependsOn: tasks.dockerBuild) {
+  group = 'Docker'
+  description = 'Tag Solr docker image'
 
-  @OutputDirectory
-  abstract DirectoryProperty getOutputDir()
+  def dockerImageIdFile = file(imageIdFile)
+  // Ensure that the docker image is re-tagged if the image ID or desired tag changes
+  inputs.properties([
+          dockerImageName: dockerImageName,
+  ])
+  inputs.file(dockerImageIdFile)
 
-  public void setSolrImageName(String solrImageName) {
-    this.solrImageName = solrImageName
-  }
+  doLast {
+    def dockerImageId = dockerImageIdFile.text
 
-  public String getSolrImageName() {
-    Preconditions.checkArgument(!Strings.isNullOrEmpty(solrImageName), "solrImageName is a required dockerTests configuration item.")
-    return solrImageName
-  }
+    exec {
+      commandLine "docker", "tag", dockerImageId, inputs.properties.dockerImageName
+    }
 
-  @Option(option = "tests", description = "Only run these specified tests, comma separated.")
-  public void setTests(List<String> tests) {
-    this.tests = tests;
+    // Print information on the image after it has been created
+    project.logger.lifecycle("Solr Docker Image Tagged")
+    project.logger.lifecycle("\tID: \t$dockerImageId")
+    project.logger.lifecycle("\tTag: \t$dockerImageName")
   }
+}
 
-  @Input
-  public List<String> getTests() {
-    return tests;
-  }
+task testDocker(dependsOn: tasks.dockerBuild) {
+  group = 'Docker'
+  description = 'Test Solr docker image'
 
-  @Option(option = "ignore", description = "Ignore these tests, comma separated.")
-  public void setIgnore(List<String> ignore) {
-    this.ignore = ignore;
-  }
+  def inputDir = "tests/cases"
+  def outputDir = "$buildDir/tmp/tests"
 
-  @Input
-  public List<String> getIgnore() {
-    return ignore;
-  }
+  // Ensure that the docker image is re-tested if the image ID changes or the test files change
+  inputs.properties([
+          includeTests: new HashSet(Arrays.asList(propertyOrEnvOrDefault("solr.docker.tests.include", "SOLR_DOCKER_TESTS_INCLUDE", ",").split(","))),
+          excludeTests: new HashSet(Arrays.asList(propertyOrEnvOrDefault("solr.docker.tests.exclude", "SOLR_DOCKER_TESTS_EXCLUDE", ",").split(",")))
+  ])
+  inputs.file(imageIdFile)
+  inputs.dir(inputDir)
+
+  doLast {
+    def solrImageId = tasks.dockerBuild.outputs.files.singleFile.text
+    def solrImageName = solrImageId.substring(7, 14)
 
-  @TaskAction
-  void execute() {
     // Print information on the image before it is tested
-    project.logger.lifecycle("Testing Solr Image: $solrImageName\n")
-    def sourceDir = project.file("tests/cases")
+    logger.lifecycle("Testing Solr Image:")
+    logger.lifecycle("\tID: $solrImageId\n")
+
+    // Run the tests
+    def sourceDir = file(inputDir)
     sourceDir.eachFile  { file ->
       def testName = file.getName()
-      def testCaseBuildDir = outputDir.dir(testName).get().toString()
+      def testCaseBuildDir = "${outputDir}/${testName}"
 
       // If specific tests are specified, only run those. Otherwise run all that are not ignored.
-      def runTest = !this.tests.isEmpty() ? tests.contains(testName) : !ignore.contains(testName)
+      def runTest = !inputs.properties.includeTests.isEmpty() ? inputs.properties.includeTests.contains(testName) : !inputs.properties.excludeTests.contains(testName)
       if (runTest) {
-        project.exec {
-          environment "TEST_DIR", "$file"
-          environment "BUILD_DIR", "$testCaseBuildDir"
+        exec {
+          environment "TEST_DIR", file
+          environment "BUILD_DIR", testCaseBuildDir
           commandLine "bash", "$file/test.sh", solrImageName
         }
       }
     }
   }
+
+  outputs.dir(outputDir)
 }
 
-task testDocker(type: DockerTestSuite) {
-  outputDir = project.file("$buildDir/tmp/tests")
-  solrImageName = dockerImageName
+task dockerPush(dependsOn: tasks.dockerTag) {
+  group = 'Docker'
+  description = 'Push Solr docker image'
+
+  // Ensure that the docker image is re-pushed if the image ID or tag changes
+  inputs.properties([
+          dockerImageName: dockerImageName,
+  ])
+  inputs.file(imageIdFile)
+
+  // We don't want to push a docker image unless the tests have passed
+  mustRunAfter tasks.testDocker
+
+  doLast {
+    exec {
+      commandLine "docker", "push", dockerImageName
+    }
+
+    // Print information on the image after it has been created
+    project.logger.lifecycle("Solr Docker Image Pushed: \t$dockerImageName")
+  }
+}
+
+// One task to build and tag a Solr docker image
+task docker {
+  dependsOn tasks.dockerBuild, tasks.dockerTag
+}
+
+artifacts {
+  dockerImage(tasks.dockerBuild.outputs.files.singleFile) {
+    builtBy(tasks.dockerBuild)
+  }
 }
\ No newline at end of file
diff --git a/solr/docker/gradle-help.txt b/solr/docker/gradle-help.txt
new file mode 100644
index 0000000..63ad735
--- /dev/null
+++ b/solr/docker/gradle-help.txt
@@ -0,0 +1,80 @@
+Docker Images for Solr
+======================
+
+In order to build and tag a Solr docker image, merely run the following command:
+
+gradlew docker
+
+This calls the dockerBuild and dockerTag tasks, which have inputs that are described below.
+
+Building
+--------
+
+In order to build the Solr Docker image, run:
+
+gradlew dockerBuild
+
+The docker build task accepts the following inputs, all accepted via both Environment Variables and Gradle Properties.
+
+Base Docker Image: (The docker image used for the "FROM" in the Solr Dockerfile)
+   Default: "openjdk:11-jre-slim"
+   EnvVar: SOLR_DOCKER_BASE_IMAGE
+   Gradle Property: -Psolr.docker.baseImage
+
+Github URL or Mirror: (The URL of github or a mirror of github releases. This is of use when building the docker image behind a firewall that does not have access to external Github.)
+   Default: "github.com"
+   EnvVar: SOLR_DOCKER_GITHUB_URL
+   Gradle Property: -Psolr.docker.githubUrl
+
+Tagging and Pushing
+-------
+
+To tag the docker image, run the following command.
+This will also ensure that the docker image has been built as per the inputs detailed above.
+
+gradlew dockerTag
+
+And to push the image with the given tag, run the following command.
+Gradle will ensure that the docker image is built and tagged as the inputs describe before being pushed.
+
+gradlew dockerPush
+
+The docker image tag can be customized via the following options, all accepted via both Environment Variables and Gradle Properties.
+
+Docker Image Repository:
+   Default: "apache/solr"
+   EnvVar: SOLR_DOCKER_IMAGE_REPO
+   Gradle Property: -Psolr.docker.imageRepo
+
+Docker Image Tag:
+   Default: the Solr version, e.g. "9.0.0-SNAPSHOT"
+   EnvVar: SOLR_DOCKER_IMAGE_TAG
+   Gradle Property: -Psolr.docker.imageTag
+
+Docker Image Name: (Use this to explicitly set a whole image name. If given, the image repo and image version options above are ignored.)
+   Default: {image_repo}/{image_tag} (both options provided above, with defaults)
+   EnvVar: SOLR_DOCKER_IMAGE_NAME
+   Gradle Property: -Psolr.docker.imageName
+
+Testing
+-------
+
+To test the docker image, run the following command.
+This will also ensure that the docker image has been built as per the inputs detailed above in the "Building" section.
+
+gradlew testDocker
+
+If a docker image build parameters were used during building, then the same inputs must be used while testing.
+Otherwise a new docker image will be built for the tests to run with.
+
+You can also specify an explicit list of tests to run, or an explicit list of tests to ignore.
+Both inputs are optional, and by default all tests will be run.
+Each input tasks a comma separated list of test names.
+
+Run specific tests:
+   EnvVar: SOLR_DOCKER_TESTS_INCLUDE
+   Gradle Property: -Psolr.docker.tests.include
+
+Exclude specific tests:
+   EnvVar: SOLR_DOCKER_TESTS_EXCLUDE
+   Gradle Property: -Psolr.docker.tests.exclude
diff --git a/solr/docker/package/Dockerfile.local-package b/solr/docker/package/Dockerfile.local-package
deleted file mode 100644
index e37d67f..0000000
--- a/solr/docker/package/Dockerfile.local-package
+++ /dev/null
@@ -1,3 +0,0 @@
-FROM scratch
-
-COPY releases/ /opt/
\ No newline at end of file
diff --git a/solr/docker/package/Dockerfile.release-package b/solr/docker/package/Dockerfile.release-package
deleted file mode 100644
index 85947c9..0000000
--- a/solr/docker/package/Dockerfile.release-package
+++ /dev/null
@@ -1,74 +0,0 @@
-ARG BASE_IMAGE=openjdk:11-jre
-
-FROM $BASE_IMAGE as downloader
-
-ARG SOLR_VERSION
-ARG SOLR_SHA512
-ARG SOLR_KEYS
-# If specified, this will override SOLR_DOWNLOAD_SERVER and all ASF mirrors. Typically used downstream for custom builds
-ARG SOLR_DOWNLOAD_URL
-
-# Override the solr download location with e.g.:
-#   docker build -t mine --build-arg SOLR_DOWNLOAD_SERVER=http://www-eu.apache.org/dist/lucene/solr .
-ARG SOLR_DOWNLOAD_SERVER
-# This is only applicable when SOLR_DOWNLOAD_URL is not provided. Skips the GPG check for Solr downloads.
-ARG SKIP_GPG_CHECK="true"
-
-ENV SOLR_CLOSER_URL="http://www.apache.org/dyn/closer.lua?filename=lucene/solr/$SOLR_VERSION/solr-$SOLR_VERSION.tgz&action=download" \
-    SOLR_DIST_URL="https://www.apache.org/dist/lucene/solr/$SOLR_VERSION/solr-$SOLR_VERSION.tgz" \
-    SOLR_ARCHIVE_URL="https://archive.apache.org/dist/lucene/solr/$SOLR_VERSION/solr-$SOLR_VERSION.tgz"
-
-RUN set -ex; \
-    apt-get update; \
-    apt-get -y install dirmngr gpg wget; \
-    rm -rf /var/lib/apt/lists/*;
-
-RUN set -ex; \
-  export GNUPGHOME="/tmp/gnupg_home"; \
-  mkdir -p "$GNUPGHOME"; \
-  chmod 700 "$GNUPGHOME"; \
-  echo "disable-ipv6" >> "$GNUPGHOME/dirmngr.conf"; \
-  for key in $SOLR_KEYS; do \
-    found=''; \
-    for server in \
-      ha.pool.sks-keyservers.net \
-      hkp://keyserver.ubuntu.com:80 \
-      hkp://p80.pool.sks-keyservers.net:80 \
-      pgp.mit.edu \
-    ; do \
-      echo "  trying $server for $key"; \
-      gpg --batch --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$key" && found=yes && break; \
-      gpg --batch --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$key" && found=yes && break; \
-    done; \
-    test -z "$found" && echo >&2 "error: failed to fetch $key from several disparate servers -- network issues?" && exit 1; \
-  done; \
-  exit 0
-
-RUN set -ex; \
-  export GNUPGHOME="/tmp/gnupg_home"; \
-  MAX_REDIRECTS=1; \
-  if [ -n "$SOLR_DOWNLOAD_URL" ]; then \
-    # If a custom URL is defined, we download from non-ASF mirror URL and allow more redirects and skip GPG step
-    # This takes effect only if the SOLR_DOWNLOAD_URL build-arg is specified, typically in downstream Dockerfiles
-    MAX_REDIRECTS=4; \
-    SKIP_GPG_CHECK="true"; \
-  elif [ -n "$SOLR_DOWNLOAD_SERVER" ]; then \
-    SOLR_DOWNLOAD_URL="$SOLR_DOWNLOAD_SERVER/$SOLR_VERSION/solr-$SOLR_VERSION.tgz"; \
-  fi; \
-  for url in $SOLR_DOWNLOAD_URL $SOLR_CLOSER_URL $SOLR_DIST_URL $SOLR_ARCHIVE_URL; do \
-    if [ -f "/opt/solr-$SOLR_VERSION.tgz" ]; then break; fi; \
-    echo "downloading $url"; \
-    if wget -t 10 --max-redirect $MAX_REDIRECTS --retry-connrefused -nv "$url" -O "/opt/solr-$SOLR_VERSION.tgz"; then break; else rm -f "/opt/solr-$SOLR_VERSION.tgz"; fi; \
-  done; \
-  if [ ! -f "/opt/solr-$SOLR_VERSION.tgz" ]; then echo "failed all download attempts for solr-$SOLR_VERSION.tgz"; exit 1; fi; \
-  if [ "$SKIP_GPG_CHECK" != "true" ]; then \
-    echo "downloading $SOLR_ARCHIVE_URL.asc"; \
-    wget -nv "$SOLR_ARCHIVE_URL.asc" -O "/opt/solr-$SOLR_VERSION.tgz.asc"; \
-    echo "$SOLR_SHA512 */opt/solr-$SOLR_VERSION.tgz" | sha512sum -c -; \
-    (>&2 ls -l "/opt/solr-$SOLR_VERSION.tgz" "/opt/solr-$SOLR_VERSION.tgz.asc"); \
-    gpg --batch --verify "/opt/solr-$SOLR_VERSION.tgz.asc" "/opt/solr-$SOLR_VERSION.tgz"; \
-  else \
-    echo "Skipping GPG validation due to non-Apache build"; \
-  fi; \
-  { command -v gpgconf; gpgconf --kill all || :; }; \
-  rm -r "$GNUPGHOME";
diff --git a/solr/docker/package/build.gradle b/solr/docker/package/build.gradle
deleted file mode 100644
index 94cbfdb..0000000
--- a/solr/docker/package/build.gradle
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-description = 'Solr Docker Package image'
-
-// The solr package docker image relies on the output of the solr:packaging project.
-Project solrPackaging = project(':solr:packaging')
-
-dependencies {
-  docker solrPackaging
-}
-
-docker {
-  name = 'apache/solr-build:local-package'
-  dockerfile file('Dockerfile.local-package')
-  files(solrPackaging.tasks.distTar.outputs)
-  getCopySpec().into('releases')
-}
-
-// Only allow the following docker tasks
-def availableDockerTasks = ["docker", "dockerClean", "dockerPrepare", "dockerfileZip"]
-project.tasks.configureEach { t -> t.enabled = t.getGroup() != "Docker" || availableDockerTasks.contains(t.getName()) }
diff --git a/solr/docker/include/scripts/docker-entrypoint.sh b/solr/docker/scripts/docker-entrypoint.sh
similarity index 100%
rename from solr/docker/include/scripts/docker-entrypoint.sh
rename to solr/docker/scripts/docker-entrypoint.sh
diff --git a/solr/docker/include/scripts/init-var-solr b/solr/docker/scripts/init-var-solr
similarity index 100%
rename from solr/docker/include/scripts/init-var-solr
rename to solr/docker/scripts/init-var-solr
diff --git a/solr/docker/include/scripts/oom_solr.sh b/solr/docker/scripts/oom_solr.sh
similarity index 100%
rename from solr/docker/include/scripts/oom_solr.sh
rename to solr/docker/scripts/oom_solr.sh
diff --git a/solr/docker/include/scripts/precreate-core b/solr/docker/scripts/precreate-core
similarity index 100%
rename from solr/docker/include/scripts/precreate-core
rename to solr/docker/scripts/precreate-core
diff --git a/solr/docker/include/scripts/run-initdb b/solr/docker/scripts/run-initdb
similarity index 100%
rename from solr/docker/include/scripts/run-initdb
rename to solr/docker/scripts/run-initdb
diff --git a/solr/docker/include/scripts/solr-create b/solr/docker/scripts/solr-create
similarity index 100%
rename from solr/docker/include/scripts/solr-create
rename to solr/docker/scripts/solr-create
diff --git a/solr/docker/include/scripts/solr-demo b/solr/docker/scripts/solr-demo
similarity index 100%
rename from solr/docker/include/scripts/solr-demo
rename to solr/docker/scripts/solr-demo
diff --git a/solr/docker/include/scripts/solr-fg b/solr/docker/scripts/solr-fg
similarity index 100%
rename from solr/docker/include/scripts/solr-fg
rename to solr/docker/scripts/solr-fg
diff --git a/solr/docker/include/scripts/solr-foreground b/solr/docker/scripts/solr-foreground
similarity index 100%
rename from solr/docker/include/scripts/solr-foreground
rename to solr/docker/scripts/solr-foreground
diff --git a/solr/docker/include/scripts/solr-precreate b/solr/docker/scripts/solr-precreate
similarity index 100%
rename from solr/docker/include/scripts/solr-precreate
rename to solr/docker/scripts/solr-precreate
diff --git a/solr/docker/include/scripts/start-local-solr b/solr/docker/scripts/start-local-solr
similarity index 100%
rename from solr/docker/include/scripts/start-local-solr
rename to solr/docker/scripts/start-local-solr
diff --git a/solr/docker/include/scripts/stop-local-solr b/solr/docker/scripts/stop-local-solr
similarity index 100%
rename from solr/docker/include/scripts/stop-local-solr
rename to solr/docker/scripts/stop-local-solr
diff --git a/solr/docker/include/scripts/wait-for-solr.sh b/solr/docker/scripts/wait-for-solr.sh
similarity index 100%
rename from solr/docker/include/scripts/wait-for-solr.sh
rename to solr/docker/scripts/wait-for-solr.sh
diff --git a/solr/docker/include/scripts/wait-for-zookeeper.sh b/solr/docker/scripts/wait-for-zookeeper.sh
similarity index 100%
rename from solr/docker/include/scripts/wait-for-zookeeper.sh
rename to solr/docker/scripts/wait-for-zookeeper.sh
diff --git a/solr/docker/tests/cases/gosu/test.sh b/solr/docker/tests/cases/gosu/test.sh
index ad9444e..29e411f 100755
--- a/solr/docker/tests/cases/gosu/test.sh
+++ b/solr/docker/tests/cases/gosu/test.sh
@@ -59,7 +59,7 @@ fi
 container_cleanup "$container_name"
 
 # chown it back
-docker run --rm --user 0:0 -d -e VERBOSE=yes \
+docker run --rm --user 0:0 -e VERBOSE=yes \
   -v "$myvarsolr:/myvarsolr" "$tag" \
   bash -c "chown -R $(id -u):$(id -g) /myvarsolr; ls -ld /myvarsolr"