【问题标题】:Unable to pip install in Docker image as agent through Jenkins declarative pipeline无法通过 Jenkins 声明式管道在 Docker 映像中作为代理进行 pip 安装
【发布时间】:2018-08-02 08:02:40
【问题描述】:

我还有一个问题,即通过 Jenkins 声明性管道运行 Docker 的权限问题。我想通过 Docker 容器中的 Jenkins 作业构建和发布 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 in /usr/local/lib/python3.7/site-packages(来自 -r requirements.txt(行 1)) (40.0.0) 收集 pytest(来自 -r requirements.txt(第 2 行))
下载 https://files.pythonhosted.org/packages/9e/a1/8166a56ce9d89fdd9efcae5601e71758029d90e5644e0b7b6eda07e67c35/pytest-3.7.0-py2.py3-none-any.whl (202kB) 收集 py>=1.5.0 (来自 pytest->-r requirements.txt (行 2)) 下载 https://files.pythonhosted.org/packages/f3/bd/83369ff2dee18f22f27d16b78dd651e8939825af5f8b0b83c38729069962/py-1.5.4-py2.py3-none-any.whl (83kB) 收集更多-itertools>=4.0.0 (来自 pytest->-r requirements.txt(第 2 行))下载 https://files.pythonhosted.org/packages/79/b1/eace304ef66bd7d3d8b2f78cc374b73ca03bc53664d78151e9df3b3996cc/more_itertools-4.3.0-py3-none-any.whl (48kB) 收集pluggy>=0.7(来自pytest->-r requirements.txt(行 2)) 下载 https://files.pythonhosted.org/packages/f5/f1/5a93c118663896d83f7bcbfb7f657ce1d0c0d617e6b4a443a53abcc658ca/pluggy-0.7.1-py2.py3-none-any.whl 收集六>=1.10.0(来自pytest->-r requirements.txt(第2行))
下载 https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl 收集 atomicwrites>=1.0(来自 pytest->-r requirements.txt(行 2)) 下载 https://files.pythonhosted.org/packages/0a/e8/cd6375e7a59664eeea9e1c77a766eeac0fc3083bb958c2b41ec46b95f29c/atomicwrites-1.1.5-py2.py3-none-any.whl 收集 attrs>=17.4.0(来自 pytest->-r requirements.txt(第 2 行))
下载 https://files.pythonhosted.org/packages/41/59/cedf87e91ed541be7957c501a92102f9cc6363c623a7666d69d51c78ac5b/attrs-18.1.0-py2.py3-none-any.whl 安装收集包:py、六、more-itertools、pluggy、 atomicwrites, attrs, pytest

由于 EnvironmentError 无法安装软件包:[Errno 13] Permission denied: '/.local' 检查权限。

如何修复这些权限?

【问题讨论】:

  • 不要使用--user,因为看起来你已经是容器的根了。 --user 用于非特权安装。
  • 您当然可以通过在docker 声明中添加args '--user 0:0' 以root 身份运行代理,但是找出默认设置和pip installing 与@ 的问题会很有趣987654336@标志。
  • Jenkins 添加了-u 1001:1001,确实用-u 0:0 否决了这个问题可以解决问题。但是,pip install ... --user 不起作用对我来说没有意义。 docker 镜像中的权限是否设置错误?
  • 是的,这有点道理。问题是python:3.7 图像对 ID 为 1001 的用户一无所知 - 如果您在容器内运行cat /etc/passwd | grep 1001,将找不到任何内容。 Jenkins 以不存在的用户身份启动容器,passwd 中没有条目,没有主目录等。我假设在这种情况下HOME 留给/,所以pip install --user 求助于安装到@987654346 @ which 1. 不存在,如果存在 2. 无论如何都属于 root。
  • 我猜你必须以 root 身份运行容器(糟糕!但是,取决于容器的用途 - 如果在构建后处理它,它可能是无害的以 root 身份运行它),或者编写您自己的 Dockerfile 继承自 python:3.7 以添加适当的非 root 用户。然后将此用户传递给 Jenkinsfile 中的 docker 代理。

标签: python docker jenkins pip


【解决方案1】:

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

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 withEnv(["HOME=${env.WORKSPACE}"]) 是不同的。容器内的用户不是root用户,也不存在于容器内,所以设置为/的工作目录。
  • withEnv(["HOME=${env.WORKSPACE}"]) {} 是关键。此外,它可以像这样使用:``` node { def customImage = docker.build(...) customImage.inside { withEnv(["HOME=${env.WORKSPACE}"]) { sh '...' } } } ```
【解决方案2】:

在我的 Jenkins 系统上设置 Docker 代理后,我正在运行一个非常相似的管道,所以我认为我的设置是错误的。使用您线程中的 cmets,我制定了这个解决方案:

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

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

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

steps {
    sh 'git clean -fdx'
}

更新:

我发现了一个问题,即失败的构建不会清理并杀死它之后的所有构建。为了解决这个问题,我将 clean 操作设置为始终运行的 post-build task

post {
    cleanup {
        cleanWs()
    }
}

【讨论】:

  • 这与 @casparjespersen 建议的 post { cleanup { cleanWs() } } 完美结合
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    你可以尝试用 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 中提到的步骤操作

    【讨论】:

    • 我不认为sudo 会带来任何东西,因为看起来 OP 在容器中已经是根目录了。
    • 我同意@hoefling。另外,基于 python:3.7 的 Docker 镜像没有安装 sudo :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    相关资源
    最近更新 更多