11

I have a Jenkins pipeline that builds and runs a Docker machine, not as an agent, but using a scripting block along with the Docker Pipeline Plugin methods docker.build() and Image.run(). This works fine but if the build fails, the docker container is left running! I currently have Container.stop() in a post{ always{} } block but it doesn't seem to work. I don't want ssh into my Jenkins server to delete the container after every build and I can't just leave it because it has a specific and necessary name. How do I stop and rm the container regardless of failure of the build?

My pipeline:

pipeline {
    agent none
    stages {
        stage('Checkout') {
            agent any
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '<some credentials>', url: '<a git repo>']]])
            }
        }
        stage('Spin Up Receiver') {
            agent any
            steps {
                script { 
                    def receiver = docker.build("receiver",  "--rm centos7_receiver")
                    def receiver_container = receiver.run("-d -v ${PWD}/realtime_files/station_name/201707/f/20170710_191:/DSK1/SSN/LOG0_f/17001 --network='rsync_test' --name='test_receiver'")
                }
            }
        }
        stage('Run Tests') {
            agent { dockerfile { args '-v /etc/passwd:/etc/passwd --network="rsync_test"' } }
            steps {
                sh "python ./rsyncUnitTests.py"
            }
        }
    }
    post {
        always {
            script { 
                receiver_container.stop()
            }
        }
        failure {
            sendEmail('foo@bar.com')
        }
        changed {
            sendEmail('foo@bar.com')
        }
    }
}
medley56
  • 1,181
  • 1
  • 14
  • 29
  • I've discovered the answer. You must declare the variable (`def receiver_container`) for the docker machine _outside_ of the `pipeline`. Then you can call it from anywhere in the pipeline and it will be recognized. – medley56 Aug 03 '17 at 15:48
  • Could you provide your solution as an answer to your own question? – Giel Berkers Sep 13 '17 at 07:04

2 Answers2

6

Here is a working solution. You simply have to define a variable for the container outside the main pipeline. Then you can use it anywhere in the pipeline to start or stop the container. In particular, you can remove the container in post{ always{ } }.

def receiver_container
pipeline {
    agent any
    stages {
        stage('Checkout') {
            agent any
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '<some credentials>', url: '<a git repo>']]])
            }
        }
        stage('Spin Up Receiver') {
            agent any
            steps {
                script { 
                    def receiver = docker.build("receiver",  "--rm receiver_docker")
                    receiver_container = receiver.run("-d -u 0:0 -v /var/lib/jenkins/workspace/RsyncRealtime/jenkins_rt:/DSK1/SSN/LOG5_F/17191 --network='rsync_test' --name='test_receiver'")
                }
            }
        }
        stage('Run Unit Tests') {
            agent { 
                dockerfile { 
                    args '-u 0:0 -v /etc/passwd:/etc/passwd --network="rsync_test"'
                } 
            }
            steps {
                sh "sshpass -p 'test' ssh anonymous@test_receiver ls -l /DSK1/SSN/LOG5_F/17191"
                sh "python ./rsyncUnitTests.py"
            }
        }
    }
    post {
        always {
            script { 
                receiver_container.stop()
            }
        }
        failure {
            sendEmail('foo@bar.com')
        }
        changed {
            sendEmail('foo@bar.com')
        }
    }
}
medley56
  • 1,181
  • 1
  • 14
  • 29
4

You can use Image.withRun() instead of Image.run().

Image.withRun[(args[, command])] {…}

Like run but stops the container as soon as its body exits, so you do not need a try-finally block.

Here other useful commands: https://qa.nuxeo.org/jenkins/pipeline-syntax/globals#docker

Community
  • 1
  • 1