11

I'm trying to set up a jenkins multibranch pipeline to run all my code validation steps in a docker container, then build the docker image and push it outside of said docker container.

Currently, my Jenkinsfile looks sort of like this (slimmed down for readability):

pipeline {
    agent {
        label 'AWS'
    }
    stages {
        stage('stuff in docker') {
            agent {
                dockerfile {
                    filename 'Dockerfile.jenkins'
                    reuseNode true
                }
            }
            steps {
                stuff
            }
        }
        stage('more stuff in docker') {
            agent {
                dockerfile {
                    filename 'Dockerfile.jenkins'
                    reuseNode true
                }
            }
            steps {
                stuff
            }
        }
        stage('stuff not in docker') {
            steps {
                stuff
            }
        }
        stage('more stuff not in docker') {
            steps {
                stuff
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}

The problem here is that every stage that I use a dockerfile agent, jenkins will attempt to rebuild the docker image. The stages are all cached, but sending build context and actually processing everything still takes more time than I'd like. If I use the dockerfile as the root agent, I get to run everything inside the same docker container, but I lose the ability to do git stuff and build the docker image (at least without connecting to the external docker process sock, which seems like more hassle than should be necessary).

I'd like to know if there's some way I can use the same docker image for multiple steps, but then pull out of that docker image for some other steps.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
ChickenWing
  • 639
  • 9
  • 24
  • 1
    Have you explored [docker save](https://docs.docker.com/engine/reference/commandline/save/) and [docker load](https://docs.docker.com/engine/reference/commandline/load/)? You can use the _save_ command in one step and _load_ in another. – Technext Aug 24 '19 at 04:06
  • 1
    What about building the image outside of the pipeline, or in another pipeline, and then utilizing the docker agent instead? – Matthew Schuchard Aug 24 '19 at 11:36

2 Answers2

17

Figured it out!

pipeline {
    agent {
        label 'AWS'
    }
    stages {
        stage('do everything in docker') {
            agent {
                dockerfile {
                    filename 'Dockerfile.jenkins'
                    reuseNode true
                }
            }
            stages {
                stage('stuff in docker') {
                    steps {
                        stuff
                    }
                stage('more stuff in docker') {
                    steps {
                         stuff
                    }
                }
            }
        }
        stage('stuff not in docker') {
            steps {
                stuff
            }
        }
        stage('more stuff not in docker') {
            steps {
                stuff
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}

tl;dr you can nest stages

ChickenWing
  • 639
  • 9
  • 24
  • 1
    This solved my problem - thanks! Also, this is the official [Jenkins blog post](https://www.jenkins.io/blog/2018/07/02/whats-new-declarative-piepline-13x-sequential-stages/#running-multiple-stages-with-the-same-agent-or-environment-or-options) where this feature is explained in depth. Found the link at https://stackoverflow.com/a/76094847/1994888. – jhn Jun 09 '23 at 09:33
1

Using dockerfile as build agent will always result in a container rebuild. If you just want to run some steps inside a (pre-build) container use docker as agent. Of course, this can also be a container build locally inside the same pipeline. You can also utilize bind mounts to share data between containers.

If unsure, check out the documentation 1 and 2. Maybe it's also advisable to set the global agent to none in your case.

Joe
  • 548
  • 3
  • 7