如何使用jenkins pipline步骤在Docker映像中进行pip安装?

时间:2019-02-21 17:13:35

标签: docker jenkins jenkins-pipeline

我有这个 Dockerfile

FROM python:3.7

CMD ["/bin/bash"]

和此 Jenkinsfile

pipeline {
agent {
    dockerfile {
        filename 'Dockerfile'
    }
}
stages {
    stage('Install') {
        steps {
            sh 'pip install --upgrade pip'
        }
    }
}

这会导致以下错误:

The directory '/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting pip
  Downloading https://files.pythonhosted.org/packages/d8/f3/413bab4ff08e1fc4828dfc59996d721917df8e8583ea85385d51125dceff/pip-19.0.3-py2.py3-none-any.whl (1.4MB)
Installing collected packages: pip
  Found existing installation: pip 19.0.2
Uninstalling pip-19.0.2:
Could not install packages due to an EnvironmentError: [Errno 13] 
Permission denied: '/usr/local/bin/pip'
Consider using the `--user` option or check the permissions.

我尝试使用--user,但没有成功。

我在docker jenkinsfile声明上使用args --user 0:0时有些运气,但这会创建root拥有的目录和文件,而用户Jenkins在下次运行时无法删除这些目录和文件。

我不想在Dockerfile上执行pip install,因为实际上Install步骤正在运行一个make文件,而不是我想在其他上下文中使用的简化。

我还看到了更改HOME environment var的建议,这似乎解决了前2条警告,提示父级目录不归当前用户所有,但不属于Errno 13部分。

5 个答案:

答案 0 :(得分:2)

正如我提到的in this comment,解决方案应该是在容器内添加适当的用户。 Jenkins将984:984用于我的机器上的uid / gid(但可能与您的不同)-登录运行Jenkins的主机并执行sudo -u jenkins id -a来检测它们),因此您需要在詹金斯应该运行的容器:

FROM python:3.7

RUN mkdir /home/jenkins
RUN groupadd -g 984 jenkins
RUN useradd -r -u 984 -g jenkins -d /home/jenkins jenkins
RUN chown jenkins:jenkins /home/jenkins
USER jenkins
WORKDIR /home/jenkins

CMD ["/bin/bash"]

当然,由于您不再是容器中的root用户,因此请创建一个虚拟环境:

$ docker run --rm -it jenkins/python /bin/bash
jenkins@d0dc87c39810:~$ python -m venv myenv
jenkins@d0dc87c39810:~$ source myenv/bin/activate
jenkins@d0dc87c39810:~$ pip install numpy

或使用--user参数:

$ docker run --rm -it jenkins/python /bin/bash
jenkins@d0dc87c39810:~$ pip install --user --upgrade pip
jenkins@d0dc87c39810:~$ pip install --user numpy


或者,您可以(但在大多数情况下不应该)以root的身份进入容器,但使用jenkins组:

$ docker run --user 0:984 ...

这样,尽管修改后的文件仍将更改所有者,但它们的组所有权仍将保持不变,因此Jenkins将能够清理文件(或者您可以自己通过

sh 'rm -f modified_file'

Jenkinsfile中。

答案 1 :(得分:0)

似乎问题与用户更相关。当您的Docker代理程序以root用户身份运行并且您阶段cmd是以Jenkins中配置的相应用户身份运行时(是否为root?)。

在您的docker文件中创建一个类似的用户,并将运行容器分配给该用户。

Dockerfile

   FROM python:3.7

   ARG Jenkins_user=XXXXXX

   RUN useradd -ms /bin/bash $Jenkins_user

   USER $Jenkins_user

   CMD ["/bin/bash"] 

编辑:此处Jenkins_user将与pip cmd在容器中运行时一起使用。要检查用户,您可以输入

sh'echo $ USER'

在安装阶段部分。然后使用确切的用户更新Dokerfile。

答案 2 :(得分:0)

我通过使用流水线环境变量动态在Docker容器中创建了一个定义的用户,从而为该问题创建了动态解决方案。您可以在我的GitHub上找到 Jenkinsfile Dockerfile 的模板。

答案 3 :(得分:0)

默认情况下,pip 尝试使用根目录。 我们需要设置HOME环境变量。

pipeline {
agent {
    dockerfile {
        filename 'Dockerfile'
    }
}

   // ******* Required change
    environment {
        HOME = "${env.WORKSPACE}"
    }
   // ******* 

stages {
    stage('Install') {
        steps {
            sh 'pip install --upgrade pip'
        }
    }
}

答案 4 :(得分:-1)

使用标准python:3.8图像

stage('Unit test') {
    steps {
        sh '''
            python -m venv .venv
            . .venv/bin/activate
            pip intall -r requirements.txt
            pytest -v
        '''
     }
}