从另一个阶段重复调用一个阶段

时间:2019-10-24 15:01:15

标签: jenkins jenkins-pipeline

我目前正在写一份作业,将上游Docker映像克隆到我的内部Docker存储库中。 我的工作参数页面看起来像

enter image description here

因此,它将获取所有图像,然后生成实际外观的路径

pipeline {
    agent none
    stages {
        stage('Create new image paths:tag'){
            steps {
                script {
                    params.IMAGES.split("\\r?\\n").each{ oldfullPath ->
                        def (path, tag) = oldfullPath.tokenize( ':' )
                        def app = path.tokenize('/')[-1]
                        println "App is ${app} and Tag is ${tag}"
                        switch(params.REPO) {
                            case "monitoring":
                                image = "eu.gcr.io/<PROJECT>/infra/monitoring"
                                break
                            case "apps":
                                image = "eu.gcr.io/<PROJECT>/infra/apps"
                                break
                        }
                        def newFullPath = "${image}/${app}:${tag}"
                        println "Full old image path is ${oldfullPath}"
                        println "Full new image path is ${newFullPath}"
                        // Pull and Push Image stage should be called here ! Using `${oldfullPath}` and `${newFullPath}`
                    }
                }
            }
        }

如您所见,由于我有多行输入,因此必须使用循环遍历每一行,获取应用程序名称和标记,然后使用switch生成newpath。因此,对于每次迭代,我得到${oldfullPath}${newfullPath}

现在,我需要拉动这些docker镜像。我不想利用dind,所以我正在使用Kaniko。而要拉动图像,我可以使用类似这样的东西:

stage('Pull and Push Image') {
    agent {
        label "kaniko"
    }
    steps {
        container(name: 'kaniko', shell: '/busybox/sh') {
            withCredentials([
                string(credentialsId: 'infra', variable: 'PASS')
            ]) {
                withEnv(['PATH+EXTRA=/busybox:/kaniko']) {
                    sh """#!/busybox/sh
                    echo "FROM <OLD-IMAGE-PATH-COMES-HERE>" | \
                    /kaniko/executor \
                        --dockerfile /dev/stdin \
                        --destination <NEW-IMAGE-PATH-COMES-HERE>
                    """
                }
            }
        }
    }
}

如您所见,这是一个完全不同的阶段。因此,我不确定如何从上一阶段重复调用Pull and Push Image阶段。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

这里有很多事情要处理。

首先,如果您只想将Docker映像复制到注册表中,可以按照以下步骤进行操作:

me@vm:~$ docker pull alpine:latest
latest: Pulling from library/alpine
89d9c30c1d48: Pull complete
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
me@vm:~$ docker tag alpine:latest my-registry.my-company.io/alpine:latest
me@vm:~$ docker push my-registry.my-company.io/alpine:latest
The push refers to a repository [my-registry.my-company.io/alpine]
77cae8ab23bf: Pushed
latest: digest: sha256:e4355b66995c96b4b468159fc5c7e3540fcef961189ca13fee877798649f531a size: 528

第二,您可以在循环中的容器内完成解析,而不是在单独的步骤中进行

stage('Pull and Push Image') {
    agent {
        label "kaniko"
    }
    steps {
        container(name: 'kaniko', shell: '/busybox/sh') {
            withCredentials([
                string(credentialsId: 'infra', variable: 'PASS')
            ]) {
                withEnv(['PATH+EXTRA=/busybox:/kaniko']) {
                    // RUN THE LOOP HERE
                    script {
                    params.IMAGES.split("\\r?\\n").each{ oldfullPath ->
                        def (path, tag) = oldfullPath.tokenize( ':' )
                        def app = path.tokenize('/')[-1]
                        println "App is ${app} and Tag is ${tag}"
                        switch(params.REPO) {
                            case "monitoring":
                                image = "eu.gcr.io/<PROJECT>/infra/monitoring"
                                break
                            case "apps":
                                image = "eu.gcr.io/<PROJECT>/infra/apps"
                                break
                        }
                        def newFullPath = "${image}/${app}:${tag}"
                        println "Full old image path is ${oldfullPath}"
                        println "Full new image path is ${newFullPath}"

                    sh """#!/busybox/sh
                    echo "FROM ${oldfullPath}" | \
                    /kaniko/executor \
                        --dockerfile /dev/stdin \
                        --destination ${newFullPath}
                    """
              // adjust closing brackets as needed 

这当然会在单个节点上按顺序运行建筑物,这可能对您来说还可以,或者可能不行。

现在,让我们假设您真正的问题是,“如何在声明式管道中启动未知数量的并行阶段?”

答案是,您可以以编程方式构建管道,如下所示:

images_array = ["quay.io/one", "docker.io/two", "docker.io/three"] // or split params as needed

def getBuilders()
{
    def builders = [:]

    images_array.eachWithIndex { it, index ->
        // name the stage
        def name = 'Build image #' + (index + 1)
        builders[name] = {
            stage (name) {
                def my_label = "kaniko" // can choose programmatically if needed
                node(my_label) {
                    timeout(time: 2, unit: 'HOURS') { 
                        try {
                            buildOneImage(it)
                        }
                        catch (err) { println "Failed to build ${it}"; throw err  }
                        finally {  }
                    }
                }
            }
        }
    };
    return builders
}

def buildOneImage(old_path) {
   // replace path as needed, build image
   // use scripted-style pipeline, not the declarative one
}

然后在您的主管道中

        stage('Build all images') {
            steps {
                script {
                    def builders = getBuilders()
                    parallel builders
                }
            }