【问题标题】:How does one create a Python virtualenv in Jenkins?如何在 Jenkins 中创建 Python virtualenv?
【发布时间】:2015-04-10 20:25:03
【问题描述】:

我正在使用 Makefile 提供一致的单一命令来设置 virtualenv、运行测试等。我已将 Jenkins 实例配置为从 mercurial repo 中提取,然后运行“make virtualenv”,它会执行以下操作:

virtualenv --python=/usr/bin/python2.7 --no-site-packages . && . ./bin/activate && pip install -r requirements.txt

但由于某种原因,它坚持使用系统安装的 pip 并尝试将我的包依赖项安装在系统站点包而不是 virtualenv 中:

error: could not create '/usr/local/lib/python2.7/dist-packages/flask': Permission denied

如果我添加一些调试命令并明确指向我的 virtualenv 中的 pip,事情会变得更加混乱:

virtualenv --python=/usr/bin/python2.7 --no-site-packages . && . ./bin/activate && ls -l bin && which pip && pwd && ./bin/pip install -r requirements.txt

生成以下输出:

New python executable in ./bin/python2.7
Not overwriting existing python script ./bin/python (you must use ./bin/python2.7)
Installing setuptools, pip...done.
Running virtualenv with interpreter /usr/bin/python2.7

看来 Jenkins 不会为每个构建从头开始重建环境,这让我觉得这是一个奇怪的选择,但不应该影响我的直接问题

“ls -l bin”的输出显示要安装在 virtualenv 中的 pip 和可执行文件:

-rw-r--r-- 1 jenkins jenkins    2248 Apr  9 21:14 activate
-rw-r--r-- 1 jenkins jenkins    1304 Apr  9 21:14 activate.csh
-rw-r--r-- 1 jenkins jenkins    2517 Apr  9 21:14 activate.fish
-rw-r--r-- 1 jenkins jenkins    1129 Apr  9 21:14 activate_this.py
-rwxr-xr-x 1 jenkins jenkins     278 Apr  9 21:14 easy_install
-rwxr-xr-x 1 jenkins jenkins     278 Apr  9 21:14 easy_install-2.7
-rwxr-xr-x 1 jenkins jenkins     250 Apr  9 21:14 pip
-rwxr-xr-x 1 jenkins jenkins     250 Apr  9 21:14 pip2
-rwxr-xr-x 1 jenkins jenkins     250 Apr  9 21:14 pip2.7
lrwxrwxrwx 1 jenkins jenkins       9 Apr 10 19:31 python -> python2.7
lrwxrwxrwx 1 jenkins jenkins       9 Apr 10 19:31 python2 -> python2.7
-rwxr-xr-x 1 jenkins jenkins 3349512 Apr 10 19:31 python2.7

“which pip”的输出似乎要使用正确的:

/var/lib/jenkins/jobs/Run Tests/workspace/bin/pip

我当前的工作目录是我所期望的:

/var/lib/jenkins/jobs/Run Tests/workspace

但是... wtf?

/bin/sh: 1: ./bin/pip: Permission denied
make: *** [virtualenv] Error 126
Build step 'Execute shell' marked build as failure
Finished: FAILURE

