如何将每个Jenkins构建实例限制为最多x个节点

时间:2016-11-07 15:20:42

标签: jenkins jenkins-plugins jenkins-pipeline

是否可以限制作业的构建实例在最多x个节点上运行?

例如,假设我有20个奴隶和一个名为“ParentJob”的父作业。 “ParentJob”配置为在任何可用的从属服务器上同时运行20个子作业,称为“ChildJob”。由于我需要启动多个ParentJobs,我想将子作业限制为每个ParentJob构建实例5个节点。

基本上,我想同时启动ParentJob#1,#2和#3,但我不希望从ParentJob#1产生的所有ChildJobs占用所有从属。 ParentJob#1的ChildJobs应使用节点1-5,ParentJob#2的ChildJobs应使用节点6-10,ParentJob#3的ChildJobs应使用节点11-15。

我看过Throttle Concurrent Builds插件和Lockable Resource插件,但它们似乎没有解决我想要实现的目标。它们似乎只在工作级别工作,而不是在构建级别工作。

我的另一个选择是编写Groovy代码来获取x个可用节点,将它们唯一标记,并在这些节点上运行子作业。作业完成后,我可以清除标签,以便其他版本可用。

是否有更简单的选项或插件可以执行此操作?也许我过于复杂了。

希望这不会太混乱。提前谢谢。

1 个答案:

答案 0 :(得分:0)

由于我找不到任何东西,我为管道工作编写了以下Groovy脚本。

此脚本将获取前3个没有“TESTING _。*”标签的从属并添加新标签。然后,仅在这些节点上执行作业,而不占用我的服务器场中的所有从属服务器。作业完成后,标签将被删除。

node ("master") {
    def new_label = "TESTING_" + org.apache.commons.lang.RandomStringUtils.random(7, true, true)
    echo "New label for slaves: " + new_label

    try {
        stage('Reserve slaves') {
            reserve_slaves(3, new_label)
        }

        stage('Smoke tests') {
            // Do your parallel jobs here
            // Pass in new_label to the job
        }
    }

    finally {
        stage('Return slaves') {
            remove_label_from_slaves(new_label)
        }
    }
}


def reserve_slaves(number_of_slaves, new_label) {
    def label_prefix = "TESTING_"
    def slaves_with_new_label = 0

    while (slaves_with_new_label < number_of_slaves) {
        for (slave in jenkins.model.Jenkins.instance.slaves) {
            def current_labels = slave.getLabelString()

            if (!current_labels.contains(label_prefix)) {
                echo "Adding label '${new_label}' to " + slave.name + ". Existing labels are: ${current_labels}"
                slave.setLabelString(current_labels + " " + new_label)
                slaves_with_new_label += 1
            }

            if (slaves_with_new_label >= number_of_slaves) {
                break
            }
        }

        if (slaves_with_new_label < number_of_slaves) {
            echo "Waiting for nodes to become available..."
            sleep(10) // in seconds
        }
    }
}


def remove_label_from_slaves(label) {
    for (slave in jenkins.model.Jenkins.instance.slaves) {
        def current_labels = slave.getLabelString()

        if (current_labels.contains(label)) {
            echo "Removing label '${label}' from " + slave.name + ". Existing labels are: ${current_labels}"

            current_labels = current_labels.replace(label, '')
            slave.setLabelString(current_labels)
        }
    }
}