Come assemblare progetti in Jenkins quando servono molti ambienti diversi

Come assemblare progetti in Jenkins quando servono molti ambienti diversi

Su Habr ci sono molti articoli su Jenkins, ma pochi descrivono un esempio pratico di funzionamento di Jenkins e degli agenti Docker. Tutti gli strumenti di build più popolari come Drone.io, Bitbucket Pipeline, GitLab, GitHub actions e altri possono compilarli all'interno di contenitori. Ma come si comporta Jenkins?

Oggi c'è una soluzione al problema: Jenkins 2 sa lavorare benissimo con gli agenti Docker. In questo articolo voglio condividere la mia esperienza e mostrarti come puoi farlo tu stesso.

Perché mi sono occupato di risolvere questo problema?

Poiché nella nostra azienda Citronium utilizziamo molteplici tecnologie, la macchina di build deve ospitare diverse versioni di Node.JS, Gradle, Ruby, JDK e altro. Ma spesso non si possono evitare conflitti di versione. Sì, avresti ragione a dire che esistono diversi gestori di versioni come nvm, rvm, ma non tutto è così semplice con loro e queste soluzioni presentano problemi:

  • un grande volume di runtime che gli sviluppatori dimenticano di pulire;
  • ci sono conflitti tra diverse versioni dello stesso runtime;
  • ogni sviluppatore ha bisogno di un diverso insieme di componenti.

Ci sono altri problemi, ma preferisco raccontarti della soluzione.

Jenkins in Docker

Poiché Docker si è ormai ben radicato nel campo dello sviluppo, quasi tutto può essere eseguito utilizzando Docker. La mia soluzione è che Jenkins fosse in Docker e potesse eseguire altri contenitori Docker. Questa questione è stata sollevata per la prima volta nel 2013 in un articolo "Docker può ora essere eseguito all'interno di Docker«.

In breve, è necessario installare Docker stesso nel contenitore di lavoro e montare il file /var/run/docker.sock.

Ecco un esempio di Dockerfile che è stato creato per 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

Così abbiamo ottenuto un contenitore Docker che può eseguire comandi Docker sulla macchina host.

Configurazione della build

Non molto tempo fa Jenkins ha ricevuto la possibilità di descrivere le proprie regole utilizzando Pipeline una sintassi che consente di modificare facilmente lo script di build e di conservarlo nel repository.

Quindi, posizioniamo un Dockerfile speciale all'interno del repository, che conterrà tutte le librerie necessarie per la build. In questo modo, lo sviluppatore può preparare un ambiente riproducibile senza dover chiedere a OPS di installare una versione specifica di Node.JS sull'host.

FROM node:12.10.0-alpine

RUN npm install yarn -g

Questa immagine di build è adatta per la maggior parte delle applicazioni Node.JS. E se, ad esempio, avessi bisogno di un'immagine per un progetto JVM con incluso un scanner Sonar? Puoi scegliere autonomamente i componenti necessari per la build.

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/

Abbiamo descritto l'ambiente di build, ma che c'entra Jenkins? Gli agenti di Jenkins possono lavorare con queste immagini Docker e condurre il processo di build al loro interno.

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

Direttiva agent utilizza la proprietà docker, dove puoi specificare:

  • il nome del container di build secondo la tua politica di denominazione;
  • gli argomenti necessari per avviare il container di build, dove nel nostro caso montiamo la directory corrente come directory all'interno del container.

E già nei passaggi di build specifichiamo quali comandi eseguire all'interno dell'agente Docker di build. Può essere qualsiasi cosa, in questo modo effettuo anche il deploy delle applicazioni utilizzando Ansible.

Di seguito voglio mostrare un Jenkinsfile generale che può costruire una semplice applicazione 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()
        }
    }

}

Cosa ne è uscito?

Grazie a questo approccio abbiamo risolto i seguenti problemi:

  • il tempo di configurazione dell'ambiente di build si riduce a 10-15 minuti per progetto;
  • un ambiente di build dell'applicazione completamente ripetibile, poiché può essere costruito anche sul computer locale;
  • nessun problema con conflitti tra diverse versioni degli strumenti di build;
  • workspace sempre pulito, che non si intasa.

La soluzione in sé è semplice e ovvia e offre solo vantaggi. Sì, la soglia di ingresso è leggermente aumentata rispetto ai comandi semplici per le build, ma ora c'è la garanzia che verrà sempre eseguita e lo sviluppatore può scegliere tutto ciò che è necessario per il suo processo di build.

Puoi anche utilizzare l'immagine che ho creato. Jenkins + Docker. Tutti i sorgenti sono aperti e disponibili su rmuhamedgaliev/jenkins_docker.

Durante la scrittura dell'articolo, è emersa una discussione sull'uso degli agenti su server remoti, per non sovraccaricare il nodo master tramite il plugin docker-plugin. Ma di questo parlerò in futuro.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster