【问题标题】:Jenkins - Multibranch Pipeline unexplained failureJenkins - 多分支管道无法解释的故障
【发布时间】:2020-05-23 14:32:01
【问题描述】:

在我的管道中,我使用 Pipeline Utility Step 插件的 readJSON 和 writeJSON 方法在管道阶段读取/写入文件。 对于普通管道,一切正常。但是,当我创建“多分支管道”时,同一管道会失败。当后续阶段尝试使用 readJSON 读取应该由前一阶段生成的文件时,会发生故障。奇怪的部分是:在一个阶段内,生成的文件可供命令使用(命令 aws ecs register-task-definition 成功)BUT 不存在于节点上的工作区 /var/jenkins_home/workspace/TestPipeline然后。

为了关注失败,我只粘贴管道的相关阶段。

stage('RegisterTaskDefinition') {
    agent any
    steps {
        sh 'printenv'
        script {            
            def templateFile = env.TEMPLATE_BASE_PATH +'/' + TASK_DEF_TEMPLATE
            def taskDefinitionTemplate = readJSON(file: templateFile)

            taskDefinitionTemplate.taskRoleArn = env.TASK_ROLE_ARN
            taskDefinitionTemplate.executionRoleArn = env.EXECUTION_ROLE_ARN
            taskDefinitionTemplate.containerDefinitions[0].image = "NewImage"
            taskDefinitionTemplate.containerDefinitions[0].portMappings[0].containerPort = env.APP_PORT.toInteger()

            taskDefFile = env.TEMPLATE_BASE_PATH + '/' + env.TASK_DEFINITION_FILE
            writeJSON(file: taskDefFile, json: taskDefinitionTemplate)

            def registerTaskDefinitionOutput = sh (
            script: "aws ecs register-task-definition --cli-input-json file://${taskDefFile}",
            returnStdout: true
            ).trim()
            echo "Register Task Def result: ${registerTaskDefinitionOutput}"

            def registerTaskDefOutputFile = env.TEMPLATE_BASE_PATH + '/registerTaskDefOutput.json'
            echo "********************************"
            sh 'pwd'
            writeJSON(file: registerTaskDefOutputFile, json: registerTaskDefinitionOutput, pretty: 2)
            echo "********************************${registerTaskDefOutputFile}"
        }
    }
}
stage('CreateTaskSet') {
    agent any
    steps{
        script{
            def registerTaskDefOutputFile = env.TEMPLATE_BASE_PATH + '/' + env.REGISTER_TASK_DEF_OUTPUT
            def taskSetTemplateFile = env.TEMPLATE_BASE_PATH + '/' + env.TASK_SET_TEMPLATE_FILE
            def taskSetFile = env.TEMPLATE_BASE_PATH + '/' + env.TASK_SET_FILE

            def registerTaskDefinitionOutput = readJSON(file: registerTaskDefOutputFile)
            def taskSetTemplateJson = readJSON(file: taskSetTemplateFile)

            taskSetTemplateJson.taskDefinition = registerTaskDefinitionOutput.taskDefinition.taskDefinitionArn
            taskSetTemplateJson.loadBalancers[0].containerPort = env.APP_PORT.toInteger()
            taskSetTemplateJson.loadBalancers[0].targetGroupArn = targetGroupArn

            writeJSON(file: taskSetFile, json: taskSetTemplateJson, pretty: 2)
        }
    }
}

澄清一下,RegisterTaskDefinition 阶段成功,CreateTaskSet 阶段失败。

产生的异常是:

java.io.FileNotFoundException: /var/jenkins_home/workspace/TestPipeline/infrastructure/registerTaskDefOutput.json does not exist.
    at org.jenkinsci.plugins.pipeline.utility.steps.json.ReadJSONStepExecution.doRun(ReadJSONStepExecution.java:82)
    at org.jenkinsci.plugins.pipeline.utility.steps.AbstractFileOrTextStepExecution.run(AbstractFileOrTextStepExecution.java:32)
    at org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

我有以下问题:

  1. 什么解释了两种管道类型的行为差异?
  2. 对于普通的管道,我可以在节点上的/var/jenkins_home/workspace/TestPipeline下看到管道产生的文件。对于“多分支管道”,情况并非如此。 Jenkins 将哪个目录用于“多分支管道”?
  3. 哪些日志可以帮助我诊断问题?

我找不到任何文档来解释这两种管道类型的行为差异。如有任何建议,我将不胜感激。

【问题讨论】:

    标签: jenkins jenkins-pipeline jenkins-plugins jenkins-groovy multibranch-pipeline


    【解决方案1】:

    来自您的代码:

    stage('RegisterTaskDefinition') {
        agent any
    

    stage('CreateTaskSet') {
        agent any
    

    这两个阶段完全有可能在不同的代理上运行,因为您已告诉 Jenkins,您希望随机代理运行第一阶段随机代理运行第二阶段。这些代理可能以前是相同的;但是没有要求它们必须相同。

    为防止这种情况,请尽早分配节点并且不要更改它:

    pipeline {
       agent any
       stage('1') { ... }
       stage('2') { ... }
    }
    

    这保证了两个阶段将在同一个代理上运行,因此第一个阶段写入${env.WORKSPACE} 的结果将可供第二个阶段使用。

    【讨论】:

    • 我明白你的意思,这是完全正确的。但是,在这种情况下,我在 Docker 中运行 Jenkins,并且只有一个代理。我会试试你的技术并更新我的发现。谢谢。
    • 在两个阶段开始时尝试echo env.WORKSPACE,以确保它们相同。
    • 你是对的。删除agent any 指令后,管道工作。当agent any 出现在舞台上时,它似乎正在检查两个阶段的回购的新副本。 但是这仅发生在“多分支管道”中。这似乎确实表明了两条管道的行为差异。这是预期的吗?
    • 代理的分配也意味着工作空间的分配。我可以猜测,在多分支中,它可能会为每个分支分配一次,以适应两个不同分支在同一节点上同时运行的情况。在单个分支中不会发生这种情况。
    • 如果我的回答对你有用,请不要忘记点赞并标记为已接受,以便其他人使用。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多