使用Jenkins声明性管道为

时间:2017-06-28 14:15:47

标签: docker jenkins dockerfile

我使用声明性管道语法在docker容器中执行一些CI工作。

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

我遇到了一些问题,因为容器将与非现有用户一起运行(特别是我遇到了一些用户没有主目录的问题)。所以我想创建一个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,并将其作为构建aguments发送,但我现在遇到的问题是它似乎是在指定代理之前,无法在声明性管道中执行这些命令。我希望我的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 {
        ..
      }
    }
    ...
  }
}

我有什么方法可以实现这个目标吗?我还尝试在管道中包装管道指令,但管道需要位于文件的根目录。

6 个答案:

答案 0 :(得分:11)

我确认尝试在没有节点的情况下分配user_id和group_id不起作用,正如您所发现的那样,但这对我来说可以分配这些值并稍后访问它们:

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之前,在声明性管道之外找出user_id和group_id的方法最有可能是一个关键缺陷:它发现user_id的slave不一定与用于启动基于docker的构建的slave相匹配。我没有任何解决方法,同时保持声明性Jenkinsfile约束。

您可以使用全局代理声明保证所有阶段的一个奴隶:Jenkins declarative pipeline: What workspace is associated with a stage when the agent is set only for the pipeline?

但是具有相同标签的多个节点引用不保证相同的工作区:Jenkins declarative pipeline: What workspace is associated with a stage when the agent is set only for the pipeline?

答案 1 :(得分:4)

你也可以像这样添加一个块:

agent {
    dockerfile {

        args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
    }
}

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

答案 2 :(得分:3)

您也可以使用args参数来解决问题 如Pipeline Syntax

中所述
  

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
            }
        }

答案 3 :(得分:2)

我相信我们找到了解决此问题的好方法。

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

我们还使用dockerfile agent指令在docker容器中运行所有构建。 有时我们需要通过ssh上的git访问一些私有作曲家库。

我们通过安装项目deps(composer)来利用docker映像缓存,这意味着我们仅在deps更改时才重建构建容器。这意味着我们需要在Docker构建期间注入SSH密钥。

查看以下示例文件:

project / 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.

答案 4 :(得分:1)

我尝试在 additionalBuildArgs 中使用单引号并将 id 命令直接放在 build-args 上,结果成功

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

答案 5 :(得分:0)

如果您拥有Jenkins的管理员权限,则可以添加以下两个脚本批准:

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/

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

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