Stel je twee ontwikkelteams voor.
Het eerste team bereidt een nieuwe versie van de applicatie voor.
De programmeur rondt de taak af. Iemand controleert de code. Daarna moeten de tests worden uitgevoerd. Iemand maakt het pakket klaar. Iemand anders logt in op de server. Vervolgens moet een aantal handmatige acties worden uitgevoerd, de configuratie worden gecontroleerd en moet het systeem na de uitrol worden gemonitord. Als alles goed gaat, is de nieuwe versie beschikbaar.
Het tweede team werkt anders.
De code komt in de repository terecht. Automatisch starten de tests, kwaliteitsanalyse en beveiligingscontroles. Het systeem bouwt de applicatieversie, zet die uit op de testomgeving, voert vervolgstappen uit en kan, nadat aan bepaalde voorwaarden is voldaan, deze naar productie uitrollen. Als er iets misgaat, wordt de uitrol gestopt of kan het systeem terugkeren naar de vorige versie.
Beide teams maken software.
Maar slechts één van hen heeft een herhaalbaar softwareleveringsproces opgebouwd.
En daar gaat CI/CD precies om.
"Werkt in productie" is nog geen volwassen proces
Veel bedrijven meten succes met een heel eenvoudige maatstaf: de applicatie werkt.
Dat is natuurlijk een basisvoorwaarde.
Maar naarmate het systeem groeit, komen er nieuwe vragen bij:
- Hoe snel kunnen we een verbetering uitrollen?
- Hoe vaak kunnen we nieuwe functionaliteit publiceren?
- Hoeveel handmatige stappen voeren we uit bij elke uitrol?
- Kan elke programmeur het uitrolproces volgens dezelfde regels starten?
- Weten we welke versie momenteel draait?
- Kunnen we teruggaan naar de vorige versie?
- Controleren we na de uitrol automatisch of het systeem correct werkt?
- Hebben we monitoring?
- Weten we dat de uitrol een probleem heeft veroorzaakt voordat de klant het meldt?
Dit zijn vragen over software delivery, en niet alleen over programmeren zelf.
CI en CD - twee onderdelen van één proces
CI, oftewel Continuous Integration, betekent continue integratie van veranderingen.
In de praktijk gaat het erom dat wijzigingen vaak in de gezamenlijke repository terechtkomen en automatisch worden gecontroleerd.
Een typische pipeline kan onder meer het volgende uitvoeren:
-
het compileren of bouwen van de applicatie,
-
unit tests,
-
integratietests,
-
linting,
-
statische code-analyse,
-
het scannen van afhankelijkheden,
-
beveiligingscontroles,
-
het bouwen van uitrolartefacten.
Daarmee kan een probleem worden ontdekt voordat de code in productie komt.
CD, oftewel Continuous Delivery of Continuous Deployment, gaat over de volgende fase - het leveren van veranderingen.
Afhankelijk van het gekozen model kan het systeem een kant-en-klare versie voorbereiden voor uitrol of deze automatisch uitrollen nadat bepaalde controles zijn doorlopen.
Dat is een belangrijk onderscheid.
Continuous Delivery hoeft niet te betekenen dat elke wijziging automatisch naar productie wordt uitgerold.
Het kan simpelweg betekenen dat elke versie op een herhaalbare manier voor uitrol wordt voorbereid.
Waarom worden handmatige uitrollen een probleem?
Een handmatige uitrol hoeft niet slecht te zijn.
In een klein project kan het volledig voldoende zijn.
Het probleem begint wanneer het proces meegroeit met de applicatie.
Eerst hebben we één persoon die weet hoe het systeem moet worden uitgerold. Dan komt er een tweede server bij. Daarna de testomgeving. Vervolgens de database, cache, wachtrijen, storage, meerdere services en externe API's. Daar bovenop komen verschillende configuraties voor development, test en productie.
Na een paar jaar kan het proces er ongeveer zo uitzien:
"Start eerst X, verander daarna parameter Y, herstart vervolgens service Z, maar maak eerst een back-up van de database. En als er een fout optreedt, bel dan de persoon die dit de vorige keer heeft uitgerold."
Dat is geen proces meer. Dat is kennis die verborgen zit in het hoofd van één persoon. En juist dan neemt het risico toe.
Automatisering is niet alleen bedoeld voor het gemak van ontwikkelaars
Vaak wordt CI/CD gepresenteerd als een hulpmiddel dat het comfort van developers vergroot. Dat klopt, maar het is slechts een deel van het verhaal.
Automatisering van delivery vergroot vooral de herhaalbaarheid van het proces.
Als een mens de uitrol uitvoert, bestaat de kans dat hij of zij elke keer iets anders doet.
Als een pipeline het doet, kun je een exacte volgorde van stappen definiëren.
Dezelfde versie.
Dezelfde tests.
Dezelfde controles.
Dezelfde regels.
Dit is vooral belangrijk in projecten die door meerdere personen of meerdere teams worden ontwikkeld.
Tests vóór de uitrol zijn belangrijker dan de snelheid van uitrollen
Automatisering zonder tests kan er alleen maar voor zorgen dat fouten sneller opduiken.
Daarom zou een goed ontworpen pipeline niet alleen een mechanisme moeten zijn: "code → productie".
Het moet een kwaliteitscontrolesysteem zijn.
Afhankelijk van het project kunnen hierin het volgende zitten:
- Unit tests - die afzonderlijke onderdelen van de logica controleren.
- Integratietests - die de samenwerking tussen componenten controleren.
- End-to-end tests - die realistische gebruikersscenario's simuleren.
- Beveiligingstests - die onder meer afhankelijkheden en bekende kwetsbaarheden controleren.
- Prestentietests - nodig waar het belangrijk is om een bepaalde belasting aan te kunnen.
Niet elke applicatie heeft al deze lagen in dezelfde omvang nodig.
En dat is belangrijk.
CI/CD gaat niet over het in de pipeline gooien van zoveel mogelijk tools.
Het gaat om het afstemmen van controles op het risico van het specifieke systeem.
Wat gebeurt er als een test niet slaagt?
Dat is een van de belangrijkste vragen in het hele proces.
Een volwassen pipeline moet duidelijk gedefinieerde regels hebben.
Als een kritieke test niet slaagt, mag de versie niet als klaar voor uitrol worden beschouwd.
Als een beveiligingsscan een bepaald risiconiveau detecteert, kan de pipeline het proces stoppen.
Als de build niet slaagt, valt er niets uit te rollen.
Dat klinkt banaal. Maar juist zulke automatische "poorten" zorgen ervoor dat kwaliteit niet alleen afhangt van het geheugen en de nauwkeurigheid van een mens.
En wat als de uitrol toch mislukt?
Zelfs het beste proces elimineert niet alle fouten. Daarom is het tweede element van volwassen delivery de mogelijkheid tot gecontroleerde terugdraaiing van een wijziging.
Rollback kan betekenen dat je teruggaat naar het vorige artefact, de vorige containerimage of de vorige applicatieversie. Maar hier duikt een belangrijk probleem op. Rollback van code betekent niet altijd rollback van data.
Als de nieuwe versie de structuur van de database heeft gewijzigd, wordt de situatie ingewikkelder.
Daarom moeten databasemigraties zo worden ontworpen dat het hele proces zo veilig en omkeerbaar mogelijk is, of op zijn minst compatibel met de vorige versie van de applicatie.
Dit is een van de voorbeelden die laten zien dat professioneel CI/CD een architectonisch probleem is, en niet alleen een configuratie van een tool.
Blue-green, canary en andere uitrolstrategieën
In veeleisender systemen hoeft niet meteen alle gebruikers naar de nieuwe versie te worden overgezet. Er kunnen verschillende deploymentstrategieën worden toegepast.
Blue-green deployment
Er draaien twee versies van de omgeving.
De ene verwerkt het verkeer, de andere wordt voorbereid om het verkeer over te nemen.
Na een positieve verificatie volgt de omschakeling.
Het voordeel is de mogelijkheid om snel terug te keren naar de vorige omgeving.
Een nadeel kan een hoger infrastructuurverbruik zijn.
Canary deployment
De nieuwe versie gaat eerst naar een klein deel van de gebruikers of van het verkeer.
Als monitoring geen problemen laat zien, kan de uitrol geleidelijk worden uitgebreid.
Dat beperkt de mogelijke impact van een fout.
Maar dit vereist wel de juiste infrastructuur, monitoring en een manier om het verkeer te beheren.
Feature flags
Een functie kan in het systeem worden uitgerold, maar uitgeschakeld blijven voor gebruikers.
Daardoor worden het uitrollen van code en het activeren van functionaliteit twee afzonderlijke processen.
Dat geeft meer controle, vooral bij grote veranderingen.
Dat betekent echter niet dat feature flags voor elk project de oplossing zijn. Hun overmatig gebruik kan ook de complexiteit van het systeem verhogen.
Monitoring na de uitrol
Je kunt alle tests uitvoeren. Je kunt een geweldige pipeline hebben. Je kunt een nieuwe versie uitrollen zonder enige fout. En een paar minuten later kan de applicatie zich anders gaan gedragen onder echte belasting.
Daarom mag het proces niet eindigen bij de deployment. Er is observability nodig, dus de mogelijkheid om te begrijpen wat er binnen het draaiende systeem gebeurt.
Afhankelijk van de architectuur omvat dit onder andere:
-
logs,
-
metingen,
-
tracing,
-
monitoring van de infrastructuur,
-
monitoring van de applicatie,
-
alerts,
-
foutinformatie,
-
businessmetrics.
Het gaat er niet om alles te verzamelen. Het gaat erom dat belangrijke vragen op basis van gegevens beantwoord kunnen worden.
Werkt de applicatie?
Werkt ze langzamer dan voorheen?
Is het aantal fouten toegenomen?
Welke service veroorzaakt het probleem?
Heeft het probleem betrekking op alle gebruikers of slechts op een deel?
100 deployments per dag is niet altijd het doel
De titel van dit artikel spreekt over 100 deployments per dag, maar het gaat er niet om dat getal als doel te stellen.
In een intern systeem dat één keer per maand wordt bijgewerkt, heeft het geen zin om kunstmatig naar honderden deployments te streven. In een systeem dat heel intensief wordt ontwikkeld, kan die frequentie echter technisch wel mogelijk zijn.
Cruciaal is de mogelijkheid om veranderingen veilig te leveren, en niet het aantal deployments zelf. Dat is een fundamenteel verschil.
De volwassenheid van het proces wordt niet gemeten aan hoe vaak we deployen, maar aan hoe voorspelbaar en veilig we dat kunnen doen.
Wanneer kan CI/CD een geval zijn van vorm boven inhoud?
Niet elke applicatie heeft een complexe deploymentinfrastructuur nodig.
Als we een kleine applicatie hebben, een klein team en een paar deployments per jaar, kan een uitgebreide pipeline meer kosten dan de problemen die hij oplost.
Hetzelfde geldt voor zeer specifieke systemen waarbij de uitrol om veiligheidsredenen, regelgeving of de aard van de infrastructuur handmatige controle vereist.
Daarom moet de delivery-architectuur voortkomen uit de behoeften van het systeem. Niet uit de mode.
Wanneer levert automatisering van deployments bijzonder veel op?
Het is vooral de moeite waard om dit te overwegen wanneer:
-
het systeem regelmatig wordt ontwikkeld,
-
er met de code door meerdere mensen wordt gewerkt,
-
er meer dan één omgeving bestaat,
-
de deployments frequent zijn,
-
handmatige deployments fouten veroorzaken,
-
het systeem van kritisch zakelijk belang is,
-
we een snelle rollback nodig hebben,
-
de applicatie uit veel componenten bestaat,
-
audits of een wijzigingshistorie vereist zijn,
-
de doorlooptijd voor het leveren van functies zakelijk belangrijk is.
In zulke gevallen kan een goed ontworpen pipeline een van de belangrijkste elementen van het softwareontwikkelproces zijn.
CI/CD herstelt geen slechte architectuur
Dat is ook iets om te benadrukken.
Je kunt een geweldige pipeline maken voor een slechte applicatie.
Slechte code automatisch testen.
Een slechte architectuur automatisch uitrollen.
Een slecht ontworpen systeem automatisch schalen.
Automatisering vervangt dus de architectuur, tests of de competenties van het team niet.
Het versterkt het bestaande proces.
Als het proces goed is, helpt het om op te schalen.
Als het proces slecht is, kan het gewoon sneller slechte dingen uitvoeren.
Hoe ziet een volwassen proces eruit?
Er bestaat niet één universele pipeline.
Maar een volwassen proces zou een paar basiskenmerken moeten hebben.
Herhaalbaarheid - de uitrol wordt uitgevoerd volgens gedefinieerde stappen.
Automatisering - machines voeren zoveel mogelijk van het repetitieve werk uit.
Testbaarheid - veranderingen worden automatisch geverifieerd.
Veiligheid - het proces omvat passende beveiligingscontroles.
Observability - na de uitrol is bekend wat er met het systeem gebeurt.
Omkeerbaarheid - er bestaat een gepland plan om op een mislukte wijziging te reageren.
Wijzigingen bijhouden - er is bekend welke versie is uitgerold en waaruit die is opgebouwd.
Toegangsbeheer - niet iedereen kan zomaar alles op productie uitrollen.
Juist uit zulke elementen ontstaat een professioneel softwaredeliveryproces.
De belangrijkste verandering begint met een andere vraag
Bedrijven vragen vaak: "Hoe snel kunnen we deze functie maken?"
Het is de moeite waard om een tweede vraag toe te voegen: "Hoe snel en veilig kunnen we de volgende 50 functies leveren?"
Want een enkele uitrol kan handmatig worden uitgevoerd. Je kunt een applicatie zelfs jarenlang handmatig uitrollen. Maar naarmate het product, het team, het aantal gebruikers en het aantal wijzigingen groeien, neemt ook de prijs van zo’n aanpak toe.
Daarom zijn CI/CD, automatische tests, monitoring en gecontroleerde deployments niet alleen oplossingen voor grote corporaties.
Het zijn elementen van de procesinfrastructuur waarmee je software kunt ontwikkelen zonder onnodig risico aan elke volgende wijziging toe te voegen.
En uiteindelijk gaat het daar juist om.
Niet om 100 deployments per dag.
Niet om modieuze tools.
Niet om de meest complexe pipeline.
Maar om de mogelijkheid te hebben te zeggen:
"We hebben een wijziging. We hebben die gecontroleerd. We weten wat we uitrollen. We weten hoe we erop moeten letten. En we weten wat we zullen doen als er iets misgaat."
