【问题标题】:Running multiple Docker containers from a single Jenkinsfile从单个 Jenkinsfile 运行多个 Docker 容器
【发布时间】:2018-04-11 18:37:51
【问题描述】:

所以我花了一整天的时间试图弄清楚如何使用多个 Docker 映像配置一个简单的 Jenkins 流水线,我一点也不高兴。

我需要在几个不同的 docker 容器上执行几个阶段(准备、构建、测试、文档)(目前我只选择了三个标准的 Python 容器)。如果它们可以并行运行会很好,但我只找到了这个解决方案,它将所有阶段组合成一个阶段(因此在 Blue Ocean UI 中创建了一个信息量不大的概述):Jenkins Pipeline Across Multiple Docker Images

所以我最终得到了下面的配置,这非常丑陋(到处重复代码),但或多或​​少地在经典 UI 中创建了一个好看的概览:

Blue Ocean UI 中信息量不大的概述

还有来自junit 的可接受测试概述,它结合了每个阶段的所有测试,但如果任何测试失败,则会显示相应的“版本”:

然而,最烦人的是,你看不到哪一步失败了。如果 Python 2.7 失败,其他所有内容也会被标记为失败,您甚至看不到哪个阶段失败了。

我尝试了很多不同的方法,我想知道应该如何做到这一点。这对 Jenkins 来说应该是一件很常见的事情,所以我想我对这个(对我来说绝对是新的)管道/节点/标签/阶段/步骤/声明/脚本/groovy/blueocean 的东西有一些普遍的误解......

应该可以为每个容器定义一个 docker 容器列表(可能是可自定义的阶段/步骤)并并行运行它们,并让它在 Blue Ocean 和 Classic UI 中很好地显示,不是吗?

node {
    stage("Python 2.7.14") {
        checkout scm
        docker.image('python:2.7.14').inside {  // just a dummy for now
            stage("Prepare") { sh 'python --version' }
            stage("Build") { sh 'ls -al' }
        }
    }
    stage("Python 3.5.4") {
        checkout scm
        docker.image('python:3.5.4').inside {
            stage("Prepare") { sh 'python -m venv venv' }
            stage("Build") {
                sh """
                    . venv/bin/activate
                    make install-dev
                """
            }
            stage('Test') {
                sh """
                    . venv/bin/activate
                    make test
                """
            }
            stage('Docs') {
                sh """
                    . venv/bin/activate
                    make doc-dependencies
                    cd docs
                    make html
                """
            }
        }
    }
    stage("Python 3.6.4") {
        checkout scm
        docker.image('python:3.5.4').inside {
            stage("Prepare") { sh 'python -m venv venv' }
            stage("Build") {
                sh """
                    . venv/bin/activate
                    make install-dev
                """
            }
            stage('Test') {
                sh """
                    . venv/bin/activate
                    make test
                """
            }
            stage('Docs') {
                sh """
                    . venv/bin/activate
                    make doc-dependencies
                    cd docs
                    make html
                """
            }
        }
    }
}

更新:当步骤失败时,这就是 Blue Ocean UI 中的样子,在这种情况下,Python 3.5.4 和 3.6.4 中的“测试”都失败了,但看起来一切都失败了。

另外 Python 2.7.14 和 3.5.4 阶段也被折叠,不能单独查看。如果我单击其中一个,所有步骤都显示为绿色,尽管在这种情况下 . venv/bin/activate make test 失败:

【问题讨论】:

  • 经典 UI 无法显示并行分支。您将始终只看到舞台名称。
  • 您可以重构代码并避免过多重复,方法是将要执行的命令存储在pipeline 语句(def buildCommand = "...")之前的变量中。
  • 就个人而言,我建议您放弃可视化并遍历定义的容器图像列表,这些容器图像都应该并行执行构建。这应该看起来非常紧凑,然后在代码方面,并且执行速度也更快。
  • 当您说当某个步骤失败时全部标记为红色时,a) 仅适用于经典 UI,b) 实际失败的一个阶段应以粗体显示。
  • 所以..你的问题涵盖了几个方面。不过,我认为你应该得到一些帮助,因为它总体上准备得很好。

标签: docker jenkins groovy jenkins-pipeline


【解决方案1】:

所以这就是我最终的结果。肯定有更好的解决方案,但我必须继续前进。我希望及时收集一些(更好的)答案,我不会将其标记为“解决方案”;)

首先,感谢 Stephen Kings 的幻灯片(标题为“声明式”,但有一些关于脚本化管道的不错示例):(Declarative) Jenkins Pipelines

这是我的gist on GitHub,带有以下 sn-p:

def docker_images = ["python:2.7.14", "python:3.5.4", "python:3.6.2"]

def get_stages(docker_image) {
    stages = {
        docker.image(docker_image).inside {
            stage("${docker_image}") {
                echo 'Running in ${docker_image}'
            }
            stage("Stage A") {
                switch (docker_image) {
                    case "python:2.7.14":
                        sh 'exit 123'  // for python 2.7.14 we force an error for fun
                        break
                    default:
                        sh 'sleep 10'  // for any other docker image, we sleep 10s
                }
                sh 'echo this is stage A'  // this is executed for all
            }
            stage("Stage B") {
                sh 'sleep 5'
                sh 'echo this is stage B'
            }
            stage("Stage C") {
                sh 'sleep 8'
                sh 'echo this is stage C'
            }

        }
    }
    return stages
}

node('master') {
    def stages = [:]

    for (int i = 0; i < docker_images.size(); i++) {
        def docker_image = docker_images[i]
        stages[docker_image] = get_stages(docker_image)
    }

    parallel stages
}

我试图让它易于使用:

  • 您将 Docker 映像添加到顶部的列表中,然后在 get_stages() 函数中定义 stages
  • 添加常用阶段和步骤
  • 如果任何 Docker 映像需要特殊处理(例如我的示例中的python:2.7.14),您可以使用简单的switch。这也可以通过特殊情况的双映射('images'->'stage'='steps')和默认的后备双映射来实现,但我将把它作为练习留给读者。 (说实话,我想不出正确的、受支持的 Groovy-lang 语法)

这是 Classic 和 Blue Ocean UI 中一切正常时的样子(众所周知,Blue Ocean UI 无法在并行运行中显示多个阶段,请参阅JENKINS-38442):

经典用户界面

蓝海用户界面

如果python:2.7.14 中的Stage A 失败,则输出如下:

经典用户界面

蓝海用户界面

【讨论】:

  • 如果我的测试需要 MySQL 怎么办?
  • @HappyCoder 您可以提供自己的 Dockerfile,在容器设置期间将在其中安装 mysql
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-22
  • 2018-09-14
  • 1970-01-01
  • 2015-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多