Як збирати проекти в Jenkins, якщо потрібно багато різних оточень

Як збирати проекти в Jenkins, якщо потрібно багато різних оточень

На Хабре багато статей про Jenkins, але мало де описується приклад роботи Jenkins та докер агентів. Усі популярні інструменти складання проектів типу Drone.io, Bitbucket Pipeline, GitLab, GitHub actions та інші, можуть збирати все у контейнерах. Але як же Jenkins?

На сьогоднішній день є вирішення проблеми: Jenkins 2 чудово вміє працювати з Docker агентами. У статті хочу поділитися досвідом і показати, як ви можете це зробити самі.

Чому я зайнявся вирішенням цієї проблеми?

Тому що ми в компанії Citronium використовуємо безліч різних технологій, то на складальній машині доводиться тримати різні версії Node.JS, Gradle, Ruby, JDK та інших. Але найчастіше конфліктів версій не уникнути. Так, ви будете праві якщо скажете, що є різні менеджери версій типу nvm, rvm, але не все так гладко з ними і ці рішення мають проблеми:

  • великий обсяг рантаймів, який розробники забувають чистити;
  • є конфлікти між різними версіями одних рантаймів;
  • кожному розробнику потрібний різний набір компонентів.

Є й інші проблеми, але давайте краще розповім про рішення.

Jenkins в Docker

Так як зараз Docker вже добре укоренився у сфері розробки, то майже все можна запустити за допомогою Docker. Моє ж рішення в тому, щоб Jenkins був у Docker та міг запускати інші Docker контейнери. Цим питанням стали задаватися ще 2013 року у статті «Docker може зараз йти з Docker".

Якщо коротко необхідно в робочий контейнер встановити сам Docker і вмонтувати файл /var/run/docker.sock.

Ось приклад Dockerfile, який вийшов для Jenkins.

FROM jenkins/jenkins:lts

USER root

RUN apt-get update && 

apt-get -y install apt-transport-https 
     ca-certificates 
     curl 
     gnupg2 
     git 
     software-properties-common && 
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && 
add-apt-repository 
   "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") 
   $(lsb_release -cs) 
   stable" && 
apt-get update && 
apt-get -y install docker-ce && 
usermod -aG docker jenkins

RUN curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose 

RUN apt-get clean autoclean && apt-get autoremove —yes && rm -rf /var/lib/{apt,dpkg,cache,log}/

USER jenkins

Таким чином ми отримали Docker контейнер, який може виконувати Docker команди на хостовій машині.

Налаштування складання

Нещодавно Jenkins отримав можливість описувати свої правила за допомогою Трубопровід синтаксису, що дозволяє досить просто змінювати скрипт складання та зберігати його в репозиторії.

Так давайте ж ми помістимо в самий репозиторій спеціальний Dockerfile, який міститиме в собі всі необхідні для складання бібліотеки. Таким чином, сам розробник може підготувати повторюване середовище і не потрібно буде OPS просити поставити на хост певну версію Node.JS.

FROM node:12.10.0-alpine

RUN npm install yarn -g

Такий складальний образ підходить для більшості програм Node.JS. А якщо вам, наприклад, потрібен образ для JVM проекту із включеним усередину Sonar сканером? Ви самі вільні вибирати потрібні для збирання компоненти.

FROM adoptopenjdk/openjdk12:latest

RUN apt update 
    && apt install -y 
        bash unzip wget

RUN mkdir -p /usr/local/sonarscanner 
    && cd /usr/local/sonarscanner 
    && wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.3.0.1492-linux.zip 
    && unzip sonar-scanner-cli-3.3.0.1492-linux.zip 
    && mv sonar-scanner-3.3.0.1492-linux/* ./ 
    && rm sonar-scanner-cli-3.3.0.1492-linux.zip 
    && rm -rf sonar-scanner-3.3.0.1492-linux 
    && ln -s /usr/local/sonarscanner/bin/sonar-scanner /usr/local/bin/sonar-scanner

ENV PATH $PATH:/usr/local/sonarscanner/bin/
ENV SONAR_RUNNER_HOME /usr/local/sonarscanner/bin/

Ми описали складальне оточення, але до чого тут Jenkins? А Jenkins агенти вміють працювати з такими образами Docker і проводити збірку всередині.

stage("Build project") {
    agent {
        docker {
            image "project-build:${DOCKER_IMAGE_BRANCH}"
            args "-v ${PWD}:/usr/src/app -w /usr/src/app"
            reuseNode true
            label "build-image"
        }
    }
    steps {
        sh "yarn"
        sh "yarn build"
    }
}

Директива agent використовує властивість docker, де ви можете вказати:

  • ім'я складального контейнера відповідно до вашої політики неймінгу;
  • аргументи необхідні для запуску конвеєра, де в нашому випадку ми монтуємо поточну директорію як директорію всередині контейнера.

А вже в кроках збирання ми вказуємо, які команди виконати всередині складального агента Docker. Це може все що завгодно, таким чином я також запускаю деплой додатків за допомогою ansible.

Нижче я хочу показати загальний Jenkinsfile, який може зібрати простий Node.JS додаток.

def DOCKER_IMAGE_BRANCH = ""
def GIT_COMMIT_HASH = ""

pipeline { 
    options {
        buildDiscarder(
            logRotator(
                artifactDaysToKeepStr: "",
                artifactNumToKeepStr: "",
                daysToKeepStr: "",
                numToKeepStr: "10"
            )
        )
        disableConcurrentBuilds()
    }

    agent any

    stages {

        stage("Prepare build image") {
            steps {
                sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
            }
        }

        stage("Build project") {
            agent {
                docker {
                    image "project-build:${DOCKER_IMAGE_BRANCH}"
                    args "-v ${PWD}:/usr/src/app -w /usr/src/app"
                    reuseNode true
                    label "build-image"
                }
            }
            steps {
                sh "yarn"
                sh "yarn build"
            }
        }

    post {
        always {
            step([$class: "WsCleanup"])
            cleanWs()
        }
    }

}

Що ж сталося?

Завдяки такому способу ми вирішили такі проблеми:

  • час зміни складання оточення зводиться до 10 - 15 хвилин на проект;
  • повністю повторюване оточення збірки програми, оскільки можна так збирати і локальному комп'ютері;
  • немає проблем із конфліктами різних версій складальних інструментів;
  • завжди чистий воркспейс, який не забивається.

Саме собою рішення просте і очевидне і дозволяє отримати одні плюси. Так, поріг входу трохи піднявся в порівнянні з простими командами для збірок, зате тепер є гарантія, що збиратиметься завжди і розробник сам може вибрати все, що необхідно для його процесу складання.

Також ви можете скористатися зібраним мною чином Jenkins + Docker. Усі вихідники відкриті і лежать на rmuhamedgaliev/jenkins_docker.

Під час написання статті з'явилася дискусія щодо використання агентів на віддалених серверах, щоб не вантажити майстер ноду за допомогою плагіна docker-plugin. Але про це я розповім у майбутньому.

Джерело: habr.com

Додати коментар або відгук