如何使用Docker和Pipelines缓存本地Maven存储库?

时间:2019-03-11 14:50:52

标签: maven docker jenkins jenkins-pipeline

我想在Docker容器中运行我的Maven构建。我不想在每个版本中都上传所有依赖关系,所以我尝试安装Using Docker with Pipeline中记录的主机的本地Maven存储库:

  

为容器缓存数据

     

[...]

     

Pipeline支持添加传递给Docker的自定义参数,允许用户指定要安装的自定义Docker卷,该卷可用于在管道运行之间在代理上缓存数据。下面的示例将利用Maven容器在管道运行之间缓存〜/ .m2,从而避免为管道的后续运行重新下载依赖项。

pipeline {
    agent {
        docker {
            image 'maven:3-alpine'
            args '-v $HOME/.m2:/root/.m2'
        }
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn -B'
            }
        }
    }
}

代码

pipeline {
    agent {
        docker { 
            image 'maven:3-alpine' 
            args '-v /home/jenkins/.m2:/root/.m2'
        }    
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn -B clean verify'
            }
        }
    }   
}

登录

Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on jenkins-docker in /home/jenkins/workspace/Test/Docker Test@2
[Pipeline] {
[Pipeline] sh
+ docker inspect -f . maven:3-alpine
.
[Pipeline] withDockerContainer
jenkins-docker does not seem to be running inside a container
$ docker run -t -d -u 1000:1000 -v /home/jenkins/.m2:/root/.m2 -w "/home/jenkins/workspace/Test/Docker Test@2" -v "/home/jenkins/workspace/Test/Docker Test@2:/home/jenkins/workspace/Test/Docker Test@2:rw,z" -v "/home/jenkins/workspace/Test/Docker Test@2@tmp:/home/jenkins/workspace/Test/Docker Test@2@tmp:rw,z" -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** maven:3-alpine cat

[...]

[DEBUG] Reading global settings from /usr/share/maven/conf/settings.xml
[DEBUG] Reading user settings from ?/.m2/settings.xml
[DEBUG] Reading global toolchains from /usr/share/maven/conf/toolchains.xml
[DEBUG] Reading user toolchains from ?/.m2/toolchains.xml
[DEBUG] Using local repository at /home/jenkins/workspace/Test/Docker Test@2/?/.m2/repository
[DEBUG] Using manager EnhancedLocalRepositoryManager with priority 10.0 for /home/jenkins/workspace/Test/Docker Test@2/?/.m2/repository

问题

构建~/m2目录为空后,未添加任何文件/目录。所有文件都添加到/home/jenkins/workspace/Test/Docker Test@2/?/.m2下( Test 是文件夹的名称, Docker Test 是竖线的名称)。

问题在于,该目录仅用于该特定管道,而不用于其他管道,因此我无法与其他管道/作业共享本地Maven存储库。

我的settings.xml也未使用,因为它保存在~/m2下。

是否存在使用Docker与不同管道共享本地Maven存储库和Maven设置的解决方案?

3 个答案:

答案 0 :(得分:3)

我找到了一种解决方法,请参见Local settings.xml not picked up by Jenkins agent

  

该问题与jenkins用于运行容器的-u uid:gid有关。您可能知道正在运行的映像仅创建了一个用户root,因此当詹金斯传递其自己的uid和gid时,该用户将没有条目,因此也不会为此声明$HOME。 / p>      

如果只希望独立于用户运行构建,则可以将以下内容用作代理:

agent {
        docker {
            image 'maven:3-alpine'
            args '-v $HOME/.m2:/root/.m2:z -u root'
            reuseNode true
        }
}
     

一些注意事项:

     
      
  1. 如果您注意到我正在使用标志z使用的卷,因为我将使用root进行构建,则需要告诉docker该卷将在另一个容器之间共享,然后防止拒绝访问我的jenkins容器(使用用户jenkins而非root运行)
  2.   
  3. 我告诉jenkins重用Node,因此使用同一映像的任何其他阶段都将在同一容器上执行(这只是为了加快配置时间)
  4.   

登录

[DEBUG] Reading global settings from /usr/share/maven/conf/settings.xml
[DEBUG] Reading user settings from /root/.m2/settings.xml
[DEBUG] Reading global toolchains from /usr/share/maven/conf/toolchains.xml
[DEBUG] Reading user toolchains from /root/.m2/toolchains.xml
[DEBUG] Using local repository at /root/.m2/repository
[DEBUG] Using manager EnhancedLocalRepositoryManager with priority 10.0 for /root/.m2/repository

很遗憾,本地存储库/home/jenkins/.m2中的文件现在由用户root而非用户jenkins拥有。那可能导致其他问题。

答案 1 :(得分:0)

获取Jenkins管道以将Docker容器用于Jenkins Agents,以及用于共享Maven本地存储库的构建,因为要解决两个问题,因此很棘手:共享本地存储库文件,并确保文件具有可用权限

我创建了一个Docker Volume来保存共享文件:

docker volume create maven-cache

然后告诉Jenkins通过让其--mount命令使用docker run选项,将Docker Volume安装在每个Agent的适当位置。这使Docker卷可用...但是由root拥有,而不是由运行代理的jenkins用户拥有。

解决该权限问题的一个复杂方法是​​,詹金斯将使用Jenkins UID docker run来映像您的图像,而您不知道该UID是什么。与I've noted elsewhere一样,您可以使用一些shell脚本魔术和RUN命令来解决此问题,以为您的代理程序映像设置jenkins用户名(和docker组名)。 / p>

您可以通过以下方法解决权限问题:将sudo添加到您的Docker映像中,并配置该映像以允许jenkins用户运行sudo命令而无需输入密码。然后,早期的Jenkins流水线步骤可以使用sudo创建一个合适的目录,以在共享安装中保存本地存储库,并将该目录的所有者更改为jenkins

最后,您可以设置一个供Jenkins Agent使用的Maven设置文件,它告诉Maven使用共享的本地存储库。

我的Jenkinsfile是这样的:

pipeline {
    agent {
        dockerfile {
            filename 'Dockerfile.jenkinsAgent'
            additionalBuildArgs  '--build-arg JENKINSUID=`id -u jenkins` --build-arg JENKINSGID=`id -g jenkins` --build-arg DOCKERGID=`stat -c %g /var/run/docker.sock`'
            args '-v /var/run/docker.sock:/var/run/docker.sock --mount type=volume,source=maven-cache,destination=/var/cache/maven -u jenkins:docker'
       }
    }
    stages {
...
        stage('Prepare') {
            steps {
                sh '[ -d /var/cache/maven/jenkins ] || sudo -n mkdir /var/cache/maven/jenkins'
                sh 'sudo -n chown jenkins /var/cache/maven/jenkins'
...
                sh 'mvn -B -s maven-jenkins-settings.xml clean'
            }
        }

随后使用Maven的步骤也说mvn -B -s maven-jenkins-settings.xml ...

我的Dockerfile.jenkinsAgent是这样的:

FROM debian:stretch-backports
ARG JENKINSUID
ARG JENKINSGID
ARG DOCKERGID

# Add Docker CE
RUN apt-get -y update && \
 apt-get -y install \
   apt-transport-https \
   ca-certificates \
   curl \
   gnupg \
   lsb-release \
   software-properties-common

RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
RUN add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"

RUN apt-get -y update && \
 apt-get -y install \
   docker-ce \
   docker-ce-cli \
   containerd.io

# Add the build and test tools and libraries
RUN apt-get -y install \
   ... \
   maven \
   sudo \
   ...

# Set up the named users and groups
# Installing docker-ce will already have added a "docker" group,
# but perhaps with the wrong ID.
RUN groupadd -g ${JENKINSGID} jenkins
RUN groupmod -g ${DOCKERGID} docker
RUN useradd -c "Jenkins user" -g ${JENKINSGID} -G ${DOCKERGID} -M -N -u ${JENKINSUID} jenkins
# Allow the build agent to run root commands if it *really* wants to:
RUN echo "jenkins ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers

(如果您的Jenkins管道本身不运行Docker命令,则可以删除用于安装Docker的RUN命令,但随后您必须groupadd docker组,而不是groupmod

Jenkins代理(maven-jenkins-settings.xml)的Maven设置文件如下:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd">
    <localRepository>/var/cache/maven/jenkins</localRepository>
    <interactiveMode>false</interactiveMode>
</settings>

答案 2 :(得分:0)

  

Maven需要用户主页才能将工件下载到   在图像中不存在,需要额外的user.home Java属性   被设置。

-Duser.home=/path/to/home/

通过此链接:https://github.com/carlossg/docker-maven#running-as-non-root-not-supported-on-windows

我在声明性Jenkins管道中通过以下配置解决了Jenkins CI上共享Maven缓存的问题。

agent {
  docker {
    image 'amazoncorretto:8'
    label 'docker'
    args '-v $HOME/tools:$HOME/tools \
          -v $HOME/.m2/:$HOME/.m2 \
          -v /etc/passwd:/etc/passwd:ro \
          -e MAVEN_CONFIG=$HOME/.m2 \
         '
  }
}