如何在Jenkins的Docker容器中运行多个命令?

Eth*_*n T 5 jenkins docker

我有一个稍微复杂的构建和测试过程,我想在Docker容器中运行。由于被测软件启动了一些xterm窗口,因此我正在容器中运行X服务器和VNC supervisord来启动它们。然后,当容器supervisord作为ENTRYPOINT 运行时,我可以使用手动启动构建和测试过程docker exec

我无法确定使用Jenkins和Docker Pipeline插件执行此操作的方法。当前版本的插件似乎存在一些限制,我无法充分解决。这是基本思想:

node {
    stage('Fetch installer') {
        // SCM commands go here
    }

    def image = docker.image('metatest')
    image.inside() {
        stage('Run installer') {
            sh "./installer.sh"
        }
        stage('Run tests') {
            sh "/opt/custom/run_tests.sh"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,此方法被打破了,因为该image.inside()方法将覆盖默认用户(将其设置为Jenkins的用户ID)和ENTRYPOINT。我需要能够使用默认的root用户启动Docker容器,因为X服务器进程必须是root用户。但是,我需要以Jenkins的非root用户身份在容器中运行安装和测试,以便Jenkins可以管理输出材料。

作为记录,image.inside()在启动Docker容器时设置了许多非常有用的参数:

docker run -t -d -u 113:123 \
  -w "/var/lib/jenkins/workspace/TestProj" \
  -v "/var/lib/jenkins/workspace/TestProj:/var/lib/jenkins/workspace/TestProj:rw" \
  -v "/var/lib/jenkins/workspace/TestProj@tmp:/var/lib/jenkins/workspace/TestProj@tmp:rw" \
  -e ******** -e ******** -e ******** -e ******** -e ******** \
  -e ******** -e ******** -e ******** -e ******** -e ******** \
  -e ******** -e ******** -e ******** -e ******** -e ******** \
  -e ******** -e ******** -e ******** \
  --entrypoint cat \
  metatest
Run Code Online (Sandbox Code Playgroud)

Jenkins uid:gid对的设置,工作目录,要从主机共享的卷以及Jenkins环境变量(在此进行了屏蔽)都非常有用,并且很烦人,无法在Jenkins中手动复制。在这种情况下,ENTRYPOINT覆盖没有太大帮助。

不幸的是,Docker Pipeline命令的image.inside()实现不允许我将容器的设置与其在所创建的运行容器中的阶段执行分开来进行区分。该过程还有其他一些命令,但是它们似乎缺少实际的执行步骤,并且其中没有包含许多有用的参数设置。

换句话说,我想做这样的事情:

node {
    stage('Fetch installer') {
        // SCM commands go here
    }

    def image = docker.image('metatest')
    def container = image.run('-u 0:0')
    container.inside() {
        stage('Run installer') {
            sh "./installer.sh"
        }
        stage('Run tests') {
            sh "/opt/custom/run_tests.sh"
        }
    }
    stage('Check output') {
        // run a script on the Jenkins host
    }
    container.inside() {
        stage('Final script step') {
            sh "./another_script.py"
        }
    }
    container.stop()
    container.remove()
}
Run Code Online (Sandbox Code Playgroud)

关键区别在于:

  1. image.run() 为Jenkins设置相同的uid:gid对(然后覆盖),并添加所有工作空间,卷和环境变量,但不设置ENTRYPOINT覆盖。
  2. container.inside()存在并允许我在运行中的容器内执行执行步骤。
  3. container.inside() 设置所有与步骤1相同的参数。
  4. container.stop()仅停止容器,而remove()实际上将其删除。无需将它们合并。

通过这种方法,我可以在容器内部执行单独的命令,然后在Jenkins中运行一些其他命令,返回到容器,停止并重新启动容器,在删除容器之前保存容器的映像,等等。当前插件很难。

我已请求詹金斯(Jenkins)添加这种分离,但我需要一种没有这种分离的方法。有任何想法吗?