Forestil dig to udviklingsteams.
Det første forbereder en ny version af applikationen.
Udvikleren afslutter opgaven. Nogen gennemgår koden. Så skal testene køres. Nogen forbereder pakken. En anden logger ind på serveren. Derefter skal der udføres nogle manuelle handlinger, konfigurationen skal kontrolleres, og systemet skal overvåges efter implementeringen. Hvis alt går godt, er den nye version tilgængelig.
Det andet team arbejder anderledes.
Koden sendes til repositoryet. Test, kvalitetsanalyse og sikkerhedskontroller starter automatisk. Systemet bygger applikationsversionen, implementerer den på testmiljøet, udfører yderligere kontroller, og når bestemte betingelser er opfyldt, kan den implementeres i produktion. Hvis noget går galt, stoppes implementeringen, eller systemet kan rulles tilbage til den tidligere version.
Begge teams udvikler software.
Men kun det ene har opbygget en gentagelig proces for softwarelevering.
Og det er netop det, CI/CD handler om.
"Det virker i produktion" er endnu ikke en moden proces
Mange virksomheder måler succes med en meget simpel indikator: applikationen virker.
Det er naturligvis en grundlæggende forudsætning.
Men i takt med at systemet vokser, opstår der flere spørgsmål:
- Hvor hurtigt kan vi implementere en rettelse?
- Hvor ofte kan vi udgive nye funktioner?
- Hvor mange manuelle handlinger udfører vi ved hver implementering?
- Kan hver udvikler starte implementeringsprocessen efter de samme regler?
- Ved vi, hvilken version der kører lige nu?
- Kan vi gå tilbage til den tidligere version?
- Tjekker vi automatisk efter implementeringen, om systemet fungerer korrekt?
- Har vi overvågning?
- Ved vi, at implementeringen skabte et problem, før kunden melder det?
Det er spørgsmål om software delivery, ikke kun om selve programmeringen.
CI og CD - to elementer i én proces
CI, altså Continuous Integration, betyder løbende integration af ændringer.
I praksis handler det om, at ændringer ofte sendes til det fælles repository og automatisk kontrolleres.
En typisk pipeline kan blandt andet køre:
-
kompilering eller bygning af applikationen,
-
enhedstests,
-
integrationstests,
-
linting,
-
statisk kodeanalyse,
-
scanning af afhængigheder,
-
sikkerhedskontroller,
-
bygning af implementeringsartefakter.
På den måde kan problemet opdages, før koden når produktion.
CD, altså Continuous Delivery eller Continuous Deployment, handler om næste fase - levering af ændringer.
Afhængigt af den valgte model kan systemet forberede en færdig version til implementering eller automatisk implementere den efter at have bestået bestemte kontroller.
Det er en vigtig forskel.
Continuous Delivery betyder ikke nødvendigvis automatisk implementering af hver ændring i produktion.
Det kan blot betyde, at hver version forberedes gentageligt til implementering.
Hvorfor bliver manuelle implementeringer et problem?
Manuel implementering behøver ikke være dårlig.
I et lille projekt kan det være helt tilstrækkeligt.
Problemet opstår, når processen vokser sammen med applikationen.
Først har vi én person, der ved, hvordan systemet implementeres. Så kommer den anden server. Senere testmiljøet. Derefter databasen, cache, køer, storage, flere tjenester og eksterne API'er. Dertil kommer forskellige konfigurationer til development, test og produktion.
Efter nogle år kan processen se nogenlunde sådan ud:
"Start først X, ændr derefter parameter Y, genstart så tjeneste Z, men tag først en backup af databasen. Og hvis der opstår en fejl, så ring til den person, der implementerede det sidst."
Det er ikke længere en proces. Det er viden gemt i et menneskes hoved. Og netop dér stiger risikoen.
Automatisering handler ikke kun om at gøre udviklernes arbejde nemmere
Ofte fremstilles CI/CD som et værktøj, der øger udviklernes komfort. Det er rigtigt, men det er kun en del af billedet.
Automatisering af delivery øger først og fremmest processens gentagelighed.
Hvis implementeringen udføres af et menneske, er der mulighed for, at vedkommende gør noget lidt anderledes hver gang.
Hvis det er pipelinen, der gør det, kan man definere en præcis rækkefølge af trin.
Den samme version.
De samme tests.
De samme kontroller.
De samme regler.
Det er især vigtigt i projekter, der udvikles af flere personer eller flere teams.
Tests før implementering er vigtigere end implementeringshastighed
Automatisering uden tests kan kun føre til, at fejl opstår hurtigere.
Derfor bør en veldesignet pipeline ikke kun være en mekanisme: "kode → produktion".
Den bør være et kvalitetssikringssystem.
Afhængigt af projektet kan den indeholde:
- Enhedstests - der kontrollerer enkelte dele af logikken.
- Integrationstests - der kontrollerer komponenternes samspil.
- End-to-end-tests - der simulerer virkelige brugerscenarier.
- Sikkerhedstests - der blandt andet kontrollerer afhængigheder og kendte sårbarheder.
- Ydelsestests - nødvendige, hvor håndtering af en bestemt belastning er vigtig.
Ikke alle applikationer har brug for alle disse lag i samme omfang.
Og det er vigtigt.
CI/CD handler ikke om at smide så mange værktøjer som muligt ind i pipelinen.
Det handler om at vælge kontroller ud fra risikoen i det konkrete system.
Hvad sker der, når en test fejler?
Det er et af de vigtigste spørgsmål i hele processen.
En moden pipeline bør have klart definerede regler.
Hvis en kritisk test ikke består, bør versionen ikke betragtes som klar til implementering.
Hvis en sikkerhedsscanning opdager et bestemt risikoniveau, kan pipelinen stoppe processen.
Hvis buildet ikke lykkes, er der intet at implementere.
Det lyder banalt. Men det er netop sådanne automatiske "gateways", der betyder, at kvaliteten ikke kun afhænger af menneskets hukommelse og nøjagtighed.
Og hvis implementeringen alligevel mislykkes?
Selv den bedste proces eliminerer ikke alle fejl. Derfor er det andet element i moden delivery muligheden for kontrolleret tilbagerulning af ændringen.
Rollback kan betyde tilbagevenden til det tidligere artefakt, containerimage eller applikationsversion. Men her opstår et vigtigt problem. Rollback af kode betyder ikke altid rollback af data.
Hvis den nye version ændrede databasens struktur, bliver situationen mere kompliceret.
Derfor bør databasemigrationer designes, så hele processen er så sikker og reversibel som muligt eller i det mindste kompatibel med den forrige version af applikationen.
Det er et af eksemplerne, der viser, at professionel CI/CD er et arkitektonisk problem og ikke kun en værktøjskonfiguration.
Blue-green, canary og andre deployeringsstrategier
I mere krævende systemer behøver man ikke straks at skifte alle brugere til den nye version. Man kan anvende forskellige deployeringsstrategier.
Blue-green deployment
To versioner af miljøet kører samtidig.
Den ene håndterer trafikken, den anden forberedes til at overtage trafikken.
Efter en positiv verifikation sker skiftet.
Fordelen er muligheden for hurtigt at vende tilbage til det tidligere miljø.
Ulempen kan være et større forbrug af infrastruktur.
Canary deployment
Den nye version rulles først ud til en lille del af brugerne eller trafikken.
Hvis overvågningen ikke viser problemer, kan udrulningens omfang gradvist øges.
Det begrænser den potentielle rækkevidde af fejlen.
Det kræver dog passende infrastruktur, overvågning og en måde at styre trafikken på.
Feature flags
En funktion kan blive implementeret i systemet, men forblive slået fra for brugerne.
På den måde bliver kodeudrulning og aktivering af funktionalitet to separate processer.
Det giver større kontrol, især ved store ændringer.
Det betyder dog ikke, at feature flags er en løsning for hvert projekt. Deres overbrug kan også øge systemets kompleksitet.
Overvågning efter udrulning
Man kan gennemføre alle tests. Man kan have en fremragende pipeline. Man kan udrulle en ny version uden nogen fejl. Og få minutter senere kan applikationen begynde at opføre sig anderledes under reel belastning.
Derfor bør processen ikke ende ved deployeringen. Der er brug for observability, altså muligheden for at forstå, hvad der sker inde i det kørende system.
Afhængigt af arkitekturen omfatter det blandt andet:
-
logs,
-
metrikker,
-
tracing,
-
infrastrukturmonitorering,
-
applikationsmonitorering,
-
alarmer,
-
fejlinformation,
-
forretningsmæssige nøgletal.
Det handler ikke om at indsamle alt. Det handler om, at man skal kunne besvare vigtige spørgsmål på baggrund af data.
Kører applikationen?
Kører den langsommere end før?
Er antallet af fejl steget?
Hvilken service skaber problemet?
Vedrører problemet alle brugere eller kun en del?
100 udrulninger om dagen er ikke altid målet
Titlen på denne artikel taler om 100 udrulninger om dagen, men det handler ikke om at sætte netop det tal som mål.
I et internt system, der opdateres én gang om måneden, giver det ikke mening kunstigt at stræbe efter hundredvis af deploymenter. I et system, der udvikles meget intensivt, kan en sådan frekvens derimod være teknisk mulig.
Det afgørende er evnen til sikkert at levere ændringer, ikke antallet af udrulninger i sig selv. Det er en grundlæggende forskel.
Procesmodenhed måles ikke på, hvor ofte vi deployer, men på, hvor forudsigeligt og sikkert vi kan gøre det.
Hvornår kan CI/CD være form uden indhold?
Ikke alle applikationer har brug for en kompleks deploymentinfrastruktur.
Hvis vi har en lille applikation, et lille team og få udrulninger om året, kan en omfattende pipeline koste mere end de problemer, den løser.
Det samme gælder meget specifikke systemer, hvor udrulning kræver manuel kontrol af hensyn til sikkerhed, regulering eller infrastrukturens karakter.
Derfor bør delivery-arkitekturen udspringe af systemets behov. Ikke af mode.
Hvornår giver automatisering af udrulninger særligt meget?
Det er især værd at overveje, når:
-
systemet udvikles løbende,
-
flere personer arbejder på koden,
-
der findes mere end ét miljø,
-
udrulninger er hyppige,
-
manuelle udrulninger skaber fejl,
-
systemet er af kritisk forretningsmæssig betydning,
-
vi har brug for hurtig rollback,
-
applikationen består af mange komponenter,
-
der kræves audits eller ændringsspor,
-
tiden til at levere en funktion har forretningsmæssig betydning.
I sådanne tilfælde kan en veludformet pipeline være et af de vigtigste elementer i softwareudviklingsprocessen.
CI/CD retter ikke dårlig arkitektur
Det er også værd at understrege.
Man kan lave en fantastisk pipeline til en dårlig applikation.
Automatisk teste dårlig kode.
Automatisk deploye dårlig arkitektur.
Automatisk skalere et dårligt designet system.
Automatisering erstatter derfor ikke arkitektur, tests eller teamets kompetencer.
Den forstærker den eksisterende proces.
Hvis processen er god, hjælper den med at skalere den.
Hvis processen er dårlig, kan den blot udføre dårlige ting hurtigere.
Hvordan ser en moden proces ud?
Der findes ikke én universel pipeline.
Men en moden proces bør have nogle grundlæggende egenskaber.
Gentagelighed - udrulningen udføres efter definerede trin.
Automatisering - maskiner udfører så stor en del af det gentagne arbejde som muligt.
Testbarhed - ændringer verificeres automatisk.
Sikkerhed - processen omfatter passende sikkerhedskontroller.
Observability - efter udrulningen ved man, hvad der sker med systemet.
Reversibilitet - der findes en planlagt måde at reagere på en mislykket ændring.
Ændringssporing - man ved, hvilken version der er blevet udrullet, og hvad den er bygget af.
Adgangskontrol - ikke alle kan frit deploye hvad som helst til produktion.
Det er netop af sådanne elementer, at en professionel software delivery-proces opstår.
Den vigtigste ændring begynder med et andet spørgsmål
Virksomheder spørger ofte: "Hvor hurtigt kan vi skabe denne funktion?"
Det er værd at tilføje et andet spørgsmål: "Hvor hurtigt og sikkert kan vi levere de næste 50 funktioner?"
For en enkelt udrulning kan man gøre manuelt. Man kan endda manuelt deploye en applikation i flere år. Men i takt med at produktet, teamet, antallet af brugere og antallet af ændringer vokser, stiger også prisen for en sådan tilgang.
Derfor er CI/CD, automatiske tests, overvågning og kontrollerede deploymenter ikke kun løsninger for store virksomheder.
De er elementer i den procesinfrastruktur, der gør det muligt at udvikle software uden at tilføre unødvendig risiko til hver eneste nye ændring.
Og i sidste ende er det netop det, det handler om.
Ikke om 100 udrulninger om dagen.
Ikke om moderne værktøjer.
Ikke om den mest komplicerede pipeline.
Bare om muligheden for at sige:
"Vi har en ændring. Vi har tjekket den. Vi ved, hvad vi ruller ud. Vi ved, hvordan vi overvåger den. Og vi ved, hvad vi gør, hvis noget går galt."



