Blog

Concourse vs Jenkins

JAN 16, 2018

En djupgående jämförelse av två CI/CD-servrar: Concourse och Jenkins.

Sofus Albertsen

Sofus is a Continuous Delivery Trainer and Consultant in Copenhagen. Before joining Eficode Praqma he was assistant professor on an Applied Science Bachelor program. He flies kites and in the summer he escapes the modern world by spending two weeks in a beach hut without electricity or network coverage.

Vad behöver vi av ett CI/CD-system? Hur ska vi avgöra vilket vi ska använda? I den här bloggen undersöker vi hur ett modernt CI/CD-system bör se ut och jämför två vanliga byggsystem: Jenkins pipelines och Concourse CI.

Kriterier för att utvärdera en byggmotor

Användare väljer ofta en byggmotor som Jenkins, Travis eller VSTS av mindre än rationella skäl. Det kan vara ett känslomässigt beslut eller ett beslut baserat på att ”någon i teamet har arbetat med det tidigare”, snarare än ett välgrundat val. Valet av rätt CI/CD-system bör utgå från de kriterier som gäller för verksamheten och teamet, inte gamla vanor eller magkänsla.

På Eficode (tidigare Praqma) hjälper vi varje dag dussintals olika företag på deras resa mot Continuous Delivery. Genom den erfarenheten har vi sammanställt en lista över kriterier som alla CI/CD-system bör uppfylla.

Ditt företag kan ha särskilda behov och vissa kriterier kan vara viktigare för dig än andra, så du behöver avgöra vilket verktyg som passar dig bäst.

Vi har delat in våra krav i två kategorier: utveckling och drift. Det här inlägget fokuserar på utvecklingssidan av CI-servern.

Krav med fokus på utveckling

  • Är open source.
    På så sätt kan vi lägga till anpassade pluginer, åtgärda buggar och förstå teknikens vision.

  • Stöder pipelines som kod.
    Infrastructure as code!

  • Måste stödja alla större operativsystem.
    Windows, OSX och Linux (minst Debian- och Red Hat-baserade distributioner)

  • Kan sätta upp en pipeline som levererar för alla större utvecklingsområden
    Embedded, webb, desktop och mobil

  • Kan nås både lokalt och på serversidan.

  • Kan köra definierade steg parallellt
    Att bygga samma källkod på tio operativsystem bör ske parallellt.

  • Kan lagra artefakter från ett byggsteg till nästa

  • Kan köra om ett pipelinesteg för att felsöka problemet

  • På så sätt kan vi lägga till anpassade pluginer, åtgärda buggar och förstå teknikens vision.

  • Infrastructure as code!

  • Windows, OSX och Linux (minst Debian- och Red Hat-baserade distributioner)

  • Embedded, webb, desktop och mobil

  • Att bygga samma källkod på tio operativsystem bör ske parallellt.

En närmare titt på Concourse och Jenkins pipelines

Vårt fokus på Jenkins ligger enbart på de ”nya” pipeline-jobben, eftersom det är här Jenkins just nu lägger allt sitt arbete. Varje gång vi säger ”Jenkins” menar vi alltså ”Jenkins pipeline”.

Historik

Concourse

Utvecklingsteamen i cloudfoundry-projektet upplevde flera problem med sina pipelines i Jenkins. De försökte få dem att fungera, men hade svårt med de olika plattformar och tjänster som CloudFoundry behöver för att köras, och fastnade i den pluginarkitektur som Jenkins är. Detta ledde till Concourse CI, under ledning av Alex Suraci och hans team. Visionen för Concourse var en modernare byggmotor som var mindre beroende av pluginer, kunde dra nytta av nyare tekniker som containrar och gjorde pipelines till förstklassiga komponenter. Eftersom CloudFoundry är open source är även Concourse CI det.

Jenkins

Jenkins har en lång historia, vilket visar att communityn kring det är både levande och stark. Den kan stå upp mot ett stort företag om den väljer att följa en egen vision.

Det har den mognad och användarbas som krävs för att hantera i stort sett allt du behöver av en plattform.

Med det sagt styrs Jenkins till stor del av Cloudbees. Sedan 2014 har skaparen Kohsuke Kawaguchi varit CTO på Cloudbees, vilket innebär att det Cloudbees gör, gör även Kohsuke, och därmed också communityn. Cloudbees utvecklar aktivt Jenkins för att möta de nya standarderna för CI-servrar.

Terminologi och arkitektur

Concourse

Concourse är i grunden en containerteknik, men det finns även alternativ för att köra saker direkt i virtuella maskiner.

Komponenterna i ett Concourse-buildsystem är en master, en PostgreSQL-databas för beständig lagring och ett antal workers.

