使用Docker Pipeline插件时,如何正确地停止和移除Jenkins中的Docker容器?

11

我有一个 Jenkins 流水线,它构建并运行 Docker 机器(不是作为代理),而是使用脚本块以及 Docker Pipeline 插件方法 docker.build()Image.run()。这个流程很好用,但如果构建失败,Docker 容器就会保持运行状态!我目前在 post { always{} } 块中使用 Container.stop(),但似乎不起作用。我不想通过 ssh 连接到我的 Jenkins 服务器来删除每次构建后的容器,因为它具有特定且必要的名称。 无论构建是否失败,我该如何停止并删除容器?

我的流水线:

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')
        }
    }
}

我已经找到了答案。你必须在pipeline之外声明变量(def receiver_container),然后就可以在管道的任何地方调用它并被识别。 - medley56
你能否将你的解决方案作为答案提供给自己的问题? - Giel Berkers
2个回答

6

这里有一个可行的解决方案。你只需要在主管道之外定义一个容器变量,然后就可以在管道中的任何地方使用它来启动或停止容器。特别是,在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')
        }
    }
}

这个代码是可行的并且被验证过了,但我认为@PlinioSilveira的答案更简洁。 - medley56

4

此外,Image.inside[(args)] {…} 允许完成整个命令块,然后在完成后删除容器。 - dimwittedanimal
1
但它是否也会在之后删除容器? - Datz
1
当使用 inside{} 时,我得到了日志 $ docker rm -f 8f10dc0b3e,因此我相信它确实会在之后删除容器。 - cowlinator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接