Building a Spring Boot application in Docker and Jenkins (part 2 of microservice devops series)

Building a Spring Boot application in Docker and Jenkins

Last Updated on November 7, 2022

Welcome to the second of this three part series where you’ll learn how to take a Spring Boot microservice from inception to deployment, using all the latest continuous integration best practices.

In this article we’ll update the Spring Boot service we built in Part 1 and get it running in a Docker container. Then we’ll setup our Jenkins instance to work with Docker, and create a pipeline to build the image and push it to Docker Hub.

This series of articles includes:

Did you read Part 1 already? If not, check it out as we’ll be building on top of the example from that article.

UPDATED in June 2021 to use the latest versions of Gradle and Jenkins.

1. Running a Spring Boot application in Docker

In the previous article we created this Spring Boot API application to model a theme park, including getting and creating rides. 🎢

Let’s take things forward and get the application running in Docker. Some reasons we might want to do this include:

  • more easily package and deploy the code (e.g. with a Docker image Java comes pre-installed)
  • use modern container orchestration services like Kubernetes or AWS ECS, which help manage applications at scale
  • make development simpler, by allowing us to more easily start up multiple associated services or microservices


A Docker image is created from a Dockerfile. It’s just a series of instructions describing how to create an image. At a high level, let’s think about what we’ll need in the image to run our Spring Boot application:

  1. have Java installed (we’re using Java 11 right now)
  2. copy the Spring Boot jar file into the image
  3. execute the Spring Boot jar file with the java command

Let’s go ahead then and create a file Dockerfile (no extension required) in the root of the Spring Boot project:

FROM openjdk:11
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
  • the FROM instruction tells Docker that we’re going to extend an existing base image, in this case an image for OpenJDK 11
  • the ARG instruction defines a variable that can be passed in at build time, in this case to provide the name of the Spring Boot jar file
  • the COPY instruction allows us to copy a file into the image, in this case the Spring Boot jar file
  • the ENTRYPOINT instruction describes what should be run when the container starts up, in this case we want to execute the jar file with the java command

Building a Docker image in Gradle

Let’s extend the build.gradle from part 1 so that we can build and run our Docker image by executing a Gradle task. A useful plugin I often use to do this is the Palantir Gradle Docker plugin, which exposes useful tasks like docker to build the image and dockerRun to run it.

It consists of several plugins, which you can pick and choose depending on what functionality you need. Let’s apply the following two Gradle plugins in our build.gradle, so we can build images and run containers.

