如何 运行 在 jenkins 上并行动态阶段,每个阶段都有一个单独的 kubernetes 代理

How to run dynamic stages in paralell on jenkins with a separate kubernetes agent for each stage

我尝试结合我在语法上发现的东西,但这是我能得到的最接近的东西。它创建了多个阶段,但说它们没有步骤。

如果我将代理语法向下移动到定义“测试”阶段的位置,我可以在同一个代理上执行 运行 一系列并行步骤,但我想单独启动 pods 每一个这样我就可以有效地使用 kubernetes 集群并并行工作。

附上Jenkinsfile的例子供参考

def parallelStagesMap

def generateStage(job) {
    return {
        stage ("$job.key") {
            agent {
                kubernetes {
                    cloud 'kubernetes'
                    yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: name
    image: image
    command:
    - sleep
    args:
    - infinity
"""
                }
            }
            steps {
                sh """
                    do some important stuff
                """
            }
        }
    }
}

pipeline {
    agent none
    stages {
        stage('Create List of Stages to run in Parallel') {
            steps {
                script {
                    def map = [
                        "name" : "aparam",
                        "name2" : "aparam2"
                    ]
                    parallelStagesMap = map.collectEntries {
                        ["${it.key}" : generateStage(it)]
                    }
                }
            }
        }
        stage('Test') {
            steps {
                script {
                    parallel parallelStagesMap 
                }
            }
        }
        stage('Release') {
            agent etc
            steps {
                etc
            }
        }
    }
}

中所述:

Dynamic parallel stages could be created only by using Scripted Pipelines. The API built-it Declarative Pipeline is not available (like agent).

因此,您不能 运行 在不同代理上并行执行动态阶段。

为了实现你想要做的事情,一个解决方案是在一个新的 kube pod 上触发另一个 运行 管道,并在下一步之前等待它完成。

这里是 Jenkinsfiles 以供更多理解:

  • 主要工作 Jenkinsfile:
def parallelJobsMap

def triggerJob(item) {
     return {
        build job: 'myChildJob', parameters: [string(name: 'MY_PARAM', value: "${item.value}")], wait: true
     }
}

pipeline {
    agent none
    stages {
        stage('Create List of Stages to run in Parallel') {
            steps {
               script {
                    def map = [
                        "name" : "aparam",
                        "name2" : "aparam2"
                     ]
                     parallelJobsMap = map.collectEntries {
                         ["${it.key}" : triggerJob(it)]
                     }
                }
            }
        }
        stage('Test') {
            steps {
                script {
                    parallel parallelJobsMap
                }
            }
        }
        stage('Release') {
            agent any
            steps {
                 echo "Release stuff"
            }
        }
    }
}
  • 子作业 Jenkinsfile:
pipeline {
    agent none
    parameters {
      string(
        name: 'MY_PARAM',
        description: 'My beautiful parameter',
        defaultValue: 'A default value',
        trim: true
      )
    }
    stages {
        stage ("Job") {
            agent {
                kubernetes {
                    cloud 'kubernetes'
                    yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: name
    image: image
    command:
    - sleep
    args:
    - infinity
"""
                }
            }
            steps {
                echo "Do some important stuff with the parameter " + params.MY_PARAM
            }
        }
    }
}

为了 运行 并行动态创建的作业,您将必须使用脚本化管道语法。
脚本管道中声明性 kubernetes 代理的等效语法是 podTemplatenode(请参阅完整的 Doucumentation):

podTemplate(yaml: '''
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: maven
        image: maven:3.8.1-jdk-8
        command:
        - sleep
        args:
        - 99d
''') {
  node(POD_LABEL) {
     ...
    }
}

注意 podTemplate 除了 yaml 之外还可以接收 cloud 参数,但它默认为 kubernetes 所以不需要传递它。

因此,在您的情况下,您可以使用此语法 运行 在不同代理上并行执行作业:

// Assuming yaml is same for all nodes - if not it can be passed as parameter
podYaml= """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: name
    image: image
    command:
    - sleep
    args:
    - infinity
"""

pipeline {
    agent none
    stages {
        stage('Create List of Stages to run in Parallel') {
            steps {
                script {
                    def map = ["name" : "aparam",
                              "name2" : "aparam2"]
                    parallel map.collectEntries {
                        ["${it.key}" : generateStage(it)]
                    }
                }
            }
        }
    }
}

def generateStage(job) {
    return {
        stage(job.key) {
            podTemplate(yaml:podYaml)  {
                node(POD_LABEL) {
                    // Each execution runs on its own node (pod)
                    sh "do some important stuff with ${job.value}"
                }
            }
        }
    }
}