通过Jenkins声明性流水线作为代理,无法在Docker镜像中使用pip install

12

我在使用Jenkins声明性流水线通过Docker运行时遇到了另一个权限问题。我想通过Jenkins作业在Docker容器中构建和发布Python软件包:

pipeline {

  agent {
    docker {
      image 'python:3.7'
      label 'docker && linux'
    }
  }

  environment {
    PACKAGE_VERSION = readFile 'VERSION'
  }

  stages {

    stage('Package') {
      steps {
        sh 'python -V'
        sh 'python -m pip install -r requirements.txt --user --no-cache'
        sh 'python setup.py sdist'
      }
    }

    stage('Deploy') {
      steps {
        ...
      }
    }

  }

  post {
    always {
      cleanWs()
    }
  }

}

然而,我由于PermissionError的原因无法执行pip install命令:

运行命令+python -m pip install -r requirements.txt --user --no-cache已经安装过了setuptools。从requirements.txt文件的第2行下载pytesthttps://files.pythonhosted.org/packages/9e/a1/8166a56ce9d89fdd9efcae5601e71758029d90e5644e0b7b6eda07e67c35/pytest-3.7.0-py2.py3-none-any.whl、py>=1.5.0https://files.pythonhosted.org/packages/f3/bd/83369ff2dee18f22f27d16b78dd651e8939825af5f8b0b83c38729069962/py-1.5.4-py2.py3-none-any.whl、more-itertools>=4.0.0https://files.pythonhosted.org/packages/79/b1/eace304ef66bd7d3d8b2f78cc374b73ca03bc53664d78151e9df3b3996cc/more_itertools-4.3.0-py3-none-any.whl、pluggy>=0.7https://files.pythonhosted.org/packages/f5/f1/5a93c118663896d83f7bcbfb7f657ce1d0c0d617e6b4a443a53abcc658ca/pluggy-0.7.1-py2.py3-none-any.whl、six>=1.10.0https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl、atomicwrites>=1.0https://files.pythonhosted.org/packages/0a/e8/cd6375e7a59664eeea9e1c77a766eeac0fc3083bb958c2b41ec46b95f29c/atomicwrites-1.1.5-py2.py3-none-any.whl和attrs>=17.4.0https://files.pythonhosted.org/packages/41/59/cedf87e91ed541be7957c501a92102f9cc6363c623a7666d69d51c78ac5b/attrs-18.1.0-py2.py3-none-any.whl。但是,因为权限错误而无法安装软件包,请检查权限。

我该如何修复这些权限?


2
当然,您可以通过在docker声明中添加args '--user 0:0'来以root身份运行代理,但是找出默认设置和使用--user标志进行pip install的问题会很有趣。 - hoefling
1
Jenkins添加了-u 1001:1001,覆盖它的-u 0:0确实解决了问题。但是,对我来说,pip install ... --user无法正常工作就没有意义了。Docker镜像中的权限设置可能有问题吗? - casparjespersen
2
是的,这有点说得通。问题在于 python:3.7 镜像对 ID 为 1001 的用户一无所知 - 如果在容器内运行 cat /etc/passwd | grep 1001,将什么也找不到。Jenkins 以不存在的用户启动容器,没有 passwd 条目,没有主目录等。我假设在这种情况下 HOME 被留空为 /,因此 pip install --user 会安装到 /.local,但是 1. 它不存在,即使存在 2. 它也属于 root。 - hoefling
1
我猜你要么以root身份运行容器(呸!但是这取决于容器的用途——如果在构建后被丢弃,以root身份运行可能是无害的),要么编写自己的Dockerfile,继承自“python:3.7”,并添加一个适当的非root用户。然后在Jenkinsfile中将此用户传递给docker代理。 - hoefling
@hoefling 我使用了 --user 0:0 参数,确实可以工作,但是再次运行管道时出现了问题,你解决了吗? - tiagosilva
显示剩余6条评论
4个回答

14

我已经找到了我自己认为更漂亮的解决方案:

stage("Python Test") {
  agent { 
    docker {
      label "docker && linux" 
      image "python:3.7"
    }
  }
  steps {
    withEnv(["HOME=${env.WORKSPACE}"]) {
      sh "pip install -r requirements.txt --user"
      # python stuff
    }
  }
  post {
    cleanup {
      cleanWs()
    }
  }
}

这种解决方法完全避开了问题本身,将软件包安装在用户级别。这里的问题是初始情况下HOME目录也无法写入,从而覆盖了HOME目录。


我对这个答案感到困惑。问题中显示已经使用了 --user,这意味着包已经在用户级别上安装了。那么权限错误的来源是什么? - cowlinator
1
@cowlinator withEnv(["HOME=${env.WORKSPACE}"]) 的作用是设置容器内的用户不是root,但也不存在于容器内,因此将其设置为工作目录/ - CivFan
withEnv(["HOME=${env.WORKSPACE}"]) {} is the key. Also, it can be used like:node { def customImage = docker.build(...) customImage.inside { withEnv(["HOME=${env.WORKSPACE}"]) { sh '...' } } } - Lane
请访问以下链接获取翻译后的文本:https://dev59.com/0lUL5IYBdhLWcg3wQWKD?rq=3 - Max Cascone

4

我在设置Docker代理程序后立即运行了类似的流水线,因此我认为我的设置有误。参考您线程中的评论,我制定了以下解决方案:

首先,您需要在容器内成为root用户,因此请将代理声明更改为类似于以下内容:

agent {
    docker {
        image "python:3.7"
        args '--user 0:0'
    }
}

现在我能够使用pip install了!但是,作业的后续运行将尝试运行git clean并失败,因为容器中创建的构建文件是由root创建的。为了解决这个问题,我在容器内运行了清理命令作为我的最后一步:

steps {
    sh 'git clean -fdx'
}

更新:

我发现一个问题,即失败的构建不会清理并杀死之后的所有构建。为了解决这个问题,我将“清理”动作作为后置构建任务进行了处理,以确保它始终运行:

post {
    cleanup {
        cleanWs()
    }
}

这个与@casparjespersen建议的post { cleanup { cleanWs() } }结合使用,完美地运行了。 - RonquilloAeon

0

withEnv(["HOME=${env.WORKSPACE}"]) {} 是关键。此外,它可以像这样使用:

node {
    def customImage = docker.build(...)
    customImage.inside {
        withEnv(["HOME=${env.WORKSPACE}"]) {
            sh '...'
        }
    }
}

请参考以下链接:https://dev59.com/0lUL5IYBdhLWcg3wQWKD?rq=3 - Max Cascone

-1

你可以尝试使用sudo来执行:

 stage('Package') {
      steps {
        sh '''
            python -V
            sudo python -m pip install -r requirements.txt --user --no-cache
            sudo python setup.py sdist
           '''
      }
    }

你可能会遇到问题,因为Jenkins无法以sudo命令运行,这种情况下我建议你按照this articlethis SO question中提到的步骤进行操作。


3
我认为 sudo 不会有任何作用,因为看起来 OP 已经是容器中的 root 用户了。 - hoefling
1
我同意@hoefling的观点。此外,基于python:3.7的Docker镜像没有安装sudo :-) - casparjespersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接