用sudo运行jenkins管道代理

时间:2017-06-27 22:42:25

标签: docker jenkins jenkins-pipeline

我有一个在Docker容器中运行的Jenkins服务器,并且可以访问docker和主机系统,到目前为止它运行良好。现在我想在docker容器中设置一个测试脚本的管道。

Jenkinsfile:

pipeline {
    agent { docker 'nginx:1.11' }
    stages {
        stage('build') {
            steps {
                sh 'nginx -t'
            }
        }
    }
}

错误消息:

> + docker pull nginx:1.11
> 
> Warning: failed to get default registry endpoint from daemon (Got
> permission denied while trying to connect to the Docker daemon socket
> at unix:///var/run/docker.sock: Get
> http://%2Fvar%2Frun%2Fdocker.sock/v1.29/info: dial unix
> /var/run/docker.sock: connect: permission denied). Using system
> default: https://index.docker.io/v1/
> 
> Got permission denied while trying to connect to the Docker daemon
> socket at unix:///var/run/docker.sock: Post
> http://%2Fvar%2Frun%2Fdocker.sock/v1.29/images/create?fromImage=nginx&tag=1.11:
> dial unix /var/run/docker.sock: connect: permission denied
> 
> script returned exit code 1

我的问题是jenkins需要使用sudo运行docker命令,但是如何说使用sudo运行命令的代理?

7 个答案:

答案 0 :(得分:10)

我遇到了同样的问题。在分析了控制台日志之后,我发现原因是Docker Jenkins插件启动了一个具有特定选项 -u 107:112 的新容器:

...
docker run -t -d -u 107:112 ...
...

在尝试了许多选项后,例如:将jenkins添加到sudo组(由于jenkins用户在容器中不存在而无效),请将USER root添加到Dockerfile ,......但他们都没有做到这一点。

最后,我找到了一个在 docker agent 中使用 args 覆盖 -u 选项的解决方案。这是我的 Jenkinsfile

pipeline {
    agent {
        docker {
            image 'ubuntu'
            args '-u root:sudo -v $HOME/workspace/myproject:/myproject'
        }
    }
    stages {
        stage("setup_env") {
            steps {
                sh 'apt-get update -y'
                sh 'apt-get install -y git build-essential gcc cmake make'
            }
        }

        stage("install_dependencies") {
            steps {
                sh 'apt-get install -y libxml2-dev'
            }
        }
        stage("compile_dpi") {
            steps {
                sh 'cd /myproject && make clean && make -j4'
            }
        }

        stage("install_dpi") {
            steps {
                sh 'cd /myproject && make install'
            }
        }

        stage("test") {
            steps {
                sh 'do some test here'
            }
        }
    }
    post {
        success {
            echo 'Do something when it is successful'
            bitbucketStatusNotify(buildState: 'SUCCESSFUL')
        }
        failure {
            echo 'Do something when it is failed'
            bitbucketStatusNotify(buildState: 'FAILED')
        }
    }
}

这里可能存在安全问题,但在我的情况下这不是问题。

答案 1 :(得分:3)

我会以不同的方式解决问题,将容器内的jenkins组ID与已装入卷的docker socket相匹配。我使用以root身份运行的入口点执行此操作,查找套接字的gid,如果这与当前容器中的gid不匹配,则执行groupmod以在容器内更正它。然后我将权限下放给jenkins用户以启动Jenkins。此入口点在每次启动时运行,但对启动的Jenkins应用程序相当透明。

执行此操作的所有步骤都包含在此github存储库中:https://github.com/sudo-bmitch/jenkins-docker/

答案 2 :(得分:1)

我刚才有同样的问题。您需要将jenkins用户添加到docker组:

DOCKER_SOCKET=/var/run/docker.sock
DOCKER_GROUP=docker
JENKINS_USER=jenkins