Concourse-mastern är egentligen ATC (en förkortning för air traffic control), som är systemets kärna. Du kan köra flera ATC:er för hög tillgänglighet, så länge de använder samma PostgreSQL-databas. ATC fungerar både som pipelineorkestrerare och lastfördelare i Concourse.

Workers registreras sedan via TSA (en förkortning för transportation security administration, en ordlek på flygtrafikstyrning), som egentligen är SSH-protokollet. Det gör att workers kan ansluta till mastern genom en omvänd tunnel från TSA, där mastern sedan kan styra trafiken.

Eftersom Concourse inte låter utvecklare konfigurera en pipeline från servern behöver du en binärfil (som heter fly) för att konfigurera en ny pipeline.

En pipeline i Concourse består av tre delar: resurser, resurstyper och jobb. I Concourse är en resurs ett objekt som du behöver hämta in till eller skicka ut från pipelinen. Bra exempel är Git, artifact-lagring och e-post, men även abstrakta saker som tid, andra pipelines och serverkonfiguration.

Resurstyper är ett sätt att definiera externa resurser som inte har skapats av Concourse-teamet. De hämtas sedan på samma sätt som en inbyggd resurs och behandlas på samma sätt. Slutligen är jobb exekveringsdelen, som bygger kod eller kör automatisering på en resurs.

Jenkins

Jenkins terminologi beskrivs enligt följande:

Jenkins-mastern är en avancerad schemaläggare som, baserat på jobbdefinitioner, övervakar och kör builds på noder. Ett jobb kan definieras på många sätt: som ett standardjobb via JobDSL eller via den nya Jenkins Pipeline.

Arkitekturmässigt är Jenkins ”bara” en Java-baserad WAR-fil för servern och en JAR-fil för noderna som bygger jobben. All konfiguration och alla loggar lagras i filer på masterns disk. Kärnan i Jenkins består endast av schemaläggaren, kommunikationen med noderna och exekveringen. Resten hanteras av plugins – och det finns gott om dem!

Jenkins swissknife

Det finns för närvarande 1 431 plugins för Jenkins, vilket både är en styrka och en svaghet. Styrkan är att Jenkins har blivit CI-världens schweiziska armékniv.

Om du behöver att Jenkins gör något åt dig är chansen stor att någon har skapat ett plugin för det! Men mängden plugins har också ett pris: alla håller inte produktionsklar kvalitet eller fungerar med det nya Pipeline-konceptet.

Eftersom Jenkins har funnits betydligt längre än containrar fokuserar det på att lägga builden på en nod snarare än i en container. Det har ändå bra stöd för containrar, både direkt från shell och via ett plugin, vilket gör det enkelt att arbeta med och hämta loggar från.

Hello world

Concourse

Concourse yml delas normalt upp i flera filer, men för att göra det lättare att läsa har allt lagts in direkt nedan:

jobs:- name: hello-world  public: true  plan:  - task: hello-world    config:      platform: linux      image_resource:        type: docker-image        source: {repository: ubuntu}      run:        path: sh        args:        - -exc        - |           echo "hello world"

Det här skapar helt enkelt ett enda jobb, utan resurser eller indata till jobbet, och skriver ut ”hello world”. Du kan starta det via webbgränssnittet eller med kommandoradsgränssnittet fly: fly -t yourconcourses execute --config tests.yml

Detta kan användas för valfri uppgift i pipelinen och ger utvecklaren full åtkomst till ett jobb med hjälp av lokala binärfiler/filer, även längre ned i pipelinen i senare jobb.

Jenkins

Jenkins har två varianter av Pipeline DSL: deklarativ och skriptad pipeline.

För båda behöver du konfigurera ett pipeline-jobb, antingen i Jenkins-gränssnittet eller via dess API. Jenkins stöder en pipeline i VCS:et eller en pipeline som skrivs i jobbdefinitionen i Jenkins. När det är klart är din DSL-fil mycket liten, vilket gör att hello world nästan ryms på en rad.

#Declarative pipeline pipeline {    agent any    stages {      stage('Build') {        steps {          echo 'hello world'        }      }    } }   #Scripted pipeline node {    stage('Build') {            echo 'hello world'    } }

Slutsats

Vinnare: Båda

Det är enkelt att komma igång med båda systemen. Om vi inte kunde få dem att fungera skulle vi inte utvärdera dem.

Operativsystem

Concourse

Du skapar en Concourse-worker eller master genom att ladda ner Concourse-binärfilen och ange argumentet ”worker” eller ”master”. Processen är densamma oavsett om du kör Windows, Linux eller OS X, vilket är möjligt eftersom Concourse är skrivet i GoLang.

