Как кэшировать локальный репозиторий Maven с помощью Docker с конвейерами? - PullRequest
4 голосов
/ 11 марта 2019

Я хочу запустить свои сборки Maven в контейнере Docker.Я не хочу загружать все зависимости с каждой сборкой, поэтому я попытался смонтировать локальный репозиторий Maven хоста, как описано в Использование Docker с конвейером :

Кэширование данныхдля контейнеров

[...]

Конвейер поддерживает добавление пользовательских аргументов, которые передаются в Docker, позволяя пользователям указывать настраиваемые тома Docker для монтирования, которые можно использовать для кэширования данныхна агента между трассами трубопровода.В следующем примере будет кэшироваться ~ / .m2 между запусками конвейера с использованием контейнера maven, что исключает необходимость повторной загрузки зависимостей для последующих запусков конвейера.

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

Code

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.

Есть ли какое-либо решение для совместного использования локального хранилища Maven и настроек Maven с различными конвейерами с помощью Docker?

Ответы [ 3 ]

3 голосов
/ 11 марта 2019

Я нашел обходной путь, см. Локальные settings.xml, не найденные агентом Jenkins :

Проблема связана с -u uid:gid, который jenkins использует для запуска контейнера. Как вы, возможно, знаете, на образе, который вы используете, создан только пользователь root, поэтому, когда jenkins передает свои собственные uid и gid, запись для пользователя отсутствует и, следовательно, $HOME не объявлено для него.

Если вы хотите запускать сборку независимо от пользователя, вы можете использовать в качестве агента следующее:

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. Я говорю jenkins повторно использовать узел, поэтому любой другой этап, использующий то же изображение, будет выполняться в том же контейнере (это просто для ускорения времени подготовки)

Вход

[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. Это может вызвать другие проблемы.

0 голосов
/ 10 апреля 2019

Получение конвейера Jenkins для использования контейнеров Docker для агентов Jenkins и для сборок, совместно использующих локальный репозиторий Maven, является непростым делом, поскольку необходимо решить две проблемы: предоставить общий доступ к файлам локального репозитория и убедиться, что файлы имеют доступные разрешения .

Я создал Docker Volume для хранения общих файлов:

docker volume create maven-cache

Затем велел Дженкинсу смонтировать этот том Docker в подходящем месте для каждого агента, передав ему параметр --mount для своей команды docker run. Это делает том Docker доступным ... но принадлежит root, а не jenkins пользователю, работающему с Агентом.

Сложность в устранении этой проблемы с разрешениями заключается в том, что Jenkins docker run изменит ваше изображение, используя UID Jenkins, и вы не можете знать, каким будет этот UID. Как и Я уже отмечал в другом месте , вы можете обойти это, используя магию сценариев оболочки и команды RUN, чтобы установить jenkins имя пользователя (и docker имя группы, если необходимо) для вашего образа агента .

Вы можете решить проблему с разрешениями, добавив sudo к своему образу Docker и сконфигурировав образ, чтобы пользователь jenkins мог запускать команды sudo без пароля. Затем на раннем этапе конвейера 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-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, вы можете удалить команды RUN для установки Docker, но тогда вам потребуется groupadd группа docker вместо groupmod)

И файл настроек Maven для агента Jenkins (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>
0 голосов
/ 12 марта 2019

Вы можете видеть мой ответ связанный, но с использованием конфигурации Gradle.

Как вы сказали, в моем базовом образе Jenkins запускает контейнер Docker с пользователем 1002, и пользователь не определен. Вы должны настроить переменную Maven user.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 в секретный файл, чтобы использовал «принцип наименьшего риска», чтобы ограничить доступ к учетным данным в конвейере Дженкинса . Также мы настраиваем личные учетные данные, и именно так мы настраиваем, например, учетные данные 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"
                        }
                    }
                }

Кажется, это также можно использовать в декларативных конвейерах , но я сам не проверял.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...