使用Jenkins声明管道为Dockerfile代理设置构建ARG



我正在使用声明的管道语法在Docker容器中进行一些CI工作。

我已经注意到,Jenkins的Docker插件使用主机中Jenkins用户的用户ID和组ID运行一个容器(即,如果Jenkins用户具有用户ID 100和组ID 111,它将运行管道创建管道。带有命令docker run -u 100:111 ...的容器(。

我对此有一些问题,因为容器将与非现有用户一起运行(尤其是我遇到了一些问题,而没有家庭dir的用户(。因此,我想到创建一个Dockerfile,该Dockerfile将接收用户ID和组ID作为构建参数,并在容器内获得适当的Jenkins用户。Dockerfile看起来像这样:

FROM ubuntu:trusty
ARG user_id
ARG group_id
# Add jenkins user
RUN groupadd -g ${group_id} jenkins
RUN useradd jenkins -u ${user_id} -g jenkins --shell /bin/bash --create-home
USER jenkins
...

Dockerfile代理具有additionalBuildArgs属性,因此我可以在主机中阅读Jenkins用户的用户ID和组ID并将其作为构建agmunty发送,但是我现在遇到的问题是,似乎没有办法在指定代理商之前,在声明的管道中执行这些命令。我希望我的Jenkinsfile成为这样的事情:

// THIS WON'T WORK
def user_id = sh(returnStdout: true, script: 'id -u').trim()
def group_id = sh(returnStdout: true, script: 'id -g').trim()
pipeline {
  agent {
    dockerfile {
      additionalBuildArgs "--build-arg user_id=${user_id} --build-arg group_id=${group_id}"
    }
  }
  stages {
    stage('Foo') {
      steps {
        ...
      }
    }
    stage('Bar') {
      steps {
        ...
      }
    }
    stage('Baz') {
      steps {
        ..
      }
    }
    ...
  }
}

i有什么方法可以实现这一目标?我还尝试在节点内包装管道指令,但是管道需要位于文件的根源。

我验证了尝试在没有节点的情况下尝试分配user_id and group_id node不起作用,但这对我来说很适合我分配这些值,然后访问它们:

def user_id
def group_id
node {
  user_id = sh(returnStdout: true, script: 'id -u').trim()
  group_id = sh(returnStdout: true, script: 'id -g').trim()
}
pipeline {
  agent { label 'docker' }
  stages {
    stage('commit_stage') {
      steps {
        echo 'user_id'
        echo user_id
        echo 'group_id'
        echo group_id
      }
    }
  }
}

希望这些也可以在您的additionalBuildArgs语句中使用。

在评论中,您指出了哪些在使用dockerfile之前弄清楚用户_id和group_id的方法最有可能是一个关键的缺陷:它发现dockerfile:它发现user_id的从与它用于启动基于Docker的构建的奴隶匹配。我没有任何办法,同时还要保持声明性的Jenkinsfile约束。

您可以使用全局代理声明来保证所有阶段的一个从:詹金斯声明管道:仅设置代理仅用于管道的阶段的工作空间与阶段关联?

但是带有相同标签的多个节点引用不能保证相同的工作区:jenkins声明管道:当仅针对管道设置代理时,哪个工作空间与阶段关联?

您还可以添加一个这样的块:

agent {
    dockerfile {
        args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
    }
}

将允许容器具有正确的用户和组ID。

您也可以使用args参数解决问题。
如管道语法中所述:

Docker还可以选择接受 args 参数,该参数可能包含可以直接传递到Docker Run Invocation的参数。

使用dockerfile而不是代理中的docker也是可能的部分。

我有像你一样的问题,以下几行对我有效:

       agent { 
            dockerfile { 
                dir 'Docker/kubernetes-cli' 
                args '-u 0:0' //Forces Container tu run as User Root                    
                reuseNode true
            }
        }

我相信我们找到了一种很好的处理方式。

我们有一个作为Docker实例运行的Jenkins部署,我已映射了一个用于/var/jenkins_home的卷,并将.SSH文件夹添加到/Var/jenkins_home/.ssh

我们还使用Dockerfile代理指令在Docker容器内运行所有构建。有时我们需要通过SSH上的git访问一些私人作曲家库。

我们通过安装项目deps(Composer(来利用Docker图像缓存,这意味着我们只有在我们的DEP更改时才重建构建容器。这意味着我们需要在Docker构建过程中注入SSH密钥。

请参阅以下示例文件:

项目/jenkinsfile

def SSH_KEY
node {
  SSH_KEY = sh(returnStdout: true, script: 'cat /var/jenkins_home/.ssh/id_rsa')
}
pipeline {
  agent {
    dockerfile {
      filename 'Dockerfile'
      additionalBuildArgs '--build-arg SSH_KEY="' + SSH_KEY + '"'
      reuseNode true
    }
  }
  stages {
    stage('Fetch Deps') {
      steps {
        sh 'mv /home/user/app/vendor vendor'
      }
    }
    stage('Run Unit Tests') {
      steps {
        sh './vendor/bin/phpunit'
      }
    }
  }
}

项目/dockerfile

FROM mycompany/php7.2-common:1.0.2
# Provides the image for building mycompany/project on Jenkins.
WORKDIR /home/user/app
ARG SSH_KEY # should receive a raw SSH private key during build.
ADD composer.json .
RUN add-ssh-key "${SSH_KEY}" ~/.ssh/id_rsa && 
    composer install && 
    remove-ssh-keys
# Note: add-ssh-key and remove-ssh-keys are our shell scripts put in
# the base image to reduce boilerplate for common tasks.

我尝试使用额外buildargs中的单个引号,然后将id命令直接放在build-args上,并且它起作用

pipeline {
  agent {
    dockerfile {
      additionalBuildArgs '--build-arg user_id=$(id -u) --build-arg group_id=$(id -g)'
    }
  }
...

如果您可以访问詹金斯,则可以添加这两个脚本批准:

staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods execute java.lang.String
staticMethod org.codehaus.groovy.runtime.ProcessGroovyMethods getText java.lang.Process

在此uri中: http://${jenkins_host:port}/jenkins/scriptApproval/

这将允许您以这种方式在主机中执行shell命令:

def user = 'id -u'.execute().text
node {
   echo "Hello World ${user}"
}

最新更新