Saltar al contenido

¿Cómo almacenar en caché el repositorio local de Maven usando Docker con Pipelines?

Luego de de nuestra prolongada selección de información hemos podido resolver este contratiempo que presentan muchos usuarios. Te regalamos la solución y nuestro deseo es que sea de gran apoyo.

Solución:

Encontré una solución alternativa, consulte Local settings.xml no recogido por el agente de Jenkins:

El problema está relacionado con la -u uid:gid que jenkins usa para ejecutar el contenedor. Como sabrá, la imagen que está ejecutando solo tiene el usuario root creado, por lo que cuando jenkins pasa su propio uid y gid, no hay ninguna entrada para el usuario y, en consecuencia, no $HOME declarado por ello.

Si solo desea ejecutar la compilación independientemente del usuario, puede usar lo siguiente como agente:

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

Algunas notas:

  1. si notas el volumen que estoy usando con la bandera z, ya que voy a compilar con root, necesito decirle a Docker que este volumen se compartirá entre otros contenedores y luego evitar el acceso denegado desde mi contenedor jenkins (ejecutándose con el usuario jenkins no root)
  2. Le digo a jenkins que reuseNode, por lo que cualquier otra etapa que use la misma imagen se ejecutará en el mismo contenedor (es solo para acelerar el tiempo de aprovisionamiento)

Tronco

[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

Desafortunadamente, los archivos en el repositorio local. /home/jenkins/.m2 ahora son propiedad del usuario root en lugar de usuario jenkins. Eso podría causar otros problemas.

Puedes ver mi respuesta relacionada pero usando la configuración de Gradle.

Como dijiste, en mi imagen base, Jenkins ejecuta el contenedor Docker con el usuario 1002 y no hay ningún usuario definido. Tienes que configurar la variable Maven user.home para poner las dependencias allí. Puedes hacerlo incluyendo user.home en el JAVA_OPTIONS como una variable de entorno en su canalización. también MAVEN_CONFIG debe incluirse:

environment 
  JAVA_TOOL_OPTIONS = '-Duser.home=/var/maven'
  SETTINGS = credentials('your-secret-file')

y crea un volumen para almacenar en caché las dependencias:

docker 
    image 'maven:3.3.9-jdk-8-alpine'
    args '-v $HOME:/var/maven'
    reuseNode true

ACTUALIZAR: olvidé decirte que puedes poner tu settings.xml en un archivo secreto con el fin de utilizar un “principio de mínima exposición” para limitar la exposición de las credenciales en la tubería de Jenkins. También estamos configurando credenciales personales y esta es la forma en que configuramos, por ejemplo, las credenciales de Nexus por usuario. Consulte la documentación de Jenkins sobre cómo cargar su archivo secreto en sus credenciales:

sh 'mvn -s $SETTINGS -B clean verify'

ACTUALIZAR2: No estoy usando una canalización declarativa, por lo que mi canalización se ve así:

            withCredentials([
                 file(credentialsId: 'settings-xml', variable: 'SETTINGS')]) 
                    stage('Deploy') 
                        gitlabCommitStatus(name: 'Deploy') 
                            // Upload the Snapshot artefact
                            sh "mvn -s $SETTINGS clean verify"
                        
                    
                

Parece que también se puede usar en canalizaciones declarativas, pero no lo probé yo mismo.

Conseguir que una canalización de Jenkins use contenedores de Docker para los Agentes de Jenkins, y que las compilaciones compartan un repositorio local de Maven, es complicado porque hay dos problemas que resolver: compartir los archivos del repositorio local y garantizar que los archivos tengan permisos utilizables.

Creé un Docker Volume para contener los archivos compartidos:

docker volume create maven-cache

Luego le dijo a Jenkins que montara ese Volumen Docker en una ubicación adecuada para cada Agente, haciendo que le diera un --mount opción a su docker run mando. Eso hace que el volumen de Docker esté disponible … pero propiedad de root, en lugar del jenkins usuario que ejecuta el Agente.

Una complicación para solucionar ese problema de permisos es que Jenkins docker run su imagen usando el UID de Jenkins, y no puede saber cuál será ese UID. Como he señalado en otra parte, puede solucionarlo utilizando algunos comandos de ejecución mágica de script de shell y para configurar el jenkins nombre de usuario (y docker nombre de grupo, si es necesario) para su imagen de Agente.

Puede solucionar el problema de permisos agregando sudo a su imagen de Docker, y configurar la imagen para permitir el jenkins usuario para ejecutar sudo comandos sin contraseña. Entonces, un paso inicial de la canalización de Jenkins puede usar sudo para crear un directorio adecuado para contener el repositorio local, dentro del montaje compartido, y cambiar el propietario de ese directorio para que sea jenkins.

Finalmente, puede configurar un archivo de configuración de Maven para que lo use el Agente de Jenkins, que le dice a Maven que use el repositorio local compartido.

Mi Jenkinsfile es así:

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 ] 
        

Y los pasos posteriores con Maven también dicen mvn -B -s maven-jenkins-settings.xml ....

Mi Dockerfile.jenkinsAgent es así:

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

(Si su canalización de Jenkins no ejecuta los comandos de Docker, podría eliminar los comandos RUN para instalar Docker, pero luego tendría que groupadd el docker grupo, en lugar de groupmod)

Y el archivo de configuración de Maven para el agente de Jenkins (maven-jenkins-settings.xml) es así:


    /var/cache/maven/jenkins
    false

Si sostienes alguna perplejidad o forma de refinar nuestro crónica puedes añadir una nota y con gusto lo ojearemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *