Sedan de först introducerades som lite mer än förhärligade shell-skript har Continuous Integration-system, eller byggservrar som de kallades, utvecklats från en exotisk nischprodukt till en central del av varje välfungerande mjukvaruleveransprojekt.
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.
I takt med att Agile-metoder och Continuous Delivery blir allt vanligare har CI-servern fått en central roll i din utvecklingslivscykel.
Marknaden för CI-servrar växer snabbt, men det kan vara svårt att se skillnaderna mellan dem och välja vilken du ska använda. Ska du välja Jenkins, GitLab CI eller kanske GitHub Actions? Det här blogginlägget guidar dig genom urvalsprocessen och hjälper dig att göra det bästa valet.
CI:s historia
För omkring 20 år sedan byggde och lanserade en ThoughtWorks-anställd vid namn Matthew Foemmel den första versionen av CruiseControl. Det var förmodligen inte det första byggsystemet någonsin, men det blev det första som fick bred spridning och blev välkänt.
Jämför man en skärmbild av det ursprungliga CruiseControl med dagens GitLab CI ligger de stora skillnaderna i över 20 års utveckling av webbgränssnitt.
Men förvånansvärt lite av den viktigaste informationen du behöver har förändrats under den tiden. I grund och botten handlar det om detta:
När kördes en build?
Lyckades den eller inte?
Länk till mer information om resultatet från just den builden.
I grunden är build pipelines just det: en serie steg som verifierar om en viss kodändring resulterar i en build som kan släppas publikt.
Landskapet: Det är vilda västern där ute
Dagens utbud av CI-system är stort och växer snabbt. När jag började arbeta med DevOps var Jenkins de facto-standard, och idén om build pipelines som kod kändes som framtidsmusik. Allt gjordes i ett klickigt gränssnitt.
I dag finns det över ett dussin olika alternativ, som alla konkurrerar om marknadsandelar.
Alla har sina unika funktioner och påstådda fördelar, vilket gör det svårt att avgöra om du går miste om några avgörande funktioner när du väljer CI-varumärke X framför varumärke Y.
När du söker på webben visar mjukvaruleverantörer vanligtvis skräddarsydda jämförelser av funktioner gentemot konkurrenterna, som alltid visar deras överlägsenhet över utmanarna.
I följande avsnitt fokuserar jag på tre alternativ: Jenkins, GitHub Actions och GitLab CI. Jag har valt dessa tre produkter eftersom det är de vi oftast ser i praktiken just nu och de representerar de vanligaste alternativen.
Så skiljer sig alternativen åt
Alla tre leverantörer har sina styrkor och svagheter, och beroende på dina behov och preferenser är vissa viktigare än andra.
Matrisen nedan visar de faktorer som jag värderar högst när jag väljer ett CI-system.
|
Capability |
Gitlab CI |
Github Actions |
Jenkins |
|
Open source |
Open core model |
No |
Yes |
|
Pipeline language |
YAML |
YAML |
Groovy DSL (both declarative and programmatic) |
|
Only fan in/out, or full DAG* |
Full DAG |
Full DAG |
Fan in/out |
|
Plugins |
No (does have built-in integrations) |
Actions (Docker/JS) |
|
|
Matrix build |
|||
|
Template/starter workflow |
2 |
||
|
Up/downstream pipeline triggers |
Not built in/ Via Actions |
||
|
Runners VM/Docker |
VM's and Docker |
Roll your own |
|
|
Saas runners OS |
X |
||
|
Self-hosted runners? |
Y |
Y |
Y |
|
Optional steps |
Funktion
GitLab CI
GitHub Actions
Jenkins
Öppen källkod
Open core-modell
Nej
Ja
Pipelinespråk
YAML
YAML
Groovy DSL (både deklarativt och programmatiskt)
Endast fan in/out eller fullständig DAG*
Fullständig DAG
Fullständig DAG
Fan in/out
Plugins
Nej (har inbyggda integrationer)
Actions (Docker/JS)
Matrisbygge
Mall-/startarbetsflöde
2
Pipeline-triggers uppströms/nedströms
Inte inbyggt/via Actions
Runners: VM/Docker
VM:ar och Docker
Egen lösning
Operativsystem för SaaS-runners
X
Self-hosted runners?
Ja
Y
Y
Valfria steg
* DAG förklaras längre fram i inlägget.
Som du kan se i tabellen är konkurrensen ganska jämn. Designval gör att vissa väljer YAML framför ett DSL, eller föredrar fler inbyggda funktioner framför att ha allt som externa verktyg, till exempel plugins eller Actions, som GitHub kallar dem.
Jenkins börjar däremot kännas allt mer föråldrat. Det har till exempel inga startmallar som gör att du kan komma i gång med ”Hello Gradle” eller liknande på några minuter.
Jenkins saknar också stöd för riktade acykliska grafer (DAG) för pipeline-orkestrering, vilket kan leda till längre återkopplingstider – något vi aktivt avråder från.
Lite om DAG-pipelines
När du bygger pipelines vill du vanligtvis köra så mycket som möjligt parallellt. Men alla jobb tar inte lika lång tid. Om CI-systemet bara stöder fan-in/fan-out måste alla jobb i ett visst ”steg” vara klara innan nästa omgång jobb kan köras.
Med DAG-pipelines (Directed Acyclic Graph) kan du ange när vart och ett av dina jobb kan köras, alltså vilka andra jobb som först måste vara klara. CI-systemet bestämmer sedan ordningen därefter. Detta är särskilt viktigt för stora projekt med flera nivåer och/eller monorepon.
Vem vinner kriget?
Här kommer en subjektiv del av bloggen: om du inte anser att en unik funktion hos en viss leverantör är en avgörande särskiljande faktor, kan du välja vilket CI-system som helst och ändå releasa kvalitativ mjukvara (förutsatt att du från början har skrivit kvalitativ mjukvara).
En sådan funktion var tidigare att CircleCI, som en av de första SaaS-lösningarna, erbjöd stöd för både OS X och Android. Det gjorde CircleCI idealiskt för utvecklare av mobilappar som inte ville köpa en Mac för att bygga iOS-appar.
Och om du inte anser att driften av din CI-verksamhet (serverinstanser för huvudservern och build agents) är en del av din konkurrensfördel, bör du fundera ordentligt på om någon annan – en leverantör eller tredje part – kan göra det åt dig. Då kan du använda dina välförtjänta innovation tokens till annat.
Så varför bygger så många företag samma sak?
För att det pågår ett krig om hela utvecklingsekosystemet.
Ur leverantörens perspektiv har en kund som använder flera av deras verktyg för ärendehantering, kodrepo, build-servrar och så vidare mycket svårare att lämna dem, eftersom saker tenderar att ”klistras” ihop. (Ur leverantörens perspektiv är inlåsning hos leverantören faktiskt något positivt.)
Sex steg till visdom
Nedan följer några praktiska steg som jag har haft nytta av när jag har valt, eller rett ut, ett CI-system:
Utvärdera din miljö. Om Github/Gitlab/Atlassian redan fungerar bra för dig, håll dig till deras build-system och dra nytta av synergierna med leverantören. Jenkins är svårare ur ett förvaltningsperspektiv, och dess plugin-djungel gör uppgraderingar röriga. Dessutom innebär kopplingen loss från källkodsreposervern att du får ytterligare en app(™) att hantera (eller bli hanterad av).
Säkra din leveranskedja. De senaste åren har attacker mot leveranskedjan varit en av de mest skrämmande metoderna för att förgifta mjukvara inifrån leveranskedjan. Säkerhetsfunktioner som tvåfaktorsautentisering, olika sätt att verifiera vem som har pushat kod (till exempel kodsignering), enkel rollbaserad åtkomstkontroll (RBAC), sårbarhetsskanning av mjukvarubibliotek eller källkod med mera är ovärderliga här. GitHub och Gitlab ligger långt före, eftersom du med Jenkins inte bara behöver bygga det mesta själv eller köpa separata verktyg, utan Jenkins och dess plugins dessutom är en ständig källa till CVE:er.
Granska dina pipelines. Om du använder många leverantörsspecifika verktyg och plugins är det sannolikt svårt att byta.
Reproducerbarhet överallt. Helst ska du kunna releasa även om ditt CI-system ligger nere. Genom att lägga merparten av build-arbetet i skript blir det enklare att testa varje steg på en utvecklarmaskin och skapa akutreleaser om CI-systemet ligger nere och du behöver releasa.
Containerisera dina arbetslaster och din leverans. Det har många andra fördelar än att bara göra din pipeline reproducerbar. Om du fortfarande kämpar med ”men det fungerar på min dator” är containrar lösningen.
Kom ihåg att hålla din pipeline enkel. Om du har logik i pipelinen som måste definiera dina kriterier för framgång eller misslyckande är din pipeline för intelligent. Ta ett steg tillbaka och fråga dig själv: ”Är det här verkligen nödvändigt?” Ett sätt att förbättra pipelinen är att hålla en workshop med teamet om pipelinen med hjälp av Pipeline game. På så sätt kan du se bortom detaljarbetet och fokusera på de större frågorna, som vilka kvalitetsgrindar du behöver och hur du avgör att det är säkert att releasa.
Att se är att tro: Eficodes exempelpipeline
Slutligen, om du vill se skillnaderna i hur syntaxen ser ut hos olika leverantörer, har vi skapat samma pipeline i alla CI-system som nämns ovan (och några till).
Pipelinen ser ungefär likadan ut i alla systemen:
Steg:
Clone down: kör git clone och förbereder repot för att distribueras till de parallella stegen
Test: kör Gradle-kommandot test som finns i ci/unit-test-app.sh
Build: kör Gradle-kommandot build som finns i ci/build-app.sh
Build Docker: kör lintning av Dockerfile, bygger Docker-imagen och pushar den till hubben
Systemtester: kör två tester: först ett k6-prestandatest med docker-compose, därefter en docker-compose-fil med ett Python-test för att testa applikationen.
Du kan fördjupa dig i skillnaderna och likheterna mellan syntaxerna i GitHub-repot: https://github.com/eficode-academy/war-ci-servers
- DevOps
- CI/CD
Subscribe to our newsletter
Related blogs