一千萬個為什麽

搜索

在詹金斯運行平行階段時的一個結賬



介紹

我們有一個多分支管道項目。構建配置由jenkins文件定義。該系統由一位主人和幾位代理人組成。

這些階段是並行運行的,每個階段我們都會檢查倉庫。

請參閱下面的附件。

問題

隨著分支數量的增加,工作區的大小會大大增加。

解決方案#1

定期清理工作區。將編寫自定義腳本。 像這樣的東西:

// Check if a slave has < 10 GB of free space, wipe out workspaces if it does

import hudson.model.*;
import hudson.util.*;
import jenkins.model.*;
import hudson.FilePath.FileCallable;
import hudson.slaves.OfflineCause;
import hudson.node_monitors.*;

for (node in Jenkins.instance.nodes) {
    computer = node.toComputer()
    if (computer.getChannel() == null) continue

    rootPath = node.getRootPath()
    size = DiskSpaceMonitor.DESCRIPTOR.get(computer).size
    roundedSize = size/(1024 * 1024 * 1024) as int

    println("node: " + node.getDisplayName() + ", free space: " + roundedSize + "GB")
    if (roundedSize < 10) {
        computer.setTemporarilyOffline(true, new hudson.slaves.OfflineCause.ByCLI("disk cleanup"))
        for (item in Jenkins.instance.items) {
            jobName = item.getFullDisplayName()

            if (item.isBuilding()) {
                println(".. job " + jobName + " is currently running, skipped")
                continue
            }

            println(".. wiping out workspaces of job " + jobName)

            workspacePath = node.getWorkspaceFor(item)
            if (workspacePath == null) {
                println(".... could not get workspace path")
                continue
            }

            println(".... workspace = " + workspacePath)

            customWorkspace = item.getCustomWorkspace()
            if (customWorkspace != null) {
                workspacePath = node.getRootPath().child(customWorkspace)
                println(".... custom workspace = " + workspacePath)
            }

            pathAsString = workspacePath.getRemote()
            if (workspacePath.exists()) {
                workspacePath.deleteRecursive()
                println(".... deleted from location " + pathAsString)
            } else {
                println(".... nothing to delete at " + pathAsString)
            }
        }

        computer.setTemporarilyOffline(false, null)
    }
}

## The Solution #2 ##
One checkout per job and node. Thus each parallel stage will execute one executable instance of the same repository. For me personaly this is the preferred method, although more complex than solution #1.

pseudocode:

    stage("Build") {
        try {
            parallel builds
        } catch (err) {
        }
    }

    def build(predef) {
        return {
            node() {
                checkout_repository(${env.NODE_NAME})
                Execute build
                ...
            }
        }
    }

    def checkout_repository(node){
        No checkout for this node
            Flag that we are checking out a repository on node (think ~semaphore)
            Cheking out ..
            Flag that repository exist on node
    }

問題

  1. 解決方案#2中的缺點是什麽
  2. 是否遵循jenkins的方式。或者這是多少自由泳?

The job: The Job

轉載註明原文: 在詹金斯運行平行階段時的一個結賬

一共有 1 個回答:

你的困難源於鼓勵可能長期存在的分支機構,它偏離了CI方法 - 這就是為什麽你會首先使用jenkins(一種CI工具)。

通常情況下,您不應該為Jenkins管道中的那些分支運行測試 - 您想測量集成工作的質量,而不是在孤島中完成的工作。

我確實理解在合並到主幹之前運行這樣的測試的願望,所以也許可以使用jenkins來執行它,如果你想,但是使用單獨的作業/管道,而不是綁定到主幹管道。請記住,這些測試的結果不一定是結論性的:僅僅因為它們傳遞並不意味著相同的測試也會傳遞到主幹中,您需要非常嚴格的條件使這永遠是真的。

Personally I'd go for a fully automated patcing/merging solution based on pre-commit verifications which can enforce the strict conditions necessary to prevent post-merge trunk quality regressions (but I'm biased, I built such solutions). See for example How to ensure that git subtrees are kept up to date?

無論如何,回到問題。由於您尋求並行執行的各個管道段的代碼來自不同的分支,您將無法使用相同的工作區,您必須從相應的不同分支中提取單獨的工作區。這使問題有點沒有實際意義。

最後說明:假設在多個版本中可以使用相同的工作區 ,您的#2方法需要一個原始的構建結構。在同一個工作空間中並行運行的不完美構建並不罕見:競爭條件創建/刪除目錄,覆蓋工件,資源使用率峰值過高等 - 通常很難重現間歇性故障。例如,如果構建適用於相同的產品,但適用於不同的CPU架構,或者包含跨多個產品共享的代碼構建,則可能會發生這些情況。請註意可能性。