0

Question on docker agents in declarative pipelines

I am trying to understand the interactions between a docker agent in a declarative pipeline and how it interacts with workspaces vs. something like a docker.inside call.

I have a declarative pipeline like this:

pipeline {
   agent{ label 'worker1''}
   stages {
      stage('Source') {
         steps {
            step([$class: 'WsCleanup'])
            // Get some code from our Git repository
            git 'git@repo.git'
          }
      }
      stage('Build') {
          agent {
              dockerfile {
                   dir '/home/user/docker'
                }
         }
         // Run the gradle build
         steps {
                   sh 'gradle --debug clean build -x test'
         }

   ....

The Dockerfile constructs an image that contains a jdk and a version of Gradle.  When I execute the pipeline, it succeeds, but I'm unclear on the interaction between the non-docker nodes and the docker agent. 

The version of gradle used is from the docker image which I would expect.  But it appears the source code and build happen on a non-docker agent.  I would have thought that the source code and build would happen on the docker agent.  That would be similar to how docker.inside works (as I understand it). But I assume I can't use docker.inside in a declarative pipeline because it's a method call (at least not without a script block).

Can you explain what a docker agent is really doing here.  is it just setting up a new node/agent with an environment but everything else happens on a non-docker node/agent?   I was expecting to have to tell the agent to download the source within the container and have the build run within the container.  Or at least to have to pass in a -v argument to map the project's workspace to a volume in the container.  

Is there an advantage to running builds in the container vs. out?   If I wanted to run it in the container, how would I even do that in declarative without a script block and docker.inside? 

Thanks in advance for taking the time to reply!

 

8 comments

  • 0
    Avatar
    Brent Laster

    Ok, so I think I'm understanding better...  The docker agent provides an implicit WithDockerContainer closure that mounts the workspace RW into the container and any sh steps, such as my sh 'gradle...' step are executed against the mounted workspace in the container.   Did I get that right? 

    I'm still a little unclear about the label argument for a docker agent.   Is this so that you can spin up the docker container on a docker-enabled existing agent?

  • 0
    Avatar
    Brent Laster

    One additional question - I'd like to create an agent from a dockerfile in one stage and then use it in later stages as the docker agent.   Without the upcoming additionalBuildArgs to specify the tag when I create the image from the dockerfile, is there a good way to be able to grab the image string that was created by the dockerfile agent to pass to the docker agent call later?

  • 0
    Avatar
    Denys Digtiar

    Hi Brent,

    Yes. I believe you are getting it right. AFAIK, Docker Pipeline plugin is used under the hood. 

    Regarding label. As documentation linked bellow describes, docker agent executes steps inside docker on a Jenkins Node. Label expression that specifies which nodes to include can be defined in System Configuration or with a label argument.

    https://jenkins.io/doc/book/pipeline/syntax/#declarative-directives

  • 0
    Avatar
    Brent Laster

    Thanks Denys for the response!

  • 0
    Avatar
    Patrick Wolf

    Hi, Brent.

    I believe what you are looking for is the the 'reuseNode' command from the page Denys linked to.

    https://jenkins.io/doc/book/pipeline/syntax/#declarative-directives

    Each 'agent' directive that you use will create a new workspace on the specified agent unless you tell it to reuse the same workspace. In your case when you specify

    agent { 

      dockerfile {

        dir '/home/user/docker'

      }

    }

    This is equivalent to 

    agent { 

      dockerfile {

        label ''  //use any agent label

        dir '/home/user/docker'

      }

    }

    If you change it to use reuseNode it will stay on the same agent and use the same workspace:

    agent { 

      dockerfile {

        dir '/home/user/docker'

        reuseNode true

      }

    }

  • 0
    Avatar
    Brent Laster

    Thanks Patrick.  But just because it will use the same workspace and node doesn't mean it will the same image, does it?   Essentially, I was wanting to create an image via an agent { dockerfile = <location> } and then reuse that same image later in the pipeline.  To do that, I need to be able to set an image identifier and tag, which I don't think I can do until the additionalBuildArgs support is released.

    Then later in the pipeline, I would use the image I created earlier. To do that, I thought I needed to specify the identifier and label.  Note that I want to build the image again, since I've already created it earlier.

     

  • 1
    Avatar
    Patrick Wolf

    Hi, Brent

    Is the image the artifact you are producing with the Pipeline or is it your build environment for running the various steps? Are you going to publish the image to a registry at the end?

    Right now the `agent` directive is building the Dockerfile using a randomized tag that isn't controllable. We can look at changing that but it is easy to get around that with a direct Docker command in shell.

    I have added a quick Gist that builds an image from my Dockerfile using a tag I specify and then uses that image in later stages:

    https://gist.github.com/HRMPW/35bc965f523743a74496c2deb2075879

    By using 'reuseNode' I never leave the node (in this case 'any') and my workspace is shared across all stages. Each stage creates a new container, due to using 'docker run' but the image is the same.

    Is this what you are trying to accomplish?

  • 1
    Avatar
    Brent Laster

    Thanks Patrick for the follow up.  Appreciate the way Cloudbees is responding to all of the questions in the Community.

     The first docker image I'm creating was to setup a custom build environment to be used by other stages. 

    Specifying the image id and tag was the issue.  I realized I could do it through the shell as you pointed out, but was hoping to be able to demonstrate how to do it through the agent directives for the online training I'm doing next week.   

    In any event, it looks like once https://issues.jenkins-ci.org/browse/JENKINS-42693 is released, I should be able to use the additionalBuildArgs with the agent based on a Dockerfile to set the image id and tag.   If that works, then I think I'll be able to do what I want just through the agent declaration.

    Thanks

Please sign in to leave a comment.