詹金斯分阶段与多个代理人

Jenkins stages with multiple agents

如果我想为特定阶段定义代理,我遇到了管道问题。

def call(Map pipelineParams) {
    pipeline {

        environment {
            // Environment variables for Docker
            DOCKERCREDS = credentials('odyssey-artifactory-token')
            COMPONENT = 'listener-publisher-service'
            REGISTRY_PATH = 'com.csg.ops.it.prf'
            REGISTRY = 'docker-dev.odyssey.rowini.net'
        }

        options {
            disableConcurrentBuilds()
            timeout(time: 1, unit: 'HOURS')
        }

        agent none

        stages {
            stage('Docker') {
                agent {
                    label 'docker'
                }
                steps {
                    sh '''
                                docker build -t $REGISTRY/$REGISTRY_PATH/$COMPONENT:$POM_VERSION . --force-rm=true
                                docker login -u $DOCKERCREDS_USR -p $DOCKERCREDS_PSW $REGISTRY
                                docker push $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker rmi $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker logout $REGISTRY
                    '''
                }
            }
        }
    }
}

我收到以下错误:

11:03:09  org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.FilePath is missing
11:03:09  Perhaps you forgot to surround the code with a step that provides this, such as: node
11:03:09    at org.jenkinsci.plugins.workflow.steps.StepDescriptor.checkContextAvailability(StepDescriptor.java:266)
11:03:09    at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:296)
11:03:09    at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:193)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
11:03:09    at sun.reflect.GeneratedMethodAccessor294.invoke(Unknown Source)
11:03:09    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11:03:09    at java.lang.reflect.Method.invoke(Method.java:498)
11:03:09    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
11:03:09    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
11:03:09    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213)
11:03:09    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
11:03:09    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42)
11:03:09    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
11:03:09    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
11:03:09    at org.kohsuke.groovy.sandbox.impl.Checker.call(Checker.java:163)
11:03:09    at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23)
11:03:09    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:158)
11:03:09    at org.kohsuke.groovy.sandbox.impl.Checker.call(Checker.java:161)
11:03:09    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:165)
11:03:09    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:135)
11:03:09    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:135)
11:03:09    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
11:03:09    at runJenkinsPipeline.call(runJenkinsPipeline.groovy)
11:03:09    at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:431)
11:03:09    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.callClosureForMapEntry(CpsDefaultGroovyMethods:5226)
11:03:09    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.collect(CpsDefaultGroovyMethods:3446)
11:03:09    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.collect(CpsDefaultGroovyMethods:3463)
11:03:09    at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:429)
11:03:09    at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.call(ModelInterpreter.groovy:78)
11:03:09    at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withCredentialsBlock(ModelInterpreter.groovy:476)
11:03:09    at ___cps.transform___(Native Method)
11:03:09    at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:86)
11:03:09    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113)
11:03:09    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:78)
11:03:09    at sun.reflect.GeneratedMethodAccessor288.invoke(Unknown Source)
11:03:09    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11:03:09    at java.lang.reflect.Method.invoke(Method.java:498)
11:03:09    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
11:03:09    at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
11:03:09    at com.cloudbees.groovy.cps.Next.step(Next.java:83)
11:03:09    at com.cloudbees.groovy.cps.Continuable.call(Continuable.java:174)
11:03:09    at com.cloudbees.groovy.cps.Continuable.call(Continuable.java:163)
11:03:09    at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
11:03:09    at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
11:03:09    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
11:03:09    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access[=11=]1(SandboxContinuable.java:18)
11:03:09    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access0(CpsThreadGroup.java:96)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.call(CpsThreadGroup.java:312)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.call(CpsThreadGroup.java:276)
11:03:09    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService.call(CpsVmExecutorService.java:67)
11:03:09    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11:03:09    at hudson.remoting.SingleLaneExecutorService.run(SingleLaneExecutorService.java:139)
11:03:09    at jenkins.util.ContextResettingExecutorService.run(ContextResettingExecutorService.java:28)
11:03:09    at jenkins.security.ImpersonatingExecutorService.run(ImpersonatingExecutorService.java:68)
11:03:09    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
11:03:09    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11:03:09    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
11:03:09    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
11:03:09    at java.lang.Thread.run(Thread.java:748)
11:03:09  Finished: FAILURE

但是如果我在阶段之外定义代理,我不会收到任何错误。

def call(Map pipelineParams) {
    pipeline {

        environment {
            // Environment variables for Docker
            DOCKERCREDS = credentials('odyssey-artifactory-token')
            COMPONENT = 'listener-publisher-service'
            REGISTRY_PATH = 'com.csg.ops.it.prf'
            REGISTRY = 'docker-dev.odyssey.rowini.net'
        }

        options {
            disableConcurrentBuilds()
            timeout(time: 1, unit: 'HOURS')
        }

        agent {
            label 'docker'
        }

        stages {
            stage('Docker') {
                steps {
                    sh '''
                                docker build -t $REGISTRY/$REGISTRY_PATH/$COMPONENT:$POM_VERSION . --force-rm=true
                                docker login -u $DOCKERCREDS_USR -p $DOCKERCREDS_PSW $REGISTRY
                                docker push $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker rmi $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker logout $REGISTRY
                    '''
                }
            }
        }
    }
}

我已经查看了有关 Jenkins 管道语法的文档,但我没有发现我的代码有任何问题。你知道我做错了什么吗?

您看到此错误是因为 environment 块内使用的 credentials 辅助方法需要给定执行上下文中的 node 上下文。您可以通过暂时注释掉这部分代码来看到这一点,并且您的初始管道不会因此而失败。

您可以通过在 docker 节点上运行的 stage 中定义 environment 块来解决此问题:

pipeline {
    environment {
        COMPONENT = 'listener-publisher-service'
        REGISTRY_PATH = 'com.csg.ops.it.prf'
        REGISTRY = 'docker-dev.odyssey.rowini.net'
    }

    options {
        disableConcurrentBuilds()
        timeout(time: 1, unit: 'HOURS')
    }

    agent none

    stages {
        stage('Docker') {
            agent {
                label 'docker'
            }
            environment {
                // Environment variables for Docker
                DOCKERCREDS = credentials('odyssey-artifactory-token')
            }
            steps {
                sh '''
                                docker build -t $REGISTRY/$REGISTRY_PATH/$COMPONENT:$POM_VERSION . --force-rm=true
                                docker login -u $DOCKERCREDS_USR -p $DOCKERCREDS_PSW $REGISTRY
                                docker push $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker rmi $REGISTRY/$REGISTRY_PATH/$COMPONENT:$VERSION
                                docker logout $REGISTRY
                    '''
            }
        }
    }
}