【问题标题】:Jenkins declarative pipeline problem when running docker-in-docker运行 docker-in-docker 时的 Jenkins 声明性管道问题
【发布时间】:2023-03-07 14:04:02
【问题描述】:

我刚刚在 Jenkins 服务器上运行 Jenkins 声明式管道时遇到了一个问题,该服务器本身在 Docker 中运行,可以从主机访问 docker.sock

管道的结构比较简单:

pipeline {
    agent {
        docker { image 'gradle:jdk11' }
    }
    stages {
        stage('Checkout') {
            steps {
                // ...
            }
        }
        stage('Assemble public API documentation') {
            environment {
                // ...
            }
            steps {
                // ...
            }
        }
        stage('Generate documentation') {
            steps {
                // ...
            }
        }
        stage('Upload documentation to Firebase') {
            agent {
                docker {
                    image 'node:12'
                    reuseNode false
                }
            }
            steps {
                // ...
            }
        }
    }
}

想法是在第一个容器中运行三个阶段,然后为最后一个阶段创建一个新容器。 进入最后阶段时打印如下:

[Pipeline] stage
[Pipeline] { (Upload documentation to Firebase)
[Pipeline] getContext
[Pipeline] isUnix
[Pipeline] sh
+ docker inspect -f . node:12
/var/jenkins_home/workspace/publish_public_api_doc@tmp/durable-bc4d65d1/script.sh: 1: /var/jenkins_home/workspace/publish_public_api_doc@tmp/durable-bc4d65d1/script.sh: docker: not found
[Pipeline] isUnix
[Pipeline] sh
+ docker pull node:12
/var/jenkins_home/workspace/publish_public_api_doc@tmp/durable-297d223a/script.sh: 1: /var/jenkins_home/workspace/publish_public_api_doc@tmp/durable-297d223a/script.sh: docker: not found
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
$ docker stop --time=1 367647f97c9eed52bf85c13c2bc2203bb7194adac803d37cab0e0d0435325efa
$ docker rm -f 367647f97c9eed52bf85c13c2bc2203bb7194adac803d37cab0e0d0435325efa
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 127
Finished: FAILURE

我真的不明白这里发生了什么。 为了调试它,我登录到那台机器,并从主机以及正在运行的 Jenkins 容器内部运行 docker 命令,它正在工作。 设置方式是 Docker 客户端安装在镜像中,即二进制文件本身不共享到容器中。 由于docker 命令是“未找到”,我唯一的解释是docker 命令为最后阶段启动代理 没有在“顶级”中执行Jenkins 容器,但是在 JDK 中,它里面没有 docker 可执行文件。 然而,这似乎是出乎意料的,如果不是一个错误的话。 如果有人对此有所了解,我将不胜感激。

【问题讨论】:

    标签: docker jenkins jenkins-pipeline jenkins-declarative-pipeline docker-in-docker


    【解决方案1】:

    Jenkins 管道代理/节点
    您的管道已指定要在最顶层运行的代理。管道将在该代理上(或在您的场景中的 docker 容器内)执行所有命令,直到指定另一个代理。当指定新代理时,顶级代理将通过某种协议连接到它,新代理将执行此代理范围内的所有管道阶段/步骤。一旦超出范围,与新代理的连接将被关闭,顶级代理将再次执行所有命令。

    导致错误的原因是什么?
    第四阶段尝试将执行上下文更改为新代理。当前代理 gradle:jdk11 容器将执行连接到这个新代理的步骤。由于新代理是一个 docker 容器,gradle:jdk11 容器将尝试使用 docker 命令本身来启动新容器。
    正如您所怀疑的,此容器中没有 docker 二进制文件/服务。

    为什么这是预期的行为?
    假设顶层代理是通过 tcp 或 ssh 连接的不同物理机,而不是 docker 容器。这台机器需要安装所有用于编译、生成文档、运行单元测试等的工具。它不会使用安装在 Jenkins 主机上的 doxygen 二进制文件,因为它应该自己提供(如果 doxygen 在$PATH 中不存在,则会抛出错误)。同样,这台机器需要 docker 安装程序在第四阶段启动容器。

    我怎样才能让我的管道正常工作?

    • 您可以创建自己的自定义 docker 映像,继承自 gradle:jdk11 并共享主机系统的 docker。这将允许您的自定义图像启动第四阶段所需的 docker 图像。您将在全局范围内使用 agent { docker { image 'my-custom-img' } }

    • 或者,您可以在全局范围内使用主代理(或其他物理机器),并让每个阶段启动自己的容器。每个阶段都有一个干净的工作环境,因此您需要使用stash/unstash 或挂载的卷在阶段之间共享 src/docs。

    【讨论】:

      猜你喜欢
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多