我想在Docker容器中运行我的Maven构建。我不想在每次构建时都上传所有依赖项,所以我尝试装载主机的本地Maven存储库,如使用Docker with Pipeline:
为容器缓存数据
[...]
Pipeline支持添加传递给Docker的自定义参数,允许用户指定要挂载的自定义Docker卷,该卷可用于在Pipeline运行之间缓存代理上的数据。以下示例将使用maven容器在Pipeline运行之间缓存~/. m2,从而避免需要为Pipeline的后续运行重新下载依赖项。
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/DockerTest@2/? /.m2
下(Test是文件夹的名称,Docker Test是管道的名称)。
问题是这个目录只用于这个特定的管道,而不用于其他管道,所以我不能与不同的管道/作业共享本地Maven存储库。
还有我的设置。不使用xml
,因为它保存在~/m2
。
是否有任何解决方案可以使用 Docker 与不同的管道共享本地 Maven 存储库和 Maven 设置?
获取 Jenkins 管道以将 Docker 容器用于 Jenkins 代理,以及用于构建以共享 Maven 本地存储库非常棘手,因为有两个问题需要解决:共享本地存储库文件,以及确保文件具有可用权限。
我创建了一个Docker卷来保存共享文件:
docker volume create maven-cache
然后告诉 Jenkins 将该 Docker 卷挂载到适合每个代理的位置,方法是让它为其 Docker 运行
命令提供 --mount
选项。这使得泊坞站卷可用...但归根
用户所有,而不是运行代理的 jenkins
用户。
解决权限问题的一个复杂之处是,Jenkins将使用Jenkins UID < code > docker run 您的映像,而您无法知道该UID将是什么。正如我在其他地方提到的,您可以使用一些shell脚本和RUN命令为您的代理映像设置< code>jenkins用户名(和< code>docker组名,如果需要的话),来解决这个问题。
您可以通过将sudo
添加到Docker映像中,并配置映像以允许jenkins
user在没有密码的情况下运行
命令来解决权限问题。然后,早期的Jenkins管道步骤可以使用
sudo
在共享装载中创建一个合适的目录来存放本地存储库,并将该目录的所有者更改为
Jenkins
。
最后,您可以设置一个Maven设置文件供Jenkins代理使用,它告诉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-设置.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设置文件(< code > Maven-Jenkins-settings . XML )如下所示:
<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>
您可以看到我的答案相关,但使用Gradle配置。
正如你所说,在我的基本映像中,Jenkins 使用用户 1002 运行 Docker html" target="_blank">容器,并且没有用户定义。您必须配置 Maven 变量用户.home
才能将依赖项放在那里。可以通过将 user.home
作为管道中的环境变量包含在JAVA_OPTIONS
来执行此操作。还应包括MAVEN_CONFIG
:
environment {
JAVA_TOOL_OPTIONS = '-Duser.home=/var/maven'
SETTINGS = credentials('your-secret-file')
}
并创建一个卷来缓存依赖项:
docker {
image 'maven:3.3.9-jdk-8-alpine'
args '-v $HOME:/var/maven'
reuseNode true
}
更新:忘记告诉您,您可以将settings.xml
放在秘密文件中,以便使用“最小暴露原则”来限制Jenkins管道中的凭据暴露。此外,我们正在配置个人凭据,例如,这是我们为每个用户配置Nexus凭据的方式。查看Jenkins留档,了解如何在凭据中上传秘密文件:
sh 'mvn -s $SETTINGS -B clean verify'
UPDATE2:我没有使用声明性管道,所以我的管道看起来像:
withCredentials([
file(credentialsId: 'settings-xml', variable: 'SETTINGS')]) {
stage('Deploy') {
gitlabCommitStatus(name: 'Deploy') {
// Upload the Snapshot artefact
sh "mvn -s $SETTINGS clean verify"
}
}
}
它似乎也可以用于声明性管道,但我自己没有测试它。
我找到了一个解决方法,请参阅本地设置。Jenkins代理未拾取的xml:
这个问题与jenkins用于运行容器的-uuid:gid
有关。正如您可能知道的那样,您正在运行的映像只创建了用户root
,因此当jenkins传递自己的uid和gid时,没有用户条目,因此没有为其声明$HOME
。
如果只想独立于用户运行生成,则可以使用以下作为代理:
agent {
docker {
image 'maven:3-alpine'
args '-v $HOME/.m2:/root/.m2:z -u root'
reuseNode true
}
}
几个注意事项:
原木
[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
所有。这可能会导致其他问题。
Serenity 提供一些缓存抽象和实用功能让你更容易地使用本地缓存。 术语 本地(local) 的意思是指在本地内存中缓存项目(因此没有涉及到序列化)。 当你的应用程序在网站群(web farm) 中部署时,本地缓存可能还不够或者有时合适。我们将在 分布式缓存 章节中讨论该场景。
我正在做一个有大约200MB依赖项的项目,我希望避免由于带宽有限而导致的无用上传。 当我推我的Dockerfile(我一会儿会附上)时,我总是有一个~200MB的上传,即使我没有碰pom.xml: 这个Dockerfile应该生成一个200MB的fatJAR,包括所有依赖项,这就是为什么每次都会发生~200MB的上传。我想要实现的是构建一个包含所有依赖项的层,并“告诉”打包阶段不要将依赖项JAR包
问题内容: 我对Docker的层缓存表现出色感到惊讶,但我也想知道它如何确定是否可以使用缓存的层。 让我们以这些构建步骤为例: 例如,它如何知道可以使用缓存的层,但可以为其创建新层呢? 问题答案: 在Dockerfile最佳实践构建缓存部分中相当详尽地解释了构建缓存过程。 * 从缓存中已存在的基本映像开始,将下一条指令与从该基本映像派生的所有子映像进行比较,以查看是否其中一个是使用完全相同的指令构
我有一个Jenkins管道,我需要在其中登录到两个不同的docker存储库。我知道如何使用以下命令对一个存储库进行身份验证 但不知道如何为超过1次的回购做这件事?
问题内容: 我有一个Jenkins实例,该实例使用从requirements.txt中附带的PyPI包来构建我的项目。但是,与TravisCI构建一样,每次从头开始构建都非常耗时,并且意味着构建要花费> 4-5分钟,这比理想情况要慢得多。 我正在寻找的是一种在本地缓存下载的软件包的方法,因此,当启动具有相同依赖项的构建时,不必从PyPI获取它就可以在本地获取,而当版本发生更改时,它可以获取上游软件
dnsmasq如何配置本地的缓存时间过期后重新向指定的DNS(server=)服务器发起请求,以获取该域名的IP地址?我使用两台dnsmasq,一台为dns解析服务,提供域名解析ip,另外一台在/etc/dnsmasq.d/address.config中配置server=该机器ip(那台机器提供DNS服务)。我在提供服务的机器上将A记录改了,dig出来的还是之前的A记录。如何在dnsmasq中配置