plugins {
    id 'com.palantir.docker' version '0.26.0'
    id 'com.palantir.docker-run' version '0.26.0'
Building the image

As you probably know, some Gradle plugins require additional configuration to set them up. We’ll configure the com.palantir.docker plugin with this configuration block:

String imageName = "tkgregory/spring-boot-api-example:$version"

docker {
    name imageName
    files "build/libs/${bootJar.archiveFileName.get()}"
    buildArgs([JAR_FILE: bootJar.archiveFileName.get()])
  • we define an imageName variable as we’ll need to reference it in multiple places (the tkgregory prefix you can change later on when we cover pushing the image to your own Docker Hub account)
  • we configure the Docker plugin name property to create an image with the specified name
  • the files property exposes the specified file to be available for COPY instructions in the Dockerfile. We’re referencing the archiveFileName from the Spring Boot Gradle plugin to get the correct jar file name.
  • we’re passing the JAR_FILE build argument to the Dockerfile, so it can execute the COPY instruction

Run ./gradlew assemble docker and the image will be built:

Info: the first time you execute the docker Gradle task it may take some time as Docker needs to download the large openjdk base image.

We can verify that our image has been built by running docker images:

Running the image

Next up, let’s configure the com.palantir.docker-run plugin:

dockerRun {
    image imageName
    ports '8080:8080'
    clean true
  • the name of our container can be the same as our project e.g. spring-boot-api-example
  • the image refers to the image which we will have built from our previous configuration. We’re reusing the imageName variable.
  • the ports we configure are 8080 on the host and 8080 on the container, which by default is where our Spring Boot application is listening
  • clean true means that when we stop our container it will be automatically deleted, saving us a bit of time

Now let’s run ./gradlew assemble docker dockerRun to run a container from our image:

We can run docker ps to validate that the container is running:

Awesome! Let’s hit the application’s http://localhost:8080/actuator/health endpoint just to make sure:

If you want to stop the container, you can just run ./gradlew dockerStop.

GitHub repository
If you want to jump straight to the good stuff, the code above is available for you in the spring-boot-api-example repository.

2. Pushing to Docker hub

In a real-world scenario we’re going to need to push our Docker image to a remote repository in order to then pull it onto a server or cloud service to run it. Our setup, from the point of view of our continuous integration service (i.e. Jenkins) might look like this:

Docker registries

In Docker lingo, a repository is where you can store one or more versions of a specific Docker image. A registry, on the other hand, is a remote service that stores a collection of repositories.

Docker Hub is a Docker registry providing free storage of public and private images (you only get to store 1 private image with a free account).

If you’re using AWS, then you might want to consider AWS ECR (Elastic Container Registry) instead, as you’ll be able to keep everything within your private AWS infrastructure.

Docker login and Docker push

To use Docker Hub, go ahead and setup an account.

Before you can push images you’ll need to login on the command line with docker login --username=<username>. Enter your password when prompted.

Docker login command

Edit the build.gradle of the Spring Boot API application and replace tkgregory in the imageName variable with your own Docker Hub username i.e. String imageName = "<your-docker-hub-username>/spring-boot-api-example:$version"

To push the image to Docker Hub just run ./gradlew docker dockerPush and wait for it to upload:

Now over in Docker Hub you’ll be able to see your image in your own account repository at<your-docker-hub-username>/spring-boot-api-example:

A word of warning
Note that by default when you push an image to Docker Hub it will be public for the world to see. See this guide to learn about setting up private repositories.

OK, so that’s our application all setup. Time to jump through a few hoops to get things working with Docker in Jenkins.

3. Configuring Jenkins to be able to run Docker in Docker

In part 1 we made use of the jenkins-demo GitHub repository (the theme-park-job branch) to run an instance of Jenkins locally using our own custom Dockerfile. We’re going to make some modifications to:

  • install Docker in the Jenkins Docker image
  • hook up the Docker command in the Jenkins image to our Docker installation on the host. This will allow us to run Docker in Docker, or in other words build Docker images from Jenkins.
Installing Docker in Jenkins (Docker in Docker)

Update the Dockerfile for Jenkins to the one below, which now includes installing Docker from

FROM jenkins/jenkins:2.346.2-jdk11

USER root
RUN curl -sSL | sh
RUN usermod -a -G docker jenkins
USER jenkins

COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt

COPY seedJob.xml /usr/share/jenkins/ref/jobs/seed-job/config.xml

ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
Making /var/run/docker.sock available to Jenkins

In order that when we run Docker commands in Jenkins they communicate with the Docker process running on the host, we have to use a file /var/run/docker.sock. This file must be mounted as a volume inside the Jenkins container.

Update the dockerRun configuration in build.gradle to as below:

Process process
if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows()) {
    process = "docker run --rm -v /var/run/docker.sock:/var/run/docker.sock alpine stat -c %g /var/run/docker.sock".execute()
} else if (DefaultNativePlatform.getCurrentOperatingSystem().isLinux()) {
    process = "stat -c %g /var/run/docker.sock".execute()
} else {
    throw new GradleException("Unsupported operating system. No way to find group of /var/run/docker.sock.")

def out = new ByteArrayOutputStream()
process.waitForProcessOutput(out, System.err)
String dockerSockGroupId = out.toString().trim()

String extraPrefix = DefaultNativePlatform.getCurrentOperatingSystem().isWindows() ? '/' : ''
dockerRun {
    name "${}"
    image "${}:${project.version}"
    ports '8080:8080'
    clean true
    daemonize false
    arguments '-v', "$extraPrefix/var/run/docker.sock:/var/run/docker.sock", '--group-add', dockerSockGroupId

You’ll also have to include this import at the top of the file:

import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
  • in the first 9 lines we’re determining if we’re on a Linux or Windows machine. Depending on the outcome, we run a specific command to find out which group owns /var/run/docker.sock and then store that value as dockerSockGroupId.
  • dockerRun has been updated to pass 2 new arguments
    • the -v argument mounts /var/run/docker.sock inside the container so that Jenkins can use the Docker process of the host. Note that in Windows an additional slash prefix is required.
    • the --group-add argument makes sure the container is also run with the group that owns /var/run/docker.sock, so that Jenkins has the required access

Docker host in Windows
If you’re using Docker for Windows, like me, the host from the container’s point of view is not Windows but a Linux VM running inside Windows. For a full explanation of Docker in Docker see my article Running Docker in Docker on Windows (Linux containers).

At this point you can run Jenkins using ./gradlew docker dockerRun, but there are still a few tweaks to add in the following section. Don’t forget to first stop the Spring Boot API application as it’s also running on port 8080.

To double check that you can run Docker in Docker, run docker exec jenkins-demo docker ps. If you see output like below, you’re good to continue.

4. Building the Docker Spring Boot API application in Jenkins

In part 1 we had the application building in this Jenkins pipeline, consisting of checkout, build, and test stages:

Let’s extend this pipeline to include stages to build the Docker image and push it to Docker Hub.

Updating the Jenkinsfile

Remember that the pipeline above is stored in a file called Jenkinsfile in our Spring Boot API application repository? Add the additional Build Docker image and Push Docker image stages shown below:

pipeline {
    agent any

    triggers {
        pollSCM '* * * * *'
    stages {
        stage('Build') {
            steps {
                sh './gradlew assemble'
        stage('Test') {
            steps {
                sh './gradlew test'
        stage('Build Docker image') {
            steps {
                sh './gradlew docker'
        stage('Push Docker image') {
            environment {
                DOCKER_HUB_LOGIN = credentials('docker-hub')
            steps {
                sh 'docker login --username=$DOCKER_HUB_LOGIN_USR --password=$DOCKER_HUB_LOGIN_PSW'
                sh './gradlew dockerPush'
  • for the Build Docker image stage we’re using the Gradle Docker plugin to build the image
  • for the Push Docker image stage we’re grabbing the docker-hub credentials from Jenkins and storing it as an environment variable. We’ll cover how to add the credentials shortly. We then use this variable to run a docker login command, and once we’re logged in we can push the image to Docker Hub using the dockerPush Gradle command.

Credentials in pipelines
When you store a username with password type credential in an environment variable in a Jenkins pipeline, the username and password are automatically separated out into two additional variables. Read more about this here in How To Secure Your Gradle Credentials In Jenkins.

If you’re following along with this example by building up your own project, make the change above and push it. Alternatively, the change is also available in Jenkinsfile-docker, a custom Jenkinsfile I’ve pushed just for you (I’ll show you how to use it in the next section).

Adding the new Docker job definition

Lastly, in createJobs.groovy of the jenkins-demo project add the following job definition:

pipelineJob('theme-park-job-docker') {
    definition {
        cpsScm {
            scm {
                git {
                    remote {
                        url ''
                    branch 'master'

This will create a job based on the Jenkinsfile-docker file discussed earlier. If you want this to refer to your own repository, change the url and scriptPath appropriately. Also, don’t forget to change the location in seedJob.xml to point to your own appropriate git URL and branch to fetch the createJobs.groovy file.

Now all we have to do is run ./gradlew docker dockerRun to start up Jenkins:

Adding credentials to Jenkins

Let’s add our Docker Hub credentials into Jenkins, by navigating through the somewhat long-winded following series of pages…

In the left hand navigation menu select Manage Jenkins then Manage Credentials:

Manage Jenkins

Select the Jenkins credential store:

Select Global credentials:

Click Add Credentials:

Finally we’re here! Now add a Username with password credential, entering your Docker Hub username, password, and an id of docker-hub. Click OK to save your credentials in Jenkins.

Running the new Docker pipeline

Now for the final act! 🎭 Build the seed-job, then build the newly created theme-park-job-docker:

Awesome! We now have a Jenkins job that builds, tests, and pushes an image for our Spring Boot API application.

5. Final thoughts

Having a pipeline that will automatically take code as soon as it’s pushed and put it in a Docker image in Docker Hub is a very good place to be.

In the final article in this series, we’ll be putting the cherry on top by taking our Docker image and deploying it into AWS.

Get the Build Boss newsletter

Found this website helpful? Subscribe for updates.

✅ All of my latest articles each week
✅ Access to video tutorials
✅ Exclusive tips and offers not found on my website

Please wait...

Thank you, your sign up request was successful! I'll be in touch soon. Tom.

6. Resources


  • Check out the sample Spring Boot application for the theme park API. It now contains the Jenkinsfile-docker file which includes Docker build and push stages in the pipeline.
  • Here you can find the code for the jenkins-demo project, for bringing up an instance of Jenkins. The theme-park-job-docker branch contains the updated version of createJobs.groovy as well as the modifications needed to run Docker in Docker.

Discover more details about how to secure credentials in Jenkins in this article.

If you prefer to learn in video format then check out the accompanying video below. It’s part of the Tom Gregory Tech YouTube channel.

Want to learn more about Jenkins?
Check out the full selection of Jenkins tutorials.

Building a Spring Boot application in Docker and Jenkins (part 2 of microservice devops series)

39 thoughts on “Building a Spring Boot application in Docker and Jenkins (part 2 of microservice devops series)

  1. I know it is now late to answer this question, but let me try this…

    give the following permissions :-
    sudo chmod 666 /var/run/docker.sock

  2. I was following your tutorial in this page. The pipe line theme-park-job-docker failed at Build Docker Image step.
    My Host OS is mac.
    I have added the following line in jenkins-demo/build.gradle.
    else if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX()) {
    process = “stat -f %z /var/run/docker.sock”.execute()
    My Build error is as follows:
    3 actionable tasks: 2 executed, 1 up-to-date
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] stage
    [Pipeline] { (Build Docker image)
    [Pipeline] sh
    + ./gradlew docker
    > Task :dockerClean UP-TO-DATE
    > Task :dockerPrepare

    > Task :docker FAILED
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post “http://%2Fvar%2Frun%2Fdocker.sock/v1.24/build?buildargs=%7B%22JAR_FILE%22%3A%22spring-boot-api-example-0.1.0-SNAPSHOT.jar%22%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&shmsize=0&t=tkgregory%2Fspring-boot-api-example%3A0.1.0-SNAPSHOT&target=&ulimits=null&version=1”: dial unix /var/run/docker.sock: connect: permission denied

    FAILURE: Build failed with an exception.

    1. Hi Joy. Sorry to hear you’re having a problem. I don’t have Mac so can’t try it myself, but some other readers have pasted solutions.

      Here’s one from perminus:

      Well for guys working on mac, I just changed “process = “stat -c %g /var/run/docker.sock”.execute()” to “process = “stat -f %g /var/run/docker.sock”.execute()” and its working. For if else statement, this statement checks for macOs “DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX()”

      Let me know how it goes.

  3. Hello Gregory, Very well laid out and nice presented 3 part series. However i have couple questions

    1. Is there a particular reason to use palantir docker plugins. Aren’t there similar plugins which does the same job?

    2. If i were to use Terraform to spin up my infrastructure rather then cloudformation, what plugin would you suggest?

    your input is greatly appreciated!


    1. Hi Sreeram. Thanks for the comment.

      1) At the time I chose this plugin as the best available. I now prefer the bmuschko plugin though, mainly because it has proper task implementation enabling Gradle’s incremental build feature. This works, for example, when building Docker images. You can read my full review if you like.

      2) I haven’t tried any Terraform Gradle plugins yet. Let us know if you find something good though.


  4. sure, thanks
    got past this stage
    and now I get a fresh error trying to deploy to AWS

    * What went wrong:
    Execution failed for task ‘:awsCfnWaitStackComplete’.
    > Timeout

    1. Hi Hamisu. Log into AWS and go to the CloudFormation dashboard. You should see a stack which has some kind of error, which should help you understand what the problem is.

  5. Hey Tom been getting this error when I try to build the pipeline please can you help resolve

    Started by user unknown or anonymous
    Checking out git into /var/jenkins_home/jobs/theme-park-job-docker/workspace@script to read Jenkinsfile-docker
    The recommended git tool is: NONE
    No credentials specified
    Cloning the remote Git repository
    Cloning repository
    > git init /var/jenkins_home/jobs/theme-park-job-docker/workspace@script # timeout=10
    Fetching upstream changes from
    > git –version # timeout=10
    > git –version # ‘git version 2.20.1’
    > git fetch –tags –force –progress — +refs/heads/*:refs/remotes/origin/* # timeout=10
    > git config remote.origin.url # timeout=10
    > git config –add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
    Avoid second fetch
    > git rev-parse origin/master^{commit} # timeout=10
    Checking out Revision b35bdbdadc1722a9ea8ac9becc27f9e470e9b2a3 (origin/master)
    > git config core.sparsecheckout # timeout=10
    > git checkout -f b35bdbdadc1722a9ea8ac9becc27f9e470e9b2a3 # timeout=10
    Commit message: “rename JenkinsFile”
    First time build. Skipping changelog.
    ERROR: /var/jenkins_home/jobs/theme-park-job-docker/workspace@script/Jenkinsfile-docker not found
    Finished: FAILURE

    1. Hi Hamisu. I’m not sure what the issue is just from the error. Did you try running the provided code examples without modification? If you can get them working you might be able to understand what the issue is with your project.

  6. Hey Tom!

    Is there an easy way to save the Jenkins configuration changes into a new Docker image? Then, be able to deploy this same image into ECS?

    Thanks a lot!

  7. Hello Tom,

    I am running into an issue with the theme-park-job-docker pipeline. It wil do the SCM, Build and Test stage. It will fail the Build Docker image block. See stacktrace below.

    The command docker ps inside CLI of running docker container gives:
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json: dial unix /var/run/docker.sock: connect: permission denied

    Tried hardcoding the dockerSockGroupId = ‘root’. Tried various suggestions from the comments to change jenkins-demo Dockerfile. Do you have an idea what the problem could be?

    + ./gradlew docker –stacktrace
    > Task :dockerClean
    > Task :dockerPrepare

    > Task :docker FAILED
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.24/build?buildargs=%7B%22JAR_FILE%22%3A%22ThemeParkRidesExample-0.1.0-SNAPSHOT.jar%22%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&shmsize=0&t=stefanvantilburg%2Fspring-boot-api-example%3A0.1.0-SNAPSHOT&target=&ulimits=null&version=1: dial unix /var/run/docker.sock: connect: permission denied

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ‘:docker’.
    > Process ‘command ‘docker” finished with non-zero exit value 1

    * Try:
    Run with –info or –debug option to get more log output. Run with –scan to get full insights.

    * Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ‘:docker’.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(
    at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(

    * Get more help at

    BUILD FAILED in 1s
    3 actionable tasks: 3 executed
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] stage
    [Pipeline] { (Push Docker image)
    Stage “Push Docker image” skipped due to earlier failure(s)

    1. Hi Stefan.

      Can you run docker exec --user root jenkins-demo docker ps? This runs a Docker command inside the container, but as the root user. If this works, we at least know the volume mount is setup correctly.

      What operating system are you using? If you’re on Windows, are you using Docker in WSL2 mode?

      Seems like the --group-add flag is not adding the correct group to allow you to access the Docker socket.

      1. For the time being, as mentioned above, I have added root the dockerfile and its working, until another workaround mentioned.

        USER root
        RUN apt-get update
        RUN curl -fsSL | sh
        RUN usermod -aG docker root
        RUN newgrp root
        USER root

      2. Another workaround was to `docker exec -it -u root jenkins-demo /bin/bash`
        chmod 666 /var/run/docker.sock
        systemctl restart docker

        allowing any user to connect to the docker service

      1. Good. I know how hard to write these long tutorials. You are amazing.
        BTW I have a questions.
        Could you please tell me why the path in build.gradle in Jenkins repository begins with two successive slashes? Does this have special meanings?

        arguments ‘-v’, ‘//var/run/docker.sock:/var/run/docker.sock’, ‘–group-add’, dockerSockGroupId

      2. Hi. The double slash was once what I had to do to get volumes working in Windows. Docker for Windows has now improved, and I can confirm with the latest version using the WSL 2 based engine, the double slash is not required.

        I’ve updated the article and the sample code.

  8. Well for guys working on mac, I just changed “process = “stat -c %g /var/run/docker.sock”.execute()” to “process = “stat -f %g /var/run/docker.sock”.execute()” and its working. For if else statement, this statement checks for macOs “DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX()”

  9. Anyone else faced this issue the moment you include the gradle plugins?

    Illegal null value provided in this collection: [inspect, –format={{.State.Running}}, null]

    id ‘com.palantir.docker’ version ‘0.25.0’
    id ‘com.palantir.docker-run’ version ‘0.25.0’

    gradle -version

    Gradle 6.6.1

    Build time: 2020-08-25 16:29:12 UTC
    Revision: f2d1fb54a951d8b11d25748e4711bec8d128d7e3

    Kotlin: 1.3.72
    Groovy: 2.5.12
    Ant: Apache Ant(TM) version 1.10.8 compiled on May 10 2020
    JVM: 14.0.1 (Oracle Corporation 14.0.1+14)
    OS: Mac OS X 10.15.7 x86_64

    1. Hi Sriram. I haven’t seen this issue before. Can you try running the Gradle command with –stacktrace to see where the error happens?

      What version of Docker are you using?

    2. I got something like this on gradle 6.6.1 (different project, but also using com.palantir.docker-run). The error went away when I switched back to gradle 6.5.

      1. I got the same error and investigated it. The reason why the error occurs is.. latest Gradle require both “`docker{}“` and “`dockerRun{}“`. So adding “`dockerRun{}“` would resolve the problem. I’m not sure whether it is intended behavior or just bug.

  10. Nevermind, I found the issue. On Mac, the docker container gets locked and the only way to get around that is to restart Docker which is painful to say the least..

  11. Thanks Tom!! That was real quick and I really appreciate it. Are you suggesting to set the value as this?
    String dockerSockGroupId = “root”

    After I added the following code, I get a value of 1 assigned to dockerSockGroupId which seems like the wrong value.

    else if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX()) {
    process = “stat -f %g /var/run/docker.sock”.execute()

    Also, when I run the gradlew assemble, it comes back to the prompt in not time and I do see the jar file in the ditrribution folder. On the other hand, when I run ./gradlew docker or ./gradlew asemble docker, it just get to this state and never comes out.

    + exec /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/bin/java -Xmx64m -Xdock:name=Gradle -Xdock:icon=/Users/aastha/s2/jenkins-setup/media/gradle.icns -Dorg.gradle.appname=gradlew -classpath /Users/aastha/s2/jenkins-setup/gradle/wrapper/gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain docker

    > Configure project :
    rootProcess[pid=17328, exitValue=0]
    66% EXECUTING [10s]
    > :docker

    1. Yes, thanks Tom, this is excellent content for sure. Learning a ton.
      I am on a mac and getting the same errors as Ramen and others specifically at ./gradle docker

      BUILD SUCCESSFUL in 2m 3s
      3 actionable tasks: 3 executed
      [Pipeline] }
      [Pipeline] // stage
      [Pipeline] stage
      [Pipeline] { (Build Docker image)
      [Pipeline] sh
      + ./gradlew docker –stacktrace. ////HERE///
      > Task :dockerClean UP-TO-DATE
      > Task :dockerPrepare

      > Task :docker FAILED
      Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post

      Based on discussions, this is what my build.gradle currently looks like..

      Process process
      if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows()) {
      process = “docker run –rm -v /var/run/docker.sock:/var/run/docker.sock alpine stat -c %g /var/run/docker.sock”.execute()
      // } else if (DefaultNativePlatform.getCurrentOperatingSystem().isLinux()) {
      } else if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX()) {
      process = “stat -f %g /var/run/docker.sock”.execute()
      } else {
      throw new GradleException(“Unsupported operating system. No way to find group of /var/run/docker.sock.”)

      def out = new ByteArrayOutputStream()
      process.waitForProcessOutput(out, System.err)
      // String dockerSockGroupId = out.toString().trim()
      String dockerSockGroupId = “root”

      dockerRun {
      name “${}”
      image “${}:${project.version}”
      ports ‘8080:8080’
      clean true
      daemonize false
      arguments ‘-v’, ‘/var/run/docker.sock:/var/run/docker.sock’, ‘–group-add’, dockerSockGroupId

      NOTE: I am still getting same error with “root” hardcoded. As Tom mentioned, I am able to run the following exec command it works fine.
      docker exec –user root jenkins-demo docker ps

      Any idea on what else needs to be added to get this to work would be appreciated.

      1. Hi Jonathan. Thanks for the comment, and sorry you’ve having an issue building the Docker image.

        When you run ./gradlew docker this is just building the image. Therefore the dockerRun configuration you pasted in your comment is unrelated, since that is configuring what happens when you run ./gradlew dockerRun.

        The way this plugin builds a Docker image is by executing Docker commands directly e.g. docker build. If you run with the --info Gradle flag you’ll see more output. Given your later comment, I’m assuming you traced the problem to one of the instructions in the Dockerfile?

      2. Really appreciate the insight and quick reply into this issue. Will modify codebase with the changes you mentioned. Again, this is excellent content and appreciate your taking the time to put all this together.

  12. Thanks Tom. Brilliant work!! I am running this on a MacOs and had to make certain changes as well. What process id are we expecting to see. My code is always returning thr value as 1. Also, I am running into an issue where the “exec docker” part of the gradlew execution commands does not return to the command prompt as you demonstrated. Any idea?

    1. Hi Raman. Thanks for visiting the site.

      You just need to determine the id of the group that owns `/var/run/docker.sock`. Can you try hard coding dockerSockGroupId as root as suggested by Matthias?

      When you say “exec docker” do you mean this command isn’t working docker exec jenkins-demo docker ps? Please let me know the error as well as any other problems you’ve had.

      Thanks, Tom

  13. Hi Gregory,

    I’m afraid, there is a bug in your build.gradle that took me quite a while to pin down:
    ” if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows()) {
    process = “docker run –rm -v /var/run/docker.sock:/var/run/docker.sock alpine stat -c %g /var/run/docker.sock”.execute()
    } else {
    process = “stat -c %g /var/run/docker.sock”.execute()
    } ”

    I’m working with a Mac and get the following error:
    ” stat: illegal option — c
    usage: stat [-FlLnqrsx] [-f format] [-t timefmt] [file …]
    > Task :dockerRun FAILED
    docker: Error response from daemon: Unable to find group.
    FAILURE: Build failed with an exception. ”

    This is because for the stat command “c” is not a valid option. You want to use “f” here. But nevertheless, changing this only sets the group of /var/run/docker.sock in your host system (for me: “daemon”) but not the group of this file in the docker image (for me: “root”).
    I ended up fixing this by hard coding dockerSockGroupId = “root” for unix systems. Clearly not the best solution.
    Do you have a better way to solve this?


    1. Hi Matthias,

      Sorry about the issue you found. I’ll be honest I hadn’t tested it on a Mac as I don’t have access to one. Not a great reason, but there you go 😉

      I’ve made the support explicit to Linux for use of the stat -c %g /var/run/docker.sock command. If you try with any other OS except Windows and Linux the build will fail now.

      Obviously that’s no good for Mac users. Anyone trying out this this example would greatly appreciate a solution if you have time. You can make a PR for this file if you are able.

      If not, I can always hard code the dockerSockGroupId to root for Mac. What do you think?


  14. Hi gregory, i have a problem when i run ./gradlew docker dockerRun on jenkins-demo, that gives me the next response “> Task :docker FAILED
    The command ‘/bin/sh -c usermod -a -G docker jenkins’ returned a non-zero code: 6” and “FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ‘:docker’.
    > Process ‘command ‘docker” finished with non-zero exit value 6″ and i don’t know what to do, what’s happening here, i’m gonna be grateful with your response. salutes from colombia.

    1. Hi Santiago. I believe you’re seeing an error on the theme-park-job-docker branch of the jenkins-demo repository? RUN usermod -a -G docker jenkins is part of the Dockerfile, which is building fine for me when I run ./gradlew docker.

      A couple of ideas:

      • try running docker build .. Do you get the same error?
      • have you modified the Dockerfile in any way?
      • what OS are you building from?

      Let me know how you get on, as I’m keen to resolve your issue.

      1. Hello gregory, i resolved the issue modified the DockerFile, i think something was wrong with “RUN usermod -a -G docker jenkins” so i changed the lines 1 and 6 and then modified with…
        ” FROM jenkins/jenkins:lts
        USER root
        RUN apt-get update
        RUN curl -fsSL | sh
        RUN usermod -aG docker jenkins
        USER jenkins”

        Also thank you very much for your help, i appreciate it.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top