Come compilare progetti in Jenkins, se sono necessari molti ambienti diversi

Come compilare progetti in Jenkins, se sono necessari molti ambienti diversi

Su Habr ci sono molti articoli su Jenkins, ma pochi descrivono esempi di utilizzo di Jenkins e agenti Docker. Tutti gli strumenti di build popolari come Drone.io, Bitbucket Pipeline, GitLab, GitHub actions e altri, possono costruire tutto in contenitori. Ma come sta messo Jenkins?

Al giorno d'oggi esiste una soluzione al problema: Jenkins 2 sa lavorare magnificamente con gli agenti Docker. In questo articolo voglio condividere la mia esperienza e mostrare come puoi farlo tu stesso.

Perché mi sono occupato di risolvere questo problema?

Poiché nella nostra azienda Citronium utilizziamo molte tecnologie diverse, sulla macchina di build è necessario mantenere diverse versioni di Node.JS, Gradle, Ruby, JDK e altro. Ma spesso i conflitti di versione sono inevitabili. Sì, avrai ragione se dici che ci sono vari gestori di versioni come nvm, rvm, ma non tutto funziona senza intoppi con loro e queste soluzioni hanno problemi:

  • grandi quantità di runtime che gli sviluppatori dimenticano di pulire;
  • ci sono conflitti tra diverse versioni dello stesso runtime;
  • ogni sviluppatore ha bisogno di un set diverso di componenti.

Ci sono anche altri problemi, ma lasciami raccontare la soluzione.

Jenkins in Docker

Poiché Docker è ormai ben radicato nel campo dello sviluppo, quasi tutto può essere eseguito tramite Docker. La mia soluzione è che Jenkins sia in Docker e possa avviare altri contenitori Docker. Questa questione è stata sollevata già nel 2013 in un articolo ‘Docker can now run within Docker«.

In sintesi, è necessario installare Docker all'interno del contenitore di lavoro e montare il file /var/run/docker.sock.

Ecco un esempio di Dockerfile 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

In questo modo 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 tramite Pipeline sintassi, che consente di modificare abbastanza facilmente lo script di build e di archiviarlo nel repository.

Quindi, mettiamo nel repository stesso un apposito Dockerfile, che conterrà tutte le librerie necessarie per la build. In questo modo, lo sviluppatore può preparare un ambiente ripetibile 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, avete bisogno di un'immagine per un progetto JVM con all'interno Sonar scanner attivato? Potete scegliere i componenti necessari per la build come preferite.

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 tali immagini Docker e effettuare la build all'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 agente usa la proprietà docker, dove è possibile specificare:

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

E già nei passi di build specifichiamo quali comandi eseguire all'interno dell'agente Docker di build. Può essere qualsiasi cosa, in questo modo eseguo 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("Prepara l'immagine di build") {
            steps {
                sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
            }
        }

        stage("Costruisci il progetto") {
            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 è uscito?

Grazie a questo metodo 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é si può costruire anche sul computer locale;
  • nessun problema con i conflitti tra versioni diverse degli strumenti di build;
  • workspace sempre pulito, che non si riempie.

Di per sé, la soluzione è semplice e ovvia e consente di ottenere solo vantaggi. Sì, la soglia di ingresso è leggermente aumentata rispetto ai semplici comandi di build, ma ora c'è la garanzia che verrà sempre costruito e lo sviluppatore può scegliere tutto ciò di cui ha bisogno per il suo processo di build.

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

Durante la scrittura dell'articolo è emersa una discussione sull'uso di agenti su server remoti, per non sovraccaricare il nodo principale 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