if [ -S ${DOCKER_SOCKET} ]; then
DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCKET})
sudo groupadd -for -g ${DOCKER_GID} ${DOCKER_GROUP}
sudo usermod -aG ${DOCKER_GROUP} ${JENKINS_USER}
fi

# Start Jenkins service
sudo service jenkins restart

运行上述操作后,管道成功启动了docker

答案 3 :(得分:1)

你可以通过以下方式解决这个问题:

1-在你的Dockerfile添加jenkins到sudoers文件:

RUN echo "jenkins ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

2-在Jenkinsfile中添加一个额外步骤,为jenkins提供使用docker的正确权限:

pipeline {

    agent none

    stages {

        stage("Fix the permission issue") {

            agent any

            steps {
                sh "sudo chown root:jenkins /run/docker.sock"
            }

        }

        stage('Step 1') {

            agent {
                docker {
                    image 'nezarfadle/tools'
                    reuseNode true
                }
            }

            steps {
                sh "ls /"
            }

        }

    }
}

答案 4 :(得分:1)

对我有用的是

node() {
    String jenkinsUserId = sh(returnStdout: true, script: 'id -u jenkins').trim()
    String dockerGroupId = sh(returnStdout: true, script: 'getent group docker | cut -d: -f3').trim()
    String containerUserMapping = "-u $jenkinsUserId:$dockerGroupId "
    docker.image('image')
        .inside(containerUserMapping + ' -v /var/run/docker.sock:/var/run/docker.sock:ro') {
             sh "..."
         }
}

通过这种方式,容器中的用户仍然使用jenkins用户ID +组ID来避免权限与共享数据发生冲突,但它还是容器内部的Docker组的成员,而该组是访问Docker套接字(/ var / run / docker.sock)

我更喜欢这种解决方案,因为它不需要任何其他脚本或dockerfiles

答案 5 :(得分:0)

这里的问题相同。

[...]
agent { docker 'whatever_I_try_doesnt_work'} # sudo, jenkins user in dockerroot group etc
[...]

所以我的解决方法是将其添加为管道构建阶段中的一个步骤,如下所示:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'sudo docker pull python:3.5.1'
            }
        }
    }
}

答案 6 :(得分:0)

我可能已经找到了一个合理的解决方案。

设置

我将Jenkins作为容器运行,并使用它在运行它的dockerhost上构建容器。为此,我将/var/run/docker.sock作为卷传递给了容器。

只需重申一些其他人已经声明的免责声明:授予对docker socket的访问本质上就像是授予对计算机的root访问权限-小心!

我假设您已经将docker安装到Jenkins Image中。

解决方案

这是基于以下事实,即docker二进制文件不在$PATH的第一个目录中。我们基本上放置了一个运行sudo docker的shell脚本,而不仅仅是运行普通的docker命令(并传递参数)。

将这样的文件添加到您的jenkins存储库中,并将其命名为docker_sudo_overwrite.sh

#! /bin/sh 
# This basically is a workaround to add sudo to the docker command, because aliases don't seem to work 
# To be honest, this is a horrible workaround that depends on the order in $PATH
# This file needs to be place in /usr/local/bin with execute permissions
sudo /usr/bin/docker $@

然后像这样扩展您的詹金斯Dockerfile

# Now we need to allow jenkins to run docker commands! (This is not elegant, but at least it's semi-portable...)
USER root

## allowing jenkins user to run docker without specifying a password
RUN echo "jenkins ALL=(ALL) NOPASSWD: /usr/bin/docker" >> /etc/sudoers

# Create our alias file that allows us to use docker as sudo without writing sudo
COPY docker_sudo_overwrite.sh /usr/local/bin/docker
RUN chmod +x /usr/local/bin/docker

# switch back to the jenkins-user
USER jenkins

这使jenkins服务用户能够使用sudo以root身份运行docker二进制文件(无需提供密码)。然后,我们将脚本复制到/usr/local/bin/docker,该脚本“覆盖”实际的二进制文件并使用sudo运行它。如果有帮助,您可以在Github上查看我的示例。