【问题讨论】:

    标签: jenkins virtualenv


    【解决方案1】:

    在过去的两年里,我每天都在使用 python virtualenvs 和 Jenkins,在多家公司和小型副项目中,我不能说我找到了“THE”的答案。不过,我希望分享我的经验可以帮助其他人节省时间。希望我能得到进一步的反馈,以便更容易做出决定。

    • 避免使用 ShiningPanda - 它维护不善,与 Jenkins2 管道不兼容,并阻止并行执行作业。此外,它还有将孤儿环境留在磁盘上的坏习惯。
    • 通过 bash 和 virtualenv DIY 是我目前的最爱。在 $WORKSPACE 中创建它,如果不总是清理,请在激活它们之前运行relocatable。这是因为 jenkins 工作区文件夹磁盘位置可以在作业 N 和 N+1 的执行之间发生变化。

    如果您使用多个确实需要相同 virtualenv 的构建器,最简单的方法是将您的环境转储到一个文件中,并在新构建器的开头获取它。

    为了便于维护,我计划调查以下内容:

    • 目录
    • virtualenv 包装器 (mkvirtualenv)
    • pyenv

    如果你点击了 shebang 命令行限制,最好的办法是将你的 jenkins 主目录更改为 /j

    【讨论】:

    • 同意,windows 也是如此。直接输入“运行 windows 批处理文件”的简单批处理文件效果很好。然后只需使用 python 获取环境变量或参数并从那里获取。
    • 我不知道该怎么做。你有一个基本的例子吗?我这样尝试: sh 'python3 -m virtualenv env' sh '。 ./env/bin/activate && pip install conan' 但它没有安装任何东西......
    • 请在帖子中添加示例,否则帖子根本没有用。
    • 这不是一个有用的 stackoverflow 答案——它更像是在吹嘘“我能做到,但我不会告诉你可怜的人怎么做” 对于像这样的答案应该有一个多反对选项这个。
    • 可重定位链接已损坏
    【解决方案2】:

    Jenkins 流水线可以在虚拟环境中运行,但需要考虑多个方面。

    • Jenkins 使用的默认 shell 是 /bin/sh - 这可以在 Manage Jenkins -> Configure System -> Shell -> Shell executable 中进行配置。将此设置为 /bin/bash 将使 source 工作。
    • 激活的 venv 只会更改环境变量,并且环境变量不会在 jenkins 的各个阶段之间持续存在。见withEnv
    • 如果您使用版本控制的多分支管道,jenkins 会创建一个工作区,其中包含分支名称和路径中的提交哈希 - 这可能会很长。 venv 脚本(例如 pip)都以 hashbang 行开头,其中包括 venv 中 python 解释器的完整路径(python 解释器本身是一个符号链接)。例如,

      ~/workspace/ink_feature-use-jenkinsfile-VGRPYD53GGGDDSBIJDLSUDYPJ34QR63ITGMC5VJNB56W6ID244AA/env/bin$ cat pip
      #!/var/jenkins_home/workspace/ink_feature-use-jenkinsfile-VGRPYD53GGGDDSBIJDLSUDYPJ34QR63ITGMC5VJNB56W6ID244AA/env/bin/python3.5
      

      Bash 只读取任何可执行文件的第一个 N 字符 - 我发现它并没有完全包含完整的 venv 路径:

      bash: ./pip: /var/jenkins_home/workspace/ink_feature-use-jenkinsfile-VGRPYD53GGGDDSBIJDLSU: bad interpreter: No such file or directory
      

      可以通过使用 Python 执行脚本来避免这个特殊问题。例如。 python3.5 ./pip

    【讨论】:

      【解决方案3】:

      我建议避免使用 ShiningPanda。

      我使用Anaconda/Miniconda 设置我的虚拟环境。安装 conda 时,请确保您以 jenkins 用户身份运行。

      your_user@$ sudo -u jenkins sh
      jenkins@$ wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
      jenkins@$ bash Miniconda3-latest-Linux-x86_64.sh
      

      由于 Jenkins 运行 sh 而不是 bash,因此我将 conda 路径添加到 /etc/profile

      export PATH="/var/lib/jenkins/miniconda3/bin:$PATH"
      

      然后您可以在 Jenkinsfile 中创建和删除 conda 环境。下面是为每个构建创建新环境的示例:

      pipeline {
          agent any
          stages {
              stage('Unit tests') {
                  steps {
                  sh '''
                      conda create --yes -n ${BUILD_TAG} python
                      source activate ${BUILD_TAG}
                      // example of unit test with nose2
                      pip install nose2
                      nose2
                  '''
                  }
              }
          }
          post {
              always {
                  sh 'conda remove --yes -n ${BUILD_TAG} --all'
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        我也有同样的问题。正如我所看到的 - 你的项目名为“运行测试”。所以,这个名字包含空格。这对我来说是个问题。我刚刚重命名了项目,比如 RunTests - 并且 venv 现在正在工作!注意 - jenkins 询问您有关确认重命名项目的问题。

        【讨论】:

        • 这解决了我的问题...现在是时候来一个大的 WTF 了。
        【解决方案5】:

        venv-python 插件在不同操作系统环境下存在一些问题。

        这是我手动调用 python 方法的方法。不是最佳做法,但它有效。

        // Put this stage on top of pipeline
        stage('Prepare venv') {
            steps {
                script {
                    if (isUnix()) {
                        env.ISUNIX = "TRUE" // cache isUnix() function to prevent blueocean show too many duplicate step (Checks if running on a Unix-like node) in python function below
                        sh 'python3 -m venv pyenv'
                        PYTHON_PATH =  sh(script: 'echo ${WORKSPACE}/pyenv/bin/', returnStdout: true).trim()                        
                    }
                    else {
                        env.ISUNIX = "FALSE"
                        powershell(script:"py -3 -m venv pyenv") // windows not allow call python3.exe with venv. https://github.com/msys2/MINGW-packages/issues/5001
                        PYTHON_PATH =  sh(script: 'echo ${WORKSPACE}/pyenv/Scripts/', returnStdout: true).trim()
                    }
        
                    try  {
                        // Sometime agent with older pip version can cause error due to non compatible plugin.
                        Python("-m pip install --upgrade pip")
                    } 
                    catch (ignore) { } // update pip always return false when already lastest version
                    // After this you can call Python() anywhere from pipeline
                    Python("-m pip install -r requirements.txt")
                }                
            }
        }
        
        // Several plugins like WithPyenv is not working perfectly accross platform when using Virtual Env.
        // Put this method outside pipeline
        def Python(String command) {
            if (env.ISUNIX == "TRUE") {
                sh script:"source pyenv/bin/activate && python ${command}", label: "python ${command}"
            }
            else {
                powershell script:"pyenv\\Scripts\\Activate.ps1 ; python ${command}", label: "python ${command}"
            }
        }

        【讨论】:

          【解决方案6】:

          启动 virtualenv 后,尝试将 pip 作为模块运行:

          python -m pip install ...
          

          python -m pippip

          • python -m pip:执行 python 解释器二进制文件,从站点包目录中读取模块 pip.py
          • pip:执行pip 二进制/从$PATH 提取的脚本

          我发现使用python -m pip解决了大部分遇到的pip权限问题。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-02-14
            • 2014-02-01
            • 2021-03-04
            • 2012-11-14
            • 1970-01-01
            相关资源
            最近更新 更多