我有一个在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运行命令的代理?
答案 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上查看我的示例。