运行docker-in-docker时的詹金斯声明性管道问题

时间:2020-08-03 13:49:07

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

在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可执行文件。 但是,这似乎是意外的,即使不是错误。 如果有人对此有所解释,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

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

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

为什么这是预期的行为?
假设顶级代理是通过tcp或s​​sh连接的另一台物理计算机,而不是docker容器。这台机器需要安装所有工具,以进行编译,生成文档,运行单元测试等。它不会使用Jenkins主站上安装的doxygen二进制文件,因为它应该提供此信息(如果$PATH中不存在doxygen,则会抛出错误)。同样,这台机器将需要docker installer在第四阶段启动容器。

如何使管道正常工作?

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

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