Hoe projecten in Jenkins op te zetten als er veel verschillende omgevingen nodig zijn

Hoe projecten in Jenkins op te zetten als er veel verschillende omgevingen nodig zijn

Op Habr zijn er veel artikelen over Jenkins, maar zelden wordt een voorbeeld gegeven van hoe Jenkins en Docker-agenten werken. Alle populaire buildtools zoals Drone.io, Bitbucket Pipeline, GitLab, GitHub-acties en anderen kunnen alles in containers bouwen. Maar hoe zit het met Jenkins?

Tegenwoordig is er een oplossing voor het probleem: Jenkins 2 kan uitstekend overweg met Docker-agenten. In dit artikel wil ik mijn ervaring delen en laten zien hoe je dit zelf kunt doen.

Waarom ben ik begonnen met het oplossen van dit probleem?

Aangezien we in het bedrijf Citronium veel verschillende technologieën gebruiken, moet er op de buildmachine een verscheidenheid aan versies van Node.JS, Gradle, Ruby, JDK en andere worden geïnstalleerd. Maar vaak zijn er versieconflicten onvermijdelijk. Ja, je hebt gelijk als je zegt dat er verschillende versiesbeheerders zijn zoals nvm, rvm, maar het is niet altijd eenvoudig met hen en deze oplossingen hebben hun problemen:

  • een groot aantal runtimes dat ontwikkelaars vergeten schoon te maken;
  • er zijn conflicten tussen verschillende versies van dezelfde runtimes;
  • elke ontwikkelaar heeft een andere set componenten nodig.

Er zijn ook andere problemen, maar laat me je beter vertellen over de oplossing.

Jenkins in Docker

Aangezien Docker nu goed is geïntegreerd in de ontwikkelingssfeer, kan bijna alles met Docker worden uitgevoerd. Mijn oplossing is dat Jenkins in Docker draait en andere Docker-containers kan opstarten. Deze vraag werd al in 2013 gesteld in het artikel "Docker can now run within Docker«.

Kort gezegd, je moet Docker in de werkcontainer installeren en het bestand koppelen. /var/run/docker.sock.

Hier is een voorbeeld van de Dockerfile die we voor Jenkins hebben gekregen.

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

Zo hebben we een Docker-container verkregen die Docker-commando's op de hostmachine kan uitvoeren.

Configuratie van de build

Niet zo lang geleden kreeg Jenkins de mogelijkheid om zijn regels te beschrijven met behulp van Pipeline syntax waardoor het behoorlijk eenvoudig is om het buildscript te wijzigen en het in de repository op te slaan.

Dus laten we een speciale Dockerfile in de repository plaatsen die alle noodzakelijke bibliotheken voor de build bevat. Op deze manier kan de ontwikkelaar een herhaalbare omgeving voorbereiden zonder dat de OPS gevraagd hoeft te worden om een specifieke versie van Node.JS op de host te installeren.

FROM node:12.10.0-alpine

RUN npm install yarn -g

Deze build-image is geschikt voor de meeste Node.JS-applicaties. Maar als je bijvoorbeeld een image nodig hebt voor een JVM-project met een ingebouwde Sonar-scanner? Je bent vrij om de benodigde componenten voor de build te kiezen.

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/

We hebben de build-omgeving beschreven, maar wat heeft Jenkins hiermee te maken? Jenkins-agenten kunnen met dergelijke Docker-images werken en de build intern uitvoeren.

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

Directive agent maakt gebruik van de eigenschap docker, waar je kunt opgeven:

  • de naam van de build-container volgens je naamgevingsbeleid;
  • de argumenten die nodig zijn om de build-container uit te voeren, waar we in ons geval de huidige directory als directory binnen de container monteren.

En in de build-stappen geven we aan welke commando's we binnen de build Docker-agent willen uitvoeren. Dit kan van alles zijn, op deze manier voer ik ook de deployment van applicaties uit met behulp van Ansible.

Hieronder wil ik een algemene Jenkinsfile laten zien die een eenvoudige Node.JS-applicatie kan bouwen.

def DOCKER_IMAGE_BRANCH = ""
def GIT_COMMIT_HASH = ""

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

    agent any

    stages {

        stage("Build afbeelding voorbereiden") {
            steps {
                sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
            }
        }

        stage("Project bouwen") {
            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()
        }
    }

}

Wat is het resultaat?

Dankzij deze aanpak hebben we de volgende problemen opgelost:

  • de configuratietijd van de buildomgeving bedraagt nu 10 tot 15 minuten per project;
  • volledig reproduceerbare buildomgeving voor de applicatie, omdat men ook lokaal kan bouwen;
  • geen problemen met conflicten tussen verschillende versies van buildtools;
  • altijd een schone werkruimte die niet volloopt.

De oplossing zelf is eenvoudig en duidelijk en biedt alleen voordelen. Ja, de instapdrempel is iets verhoogd vergeleken met eenvoudige buildcommando's, maar nu is er de garantie dat de build altijd zal plaatsvinden en kan de ontwikkelaar zelf alles kiezen wat nodig is voor zijn bouwproces.

U kunt ook gebruikmaken van de afbeelding die ik heb gebouwd Jenkins + Docker. Alle bronbestanden zijn open en te vinden op rmuhamedgaliev\/jenkins_docker.

Tijdens het schrijven van dit artikel ontstond er een discussie over het gebruik van agenten op externe servers, om de masternode niet te belasten via de plugin docker-plugin. Maar hier ga ik in de toekomst verder op in.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster