Як збіраць праекты ў 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

Дадаць каментар