首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用带有管道的Docker缓存本地Maven存储库?

如何使用带有管道的Docker缓存本地Maven存储库?
EN

Stack Overflow用户
提问于 2019-03-11 14:50:51
回答 4查看 14.5K关注 0票数 7

我想在Docker容器中运行我的Maven构建。我不想在每次构建中上传所有的依赖项,所以我尝试挂载主机的本地Maven存储库,如码头与管道结合使用中所记录的那样

容器的缓存数据 ..。 管道支持添加传递给Docker的自定义参数,允许用户指定要挂载的自定义Docker卷,可用于在管道运行之间缓存代理上的数据。下面的示例将使用maven容器在管道运行之间缓存~/.m2,从而避免了重新下载管道后续运行的依赖关系的需要。 管道{代理{ docker { image‘maven:3-高寒’args '-v $HOME/.m2:/root/.m2‘}}阶段{阶段(’构建‘){步骤{ sh 'mvn -B’}

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

日志

代码语言:javascript
复制
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是对线的名称)。

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

另外,我的settings.xml不被使用,因为它保存在~/m2下。

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-03-11 22:57:05

您可以看到我的回答相关,但使用的是Gradle配置。

正如您所说的,在我的基本映像中,Jenkins使用用户1002运行Docker容器,并且没有定义用户。您必须配置Maven变量user.home,以便将依赖项放在那里。您可以通过将user.home包含在JAVA_OPTIONS中作为管道中的环境变量来实现。此外,还应包括MAVEN_CONFIG

代码语言:javascript
复制
environment {
  JAVA_TOOL_OPTIONS = '-Duser.home=/var/maven'
  SETTINGS = credentials('your-secret-file')
}

并创建一个卷来缓存依赖项:

代码语言:javascript
复制
docker {
    image 'maven:3.3.9-jdk-8-alpine'
    args '-v $HOME:/var/maven'
    reuseNode true
}

UPDATE:忘记告诉您您可以将settings.xml放在一个秘密文件中,以便进行使用“最少曝光原则”限制Jenkins管道中的凭据曝光。此外,我们正在配置个人凭据,这就是我们配置的方式,例如,每个用户都配置Nexus凭据。检查如何在凭据中上载机密文件的Jenkins文档

代码语言:javascript
复制
sh 'mvn -s $SETTINGS -B clean verify'

UPDATE2:我没有使用声明式管道,所以我的管道看起来如下:

代码语言:javascript
复制
            withCredentials([
                 file(credentialsId: 'settings-xml', variable: 'SETTINGS')]) {
                    stage('Deploy') {
                        gitlabCommitStatus(name: 'Deploy') {
                            // Upload the Snapshot artefact
                            sh "mvn -s $SETTINGS clean verify"
                        }
                    }
                }

它似乎也可以在声明管道中使用,但我没有亲自测试它。

票数 3
EN

Stack Overflow用户

发布于 2019-03-11 16:14:39

我找到了一个解决办法,见当地的settings.xml没有被詹金斯探员接走

这个问题与jenkins用来运行容器的-u uid:gid有关。正如您可能知道的,您正在运行的映像只创建了用户root,所以当jenkins传递自己的uid和gid时,用户没有条目,因此也就没有为其声明的$HOME。 如果只想独立于用户运行构建,可以使用以下代理: 代理{ docker { image‘maven:3-高寒’args '-v $HOME/.m2:/root/.m2:z -u root‘reuseNode true } 几个注意事项:

  1. 如果您注意到我与标志z一起使用的卷,正如我要用根用户构建的那样,我需要告诉docker,这个卷将在另一个容器之间共享,然后防止从我的jenkins容器(与用户jenkins而不是root用户一起运行)拒绝访问。
  2. 我告诉jenkins给reuseNode,所以使用相同映像的任何其他阶段都将在同一个容器上执行(这只是为了加快准备时间)。

日志

代码语言:javascript
复制
[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拥有。这可能会引起其他问题。

票数 5
EN

Stack Overflow用户

发布于 2019-04-10 10:53:28

让Jenkins管道为Jenkins代理使用Docker容器和构建共享Maven本地存储库是很棘手的,因为有两个问题需要解决:共享本地存储库文件和确保文件具有可用权限。

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

代码语言:javascript
复制
docker volume create maven-cache

然后告诉Jenkins将Docker卷挂载到适合每个代理的位置,让它为其--mount命令提供一个docker run选项。这使得码头的容量..。但是属于root,而不是运行代理的jenkins用户。

解决该权限问题的一个复杂问题是,Jenkins将使用Jenkins来docker run您的映像,并且您无法知道该UID将是什么。作为我在其他地方注意到了,您可以使用一些shell脚本魔术并运行命令来为您的jenkins映像设置jenkins用户名(如果需要的话,还有docker组名称)。

您可以通过将sudo添加到您的Docker映像并配置映像以允许jenkins用户在没有密码的情况下运行sudo命令来解决权限问题。然后,早期的Jenkins管道步骤可以使用sudo创建一个合适的目录,在共享挂载中保存本地存储库,并将该目录的所有者更改为jenkins

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

我的Jenkinsfile是这样的

代码语言:javascript
复制
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是这样的

代码语言:javascript
复制
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的运行命令,但随后您将不得不groupadd docker组,而不是groupmod)

詹金斯代理(maven-jenkins-settings.xml)的Maven设置文件如下所示:

代码语言:javascript
复制
<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>
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55104543

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档