Alla inbyggda resurser, liksom de flesta community-resurser, körs dock i containrar, vilket innebär ytterligare saker att ta hänsyn till. Det betyder att en typisk Windows-konfiguration fortfarande har minst en Linux-worker för att komma åt resurser. Dessutom arbetar Windows fortfarande med att få containrar att fungera, medan Concourse har det som en funktion för framtiden. En Windows-worker kör därför alltid sina processer i en virtuell maskin och isolerar dem genom mappstrukturen, snarare än på samma sätt som en container gör.

För ett pipeline-jobb som kör Windows, se vårt Git Phlow-jobb för Windows – och det görs på liknande sätt för OSX (men ofta är det helt enkelt enklare att använda Linux-slavar).

Ett bra exempel finns här (notera ”platform: darwin”). Det är hämtat från David Karlssons blogg om att konfigurera Concourse för mobil- och OSX-utveckling.

Jenkins

Jenkins-noder körs antingen på fysiska servrar eller virtuella maskiner. Så länge det finns en JVM för operativsystemet kan den köras. Hur du beskriver din nodmiljö avgör du själv, med hjälp av ett tredjepartsverktyg som Ansible, Chef eller Puppet, eller genom att manuellt installera en server (Om du gör det, fundera på att automatisera den delen!). Du lägger antingen till noder i din miljö via master-nodens gränssnitt eller med Jenkins Swarm-pluginet, som gör att noderna kontaktar sin master.

Slutsats

Vinnare: Oavgjort

Containrar har tydliga fördelar, men de innebär också en viss komplexitet. JVM är enkel att konfigurera och körs överallt, men är mer begränsad.

Pipelines: från embedded till mobil

Concourse

Concourse är mycket väl anpassat för webb-, mobil- och desktoputveckling. Embedded-utveckling har däremot ofta många FPGA-verktyg som körs på Windows, och även om det inte är ett hinder för Concourse får du inga av teknikens fördelar.

Linux-verktygen (som NT FPGA) är ganska GUI-tunga, vilket orsakar liknande problem. Concourse är som starkast när du drar nytta av containrar, och processer som är resurskrävande bör inte använda containrar. Om ett bygge tar en halvtimme hjälper det inte särskilt mycket att containrar är billiga att köra om vid fel.

För mycket embedded-utveckling behöver du låsa dina resurser för att säkerställa byggflödet, medan Concourse normalt är tänkt att bestå av helt atomära processer.

Jenkins

Som nämnts ovan

om det har en JVM kan det köra Jenkins.

I det avseendet kör den alltså alla pipelines på samma sätt, oavsett om det gäller mobilappar (exempel här och här), en Haskell-kompilator eller inbyggd FPGA-utveckling.

När du arbetar med en begränsad resurs erbjuder pluginet Lockable Resources ett mycket effektivt sätt att dela resursen mellan noder.

Koden för att låsa en resurs är mycket enkel och tydlig:

echo 'Starting' lock('my-resource-name') {   echo 'Do something here that requires unique access to the resource'   // any other build will wait until the one locking the resource leaves this block } echo 'Finish'

Du kan till och med ändra i vilken ordning resurser tilldelas för att vända på FIFO-kön:

lock(resource: 'staging-server', inversePrecedence: true) {  node {      servers.deploy 'staging'   }   input message: "Does ${Url}staging/ look good?" }

Slutsats

Vinnare: Jenkins

Jenkins är vinnaren här. Det körs överallt och det är enkelt att låsa resurser, vilket är ett måste för många.

Utvecklarinitierat arbete

Concourse

Concourse gör det möjligt för utvecklare att köra jobb på servern från sin egen terminal genom att köra:

fly -t myserver execute --config myjob.yml

Därefter används de lokala indata som anges för att köra jobbet! Det är mycket användbart eftersom utvecklare kan felsöka sin kod utan att behöva gå via pipelinen.

Det enda som behövs är en Concourse-server som utvecklarna kan rikta in sig på och som sedan kör jobbet i en avgränsad miljö, på en angiven slave, enligt specifikationen.

Jenkins

På det här området är Jenkins inte ens med. Vi behöver ett serverdefinierat jobb för att kunna köra något på byggservrarna. Punkt.

Så du måste göra rundresan via Git för att testa något:

Git push --> Jenkins pull --> Jenkins build --> Jenkins response --> Upprepa

Men med multibranch pipeline kan du anpassa pipelinen efter dina behov och pusha den till en annan branch än master för att se hur den körs.

I en enterprise-miljö skulle man kanske kunna hävda att ”du inte bör använda resurser för något som saknar en riktig pipeline”.

Jag måste erkänna att jag gärna skulle vilja kunna skicka in ett jobb till servern för körning. Det vore en utmärkt funktion att ha.

Slutsats

Vinnare: Concourse

Concourse visar vägen när det gäller utvecklarinitierad pipelinekörning. Jenkins, ni behöver höja nivån här!

Parallellisera din pipeline

Concourse

Det finns stöd för att köra både enskilda jobb (aggregate), resurser och hela pipelines parallellt. När en resurs ändras kan den trigga alla jobb som är beroende av den. Om resursen ändras igen strax därefter körs jobbet parallellt med de nya indata.

Återigen har vårt git phlow bra exempel på hur detta används i produktionskod.

- name: afterburner plan: - aggregate:   - get: praqma-tap   - get: git-phlow #contains the formula update script   - get: gp-version     passed: [takeoff]   - get: phlow-artifact-darwin-s3     passed: [takeoff]     trigger: true   - task: brew-release     file: git-phlow/ci/brew/brew.yml     on_failure:       put: slack-alert       params:         text: |           brew release failed https://concourse.bosh.praqma.cloud/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME   - put: praqma-tap     params:       repository: updated-praqma-tap

Jenkins

Jenkins har inbyggt stöd för detta i båda DSL-varianterna. Det skapar ett lättviktigt jobb på mastern för att samordna byggena. Det innebär att alla parallella körningar i ett steg måste slutföras innan nästa steg körs.

Nedan följer exempel på hur en lista med parallella körningar kan se ut, både i scriptad och deklarativ form.

Jenkinsfile (Scripted Pipeline) stage('Test') {        parallel linux: {        node('linux') {               try {               sh 'run-tests.sh'               }               finally {               junit '**/target/*.xml'               }        }        },        windows: {        node('windows') {               try {               sh 'run-tests.bat'               }               finally {               junit '**/target/*.xml'              }         }         } }
Jenkinsfile (Declarative Pipeline) pipeline {        agent none        stages {        stage('Test') {               parallel {               stage('Windows') {                      agent {                      label "windows"                      }                      steps {                      bat "run-tests.bat"                      }                      post {                      always {                              junit "**/TEST-*.xml"                      }                      }                }                stage('Linux') {                       agent {                       label "linux"                       }                       steps {                       sh "run-tests.sh"                       }                       post {                       always {                               junit "**/TEST-*.xml"                       }                       }                 }                 }          }          } }

Slutsats

Vinnare: Concourse

Även om marginalen inte är stor tar Concourse hem denna.

När du kör uppgifter parallellt i Jenkins måste alla vara klara innan du kan förgrena igen. Concourse har en betydligt friare definition och kan därför bero på godtyckliga villkor.

Hantering av artefakter

Concourse

Arbetsflödet i Concourse har en strikt uppdelning mellan resurser och jobb. Ett jobb kan bestå av flera uppgifter som kan dela artefakter, men ett jobb kan bara dela en artefakt med ett annat jobb om resursen skickas ut och lagras mellan jobben. Concourse lagrar aldrig artefakter självt och upprätthåller detta pull/push-tänk för att säkerställa atomära jobb.

Jenkins

Jenkins kan lagra artefakter på mastern med nyckelordet archive, men vi rekommenderar generellt att du använder ett dedikerat system för artefakthantering, som Artifactory, för detta behov.

För att överföra filer från en nod till en annan i samma pipeline-skript, till exempel när du behöver överföra din webbapplikation till din stresstestmiljö, kan du använda funktionen stash/unstash, som tillhandahåller artefakterna till den aktuella noden vid behov.

Slutsats

Vinnare: Jenkins

Båda har funktioner från tredje part, men Jenkins har även inbyggt stöd för att lagra artefakter på mastern.

Men den verkliga frågan är: vill du verkligen att ditt CI/CD-system även ska vara ditt system för artefakthantering?

Köra pipelines igen

Concourse

Det är så enkelt som att antingen gå till webbklienten och klicka på ”+” i ett jobb, eller köra det igen från kommandoradsgränssnittet fly. Därefter försöker systemet köra samma process som tidigare, med samma indata eller nya om de har uppdaterats.

concourse

Jenkins

Du kan köra om en hel pipeline när som helst, med samma parametrar.

Att köra ett steg i en pipeline igen är (till min stora frustration) en funktion som endast finns i Jenkins Enterprise. Cloudbees arbetar dock med en funktion för deklarativa pipelines, men inte för de mer avancerade scriptade varianterna. Jag tycker att det är ett mycket besvikande beslut.

helloworld

Slutsats

Vinnare: Concourse

Eftersom Concourse hanterar varje jobb i en pipeline som en atomär åtgärd är det självklart att kunna köra om dem. Jenkins behöver (åter)implementera den här funktionen för att kunna mäta sig med Concourse.

Slutsats

Och vinnaren är ….

För att vara ärlig finns det ingen sådan slutsats, eftersom allt beror på vad du värdesätter mest i din miljö. Jenkins är de facto-standarden hos våra kunder, men Concourse har fördelar som gör det till en värdig konkurrent.

  • CI/CD

Subscribe to our newsletter