Cum să construiești proiecte în Jenkins, dacă ai nevoie de multe medii diferite

Cum să construiești proiecte în Jenkins, dacă ai nevoie de multe medii diferite

Pe Habr există multe articole despre Jenkins, dar puține dintre ele descriu un exemplu de utilizare a agenților Docker pentru Jenkins. Toate instrumentele populare de construire a proiectelor, precum Drone.io, Bitbucket Pipeline, GitLab, GitHub actions și altele, pot să compileze totul în containere. Dar cum rămâne cu Jenkins?

În prezent, există o soluție pentru această problemă: Jenkins 2 știe să lucreze excelent cu agenți Docker. În acest articol vreau să împărtășesc experiența mea și să arăt cum puteți face acest lucru singuri.

De ce m-am apucat de soluționarea acestei probleme?

Având în vedere că, în compania Citronium , folosim numeroase tehnologii diferite, pe mașina de construire trebuie să avem diverse versiuni de Node.JS, Gradle, Ruby, JDK și altele. Totuși, conflictele de versiuni nu pot fi evitate. Da, veți avea dreptate dacă spuneți că există diferite manageri de versiuni, precum nvm, rvm, dar lucrurile nu sunt chiar atât de simple cu ei și aceste soluții au probleme:

  • există un volum mare de runtime-uri pe care dezvoltatorii uită să le curețe;
  • există conflicte între diferite versiuni ale acelorași runtime-uri;
  • fiecare dezvoltator are nevoie de un set diferit de componente.

Există și alte probleme, dar mai bine să vă povestesc despre soluție.

Jenkins în Docker

Având în vedere că Docker este deja bine consacrat în domeniul dezvoltării, aproape totul poate fi pornit prin intermediul Docker. Soluția mea este ca Jenkins să fie în Docker și să poată rula alte containere Docker. Această întrebare a fost abordată încă din 2013 într-un articol intitulat „Docker can now run within Docker«.

Pe scurt, este necesar să instalați Docker în containerul de lucru și să montați fișierul /var/run/docker.sock.

Iată un exemplu de Dockerfile pentru 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

Astfel, am obținut un container Docker care poate executa comenzi Docker pe mașina gazdă.

Configurarea construirii

Nu cu mult timp în urmă, Jenkins a primit posibilitatea de a-și descrie regulile folosind Pipeline sintaxei, ceea ce permite modificarea destul de simplă a scriptului de construire și stocarea acestuia în repository.

Așa că haideți să plasăm în repository un Dockerfile special, care va conține toate bibliotecile necesare pentru construcție. Astfel, dezvoltatorul poate pregăti un mediu replicabil și nu va trebui să ceară OPS-ului să instaleze o anumită versiune de Node.JS pe gazdă.

FROM node:12.10.0-alpine

RUN npm install yarn -g

Această imagine de construire este potrivită pentru majoritatea aplicațiilor Node.JS. Și dacă, de exemplu, aveți nevoie de o imagine pentru un proiect JVM cu scannerul Sonar inclus? Sunteți liber să alegeți componentele necesare pentru construcție.

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/

Am descris mediul de construcție, dar ce legătură are Jenkins? Agentele Jenkins pot lucra cu astfel de imagini Docker și pot efectua construcții în interior.

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"
    }
}

Directiva agent folosește proprietate docker, unde puteți specifica:

  • numele containerului de construcție conform politicii dumneavoastră de denumire;
  • argumentele necesare pentru a rula containerul de construcție, unde în cazul nostru montăm directorul curent ca director în interiorul containerului.

Și deja în pașii de construcție specifice care comenzi să fie executate în interiorul agentului Docker de construcție. Poate fi orice, astfel îl folosesc și pentru a rula deploy-ul aplicațiilor cu ajutorul ansible.

Mai jos vreau să arăt un Jenkinsfile general, care poate construi o aplicație simplă Node.JS.

def DOCKER_IMAGE_BRANCH = ""
def GIT_COMMIT_HASH = ""

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

    agent any

    stages {

        stage("Pregătește imaginea de construcție") {
            steps {
                sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
            }
        }

        stage("Construiește proiectul") {
            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()
        }
    }

}

Ce a rezultat?

Datorită acestei metode, am rezolvat următoarele probleme:

  • timpul de configurare a mediu de construcție se reduce la 10 — 15 minute pe proiect;
  • un mediu complet replicabil pentru construcția aplicației, deoarece se poate construi și pe computerul local;
  • fără probleme cu conflictele între diferitele versiuni ale uneltelor de construcție;
  • întotdeauna un spațiu de lucru curat, care nu se aglomerează.

În sine, soluția este simplă și evidentă și oferă doar avantaje. Da, pragul de intrare a crescut puțin comparativ cu comenzile simple pentru construcții, dar acum există garanția că va fi întotdeauna construit și dezvoltatorul poate alege tot ce este necesar pentru procesul său de construcție.

De asemenea, puteți folosi imaginea pe care am construit-o Jenkins + Docker. Toate sursele sunt deschise și se află pe rmuhamedgaliev\/jenkins_docker.

În timpul redactării articolului a apărut o discuție despre utilizarea agenților pe servere externe, pentru a nu încărca nodul principal prin pluginul docker-plugin. Dar despre asta voi povesti în viitor.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster