Föreställ dig två utvecklingsteam.
Det första förbereder en ny version av applikationen.
Utvecklaren avslutar uppgiften. Någon granskar koden. Sedan måste testerna köras. Någon förbereder paketet. Någon annan loggar in på servern. Därefter måste några manuella steg utföras, konfigurationen kontrolleras och systemet övervakas efter driftsättning. Om allt går bra blir den nya versionen tillgänglig.
Det andra teamet arbetar på ett annat sätt.
Koden hamnar i repositoryt. Tester, kvalitetsanalys och säkerhetskontroller körs automatiskt. Systemet bygger applikationsversionen, driftsätter den till testmiljön, utför fler kontroller och kan efter uppfyllda villkor driftsätta den i produktion. Om något går fel stoppas driftsättningen eller så kan systemet gå tillbaka till den tidigare versionen.
Båda teamen utvecklar mjukvara.
Men bara ett av dem har byggt en repeterbar process för leverans av mjukvara.
Och det är just det som CI/CD handlar om.
"Fungerar i produktion" är ännu inte en mogen process
Många företag mäter framgång med ett mycket enkelt mått: applikationen fungerar.
Det är förstås ett grundläggande krav.
Men i takt med att systemet växer dyker fler frågor upp:
- Hur snabbt kan vi driftsätta en fix?
- Hur ofta kan vi publicera nya funktioner?
- Hur många manuella steg gör vi vid varje driftsättning?
- Kan varje utvecklare starta driftsättningsprocessen enligt samma regler?
- Vet vi vilken version som körs just nu?
- Kan vi gå tillbaka till den tidigare versionen?
- Kontrollerar vi automatiskt efter driftsättning att systemet fungerar korrekt?
- Har vi övervakning?
- Vet vi att driftsättningen orsakade ett problem innan kunden rapporterar det?
Det här är frågor om software delivery, inte bara om själva programmeringen.
CI och CD - två delar av en och samma process
CI, alltså Continuous Integration, betyder kontinuerlig integrering av ändringar.
I praktiken handlar det om att ändringar ofta ska hamna i det gemensamma repositoryt och automatiskt kontrolleras.
En typisk pipeline kan bland annat köra:
-
kompilering eller byggande av applikationen,
-
enhetstester,
-
integrationstester,
-
linting,
-
statisk kodanalys,
-
scanning av beroenden,
-
säkerhetskontroller,
-
byggande av driftsättningsartefakter.
På så sätt kan problem upptäckas innan koden når produktion.
CD, alltså Continuous Delivery eller Continuous Deployment, gäller nästa steg - att leverera förändringar.
Beroende på den valda modellen kan systemet förbereda en färdig version för driftsättning eller automatiskt driftsätta den efter att vissa kontroller har godkänts.
Det är en viktig skillnad.
Continuous Delivery behöver inte betyda att varje ändring automatiskt driftsätts i produktion.
Det kan helt enkelt betyda att varje version på ett repeterbart sätt förbereds för driftsättning.
Varför blir manuella driftsättningar ett problem?
Manuell driftsättning behöver inte vara dåligt.
I ett litet projekt kan det vara helt tillräckligt.
Problemet börjar när processen växer tillsammans med applikationen.
Först har vi en person som vet hur systemet ska driftsättas. Sedan tillkommer en andra server. Därefter testmiljön. Sedan databas, cache, köer, lagring, flera tjänster och externa API:er. Till det kommer olika konfigurationer för utveckling, test och produktion.
Efter några år kan processen se ungefär ut så här:
"Kör först X, ändra sedan parametern Y, starta därefter om tjänsten Z, men innan dess gör en säkerhetskopia av databasen. Och om ett fel uppstår, ring personen som driftsatte detta förra gången."
Det är inte längre en process. Det är kunskap gömd i en människas huvud. Och just då ökar risken.
Automatisering handlar inte bara om att göra livet enklare för utvecklare
Ofta presenteras CI/CD som ett verktyg som ökar utvecklarnas bekvämlighet. Det stämmer, men det är bara en del av bilden.
Automatisering av delivery ökar framför allt processens repeterbarhet.
Om en människa utför driftsättningen finns det en möjlighet att något görs lite annorlunda varje gång.
Om en pipeline gör det kan man definiera en exakt sekvens av steg.
Samma version.
Samma tester.
Samma kontroller.
Samma regler.
Detta är särskilt viktigt i projekt som utvecklas av flera personer eller flera team.
Tester före driftsättning är viktigare än hastigheten på driftsättningen
Automatisering utan tester kan bara göra att fel uppstår snabbare.
Därför bör en väl utformad pipeline inte bara vara en mekanism: "kod → produktion".
Den bör vara ett system för kvalitetskontroll.
Beroende på projektet kan den innehålla:
- Enhetstester - kontrollerar enskilda delar av logiken.
- Integrationstester - kontrollerar komponenternas samspel.
- End-to-end-tester - simulerar verkliga användarscenarier.
- Säkerhetstester - kontrollerar bland annat beroenden och kända sårbarheter.
- Prestandatester - behövs där det är viktigt att hantera en viss belastning.
Inte varje applikation behöver alla dessa lager i samma omfattning.
Och det är viktigt.
CI/CD handlar inte om att stoppa in så många verktyg som möjligt i pipelinen.
Det handlar om att anpassa kontrollerna till riskerna i det specifika systemet.
Vad händer när ett test inte går igenom?
Det är en av de viktigaste frågorna i hela processen.
En mogen pipeline bör ha tydligt definierade regler.
Om ett kritiskt test misslyckas ska versionen inte betraktas som redo för driftsättning.
Om en säkerhetsscanning upptäcker en viss risknivå kan pipelinen stoppa processen.
Om bygget inte lyckas finns det inget att driftsätta.
Det låter banalt. Men just sådana automatiska "grindar" gör att kvaliteten inte enbart beror på människans minne och noggrannhet.
Och om driftsättningen ändå misslyckas?
Även den bästa processen eliminerar inte alla fel. Därför är den andra delen av en mogen delivery möjligheten till kontrollerad återställning av ändringen.
Rollback kan betyda att man går tillbaka till den tidigare artefakten, containeravbilden eller applikationsversionen. Men här uppstår ett viktigt problem. Rollback av kod betyder inte alltid rollback av data.
Om den nya versionen har ändrat databasschemat blir situationen mer komplicerad.
Därför bör databasmigrationer utformas så att hela processen är så säker och reversibel som möjligt, eller åtminstone kompatibel med den tidigare versionen av applikationen.
Detta är ett av exemplen som visar att professionell CI/CD är ett arkitekturproblem, inte bara en konfiguration av ett verktyg.
Blue-green, canary och andra distributionsstrategier
I mer krävande system behöver man inte omedelbart flytta alla användare till den nya versionen. Man kan använda olika deploymentsstrategier.
Blue-green deployment
Två versioner av miljön körs parallellt.
Den ena hanterar trafiken, den andra förbereds för att ta över trafiken.
Efter en positiv verifiering sker växlingen.
Fördelen är möjligheten att snabbt återgå till den tidigare miljön.
Nackdelen kan vara högre infrastrukturförbrukning.
Canary deployment
Den nya versionen går först till en liten del av användarna eller trafiken.
Om övervakningen inte visar några problem kan utrullningens omfattning successivt ökas.
Detta begränsar den potentiella omfattningen av felet.
Det kräver dock lämplig infrastruktur, övervakning och ett sätt att hantera trafiken.
Feature flags
En funktion kan vara distribuerad till systemet men ändå förbli avstängd för användarna.
Tack vare detta blir koddistribution och aktivering av funktionalitet två separata processer.
Det ger större kontroll, särskilt vid större förändringar.
Det betyder dock inte att feature flags är en lösning för alla projekt. Deras överanvändning kan också öka systemets komplexitet.
Övervakning efter driftsättning
Man kan genomföra alla tester. Man kan ha en utmärkt pipeline. Man kan driftsätta en ny version utan något fel. Och några minuter senare kan applikationen börja bete sig annorlunda under verklig belastning.
Därför bör processen inte sluta vid deploymenten. Det behövs observability, alltså möjligheten att förstå vad som händer inuti det körande systemet.
Beroende på arkitekturen omfattar det bland annat:
-
loggar,
-
metriker,
-
spårning,
-
övervakning av infrastrukturen,
-
övervakning av applikationen,
-
larm,
-
information om fel,
-
affärsindikatorer.
Det handlar inte om att samla in allt. Det handlar om att kunna besvara viktiga frågor utifrån data.
Fungerar applikationen?
Fungerar den långsammare än tidigare?
Har antalet fel ökat?
Vilken tjänst orsakar problemet?
Berör problemet alla användare eller bara en del?
100 driftsättningar per dag är inte alltid målet
Rubriken på den här artikeln talar om 100 driftsättningar per dag, men det handlar inte om att sätta just det antalet som mål.
I ett internt system som uppdateras en gång i månaden finns det ingen mening med att konstlat sträva efter hundratals deploymenter. I ett system som utvecklas mycket intensivt kan en sådan frekvens däremot vara tekniskt möjlig.
Det viktiga är förmågan att leverera förändringar på ett säkert sätt, inte själva antalet driftsättningar. Detta är en grundläggande skillnad.
Processens mognad mäts inte av hur ofta vi driftsätter, utan av hur förutsägbart och säkert vi kan göra det.
När kan CI/CD bli mer form än innehåll?
Inte varje applikation behöver en komplicerad infrastruktur för deployment.
Om vi har en liten applikation, ett litet team och några få driftsättningar per år kan en omfattande pipeline kosta mer än de problem den löser.
Samma sak gäller mycket specifika system där driftsättningen kräver manuell kontroll av säkerhetsskäl, regler eller infrastrukturens karaktär.
Därför bör leveransarkitekturen utgå från systemets behov. Inte från trender.
När ger automatisering av driftsättning särskilt mycket?
Det är värt att överväga särskilt när:
-
systemet utvecklas regelbundet,
-
flera personer arbetar med koden,
-
det finns mer än en miljö,
-
driftsättningar är frekventa,
-
manuella driftsättningar genererar fel,
-
systemet är affärskritiskt,
-
vi behöver snabb rollback,
-
applikationen har många komponenter,
-
revisioner eller förändringsspår krävs,
-
tiden för att leverera en funktion är affärsmässigt viktig.
I sådana fall kan en väl utformad pipeline vara en av de viktigaste delarna i mjukvaruutvecklingsprocessen.
CI/CD reparerar inte dålig arkitektur
Detta är också värt att betona.
Man kan skapa en utmärkt pipeline för en dålig applikation.
Automatiskt testa dålig kod.
Automatiskt driftsätta dålig arkitektur.
Automatiskt skala ett dåligt utformat system.
Automatisering ersätter alltså inte arkitektur, tester eller teamets kompetens.
Den förstärker den befintliga processen.
Om processen är bra hjälper den att skala den.
Om processen är dålig kan den helt enkelt utföra dåliga saker snabbare.
Hur ser en mogen process ut?
Det finns ingen universell pipeline.
Men en mogen process bör ha några grundläggande egenskaper.
Repeterbarhet - driftsättningen genomförs enligt definierade steg.
Automatisering - maskiner utför så stor del som möjligt av det repetitiva arbetet.
Testbarhet - förändringar verifieras automatiskt.
Säkerhet - processen omfattar lämpliga säkerhetskontroller.
Observerbarhet - efter driftsättningen vet man vad som händer med systemet.
Återställbarhet - det finns ett planerat sätt att hantera en misslyckad förändring.
Spårning av förändringar - man vet vilken version som driftsattes och vad den byggdes från.
Åtkomstkontroll - inte vem som helst kan driftsätta vad som helst till produktion.
Det är just av sådana element som en professionell software delivery-process byggs upp.
Den viktigaste förändringen börjar med en annan fråga
Företag frågar ofta: "Hur snabbt kan vi skapa den här funktionen?"
Det är värt att lägga till en andra fråga: "Hur snabbt och säkert kommer vi att kunna leverera de nästa 50 funktionerna?"
En enskild driftsättning kan göras manuellt. Man kan till och med driftsätta en applikation manuellt i flera år. Men i takt med att produkten, teamet, antalet användare och antalet förändringar växer, ökar också kostnaden för detta tillvägagångssätt.
Därför är CI/CD, automatiska tester, övervakning och kontrollerade deploymenter inte bara lösningar för stora företag.
De är element i processinfrastrukturen som gör det möjligt att utveckla mjukvara utan att lägga till onödig risk i varje efterföljande förändring.
Och det är i slutändan just det som är poängen.
Inte 100 driftsättningar per dag.
Inte trendiga verktyg.
Inte om den mest komplicerade pipeline.
Utan om att kunna säga:
"Vi har en förändring. Vi har granskat den. Vi vet vad vi driftsätter. Vi vet hur vi övervakar den. Och vi vet vad vi gör om något går fel."



