Sammendrag
Hvordan oppnår man 100 % oppetid når koden endres daglig? Denne artikkelen tar for seg arkitekturen som kreves for å eliminere nedetid i forretningskritiske systemer. Vi bruker en anonymisert transformasjon av et ledende norsk teknologiselskap («NordFinans») som eksempel på hvordan monolittisk arv ble erstattet med moderne mikrotjenester.
Fokuset er den tekniske implementeringen av Zero Downtime Deployment (ZDD). Vi går i dybden på hvordan man konfigurerer Kubernetes, databaseskjemaer og applikasjonslogikk for å oppnå kontinuerlig leveranse uten avbrudd – uavhengig av om stacken din er bygget på PHP, Python, Go eller Node.js.
Bakgrunn: Frykten for deployering
Den gamle verden
Mange bedrifter kjenner seg igjen i situasjonen NordFinans stod i: En massiv monolittisk applikasjon som hadde vokst seg uhåndterlig. Distribusjonsprosessen var manuell, langsom og preget av høy risiko:
Vedlikeholdsvinduer: Oppdateringer krevde planlagt nedetid, typisk lagt til sene kvelder. Dette skapte frustrasjon for brukere som forventet døgnåpne tjenester, og slet ut utviklerne som måtte jobbe natt.
«Deployment Fear»: Fordi hver utrulling var en stor operasjon, ble de utsatt så lenge som mulig. Dette førte til en ond sirkel med enorme kodekonflikter og økt sannsynlighet for feil.
Ineffektiv skalering: Under trafikktopper måtte hele monolitten skaleres opp, selv om det kun var en liten del av systemet som var under press.
Målsettingen
For å møte dagens krav til tilgjengelighet, satte selskapet tre absolutte tekniske krav:
| Krav | Mål |
|---|---|
| Deployment Frequency | Fra månedlige til daglige utrullinger |
| Change Failure Rate | Under 1 % feilrate ved utrulling |
| True Zero Downtime | Ingen avbrutte sesjoner eller 5xx-feil |
Strategi: Hybrid CI/CD med GitLab og GitHub
For å balansere intern sikkerhet med ekstern tilgjengelighet, ble det valgt en hybrid strategi. Dette er en modell som passer godt for selskaper som både har proprietær kjernevirksomhet og offentlige integrasjoner.
GitLab: Kjernen for DevSecOps
GitLab (Self-Managed) ble valgt som primær plattform for intern kildekode og infrastruktur.
Hvorfor: GitLab tilbyr en komplett pakke med kildekode, CI-pipelines, container registry og sikkerhetsscanning (SAST/DAST) i ett lukket økosystem.
Kubernetes-integrasjon: Via GitLab Agent kan plattform-teamet styre tilganger granulært uten å eksponere sensitive tilgangsnøkler til utviklere.
GitHub: Ansiktet utad
Offentlige SDK-er og partner-integrasjoner lever på GitHub.
Hvorfor: GitHub er bransjestandarden for open-source.
GitHub Actions: Her brukes Actions for å kjøre offentlige tester og publisere pakker til registre som NPM, PyPI og Packagist.
Synkronisering
For å unngå fragmentering, fungerer GitLab som «Source of Truth». Kode speiles automatisk ut til GitHub, slik at utviklerne kun forholder seg til ett dashboard, mens koden lever to steder.
GitOps: Motoren under panseret
For å oppnå null nedetid, må man eliminere manuelle feilkilder. Manuell kjøring av kubectl apply ble derfor strengt forbudt til fordel for en ren GitOps-modell.
ArgoCD som trafikkpoliti
ArgoCD ble implementert for å synkronisere tilstanden i Git med tilstanden i Kubernetes-clusteret.
Pull-basert modell: I stedet for at CI-serveren «pusher» endringer til clusteret (noe som krever at CI-serveren har admin-tilgang til prod), «puller» ArgoCD endringer fra et eget manifest-repo.
Sikkerhet: Dette betyr at CI-systemet aldri har direkte tilgang til produksjonsmiljøet, noe som eliminerer en massiv angrepsflate.
Flyten fra kode til prod
- CI (Build): Utvikler pusher kode. Pipeline kjører tester, bygger Docker-image og scanner for sårbarheter.
- CD (Update): Hvis bygget er vellykket, oppdaterer CI-jobben versjonstaggen i et separat manifest-repo.
- Sync: ArgoCD oppdager endringen, kalkulerer differansen, og ruller ut endringen kontrollert i Kubernetes.
Teknisk dypdykk: Hvordan oppnå 100% oppetid?
Å bytte ut motoren på et fly mens det er i luften krever presisjon. Her er de spesifikke konfigurasjonene som gjør det mulig å rulle ut nye versjoner midt i arbeidstiden uten tapte forespørsler.
Rolling Update-strategien
Standardoppførselen til Kubernetes er en «Rolling Update», men standardinnstillingene er ofte for aggressive for kritiske applikasjoner. Strategien må justeres for å garantere kapasitet:
Graceful Shutdown: Løsningen på 502 Bad Gateway
Den vanligste feilen ved overgang til Kubernetes er å ignorere applikasjonens livssyklus. Når en pod skal dø, skjer to ting samtidig (asynkront):
- Kubernetes fjerner podens IP fra lastbalansererne.
- Kubernetes sender SIGTERM til containeren for å stoppe prosessen.
Problemet: Prosesser som Nginx, Go-binærer eller Node.js stopper ofte raskere enn det tar for Kubernetes å oppdatere nettverksreglene i hele clusteret. Resultatet? Trafikk sendes til en pod som nettopp har dødd. Brukeren ser «502 Bad Gateway».
Probes: Helsekontrollens kunst
Liveness Probe: «Er jeg i live?». Sjekker om prosessen kjører. Best Practice: Skal være enkel. Ikke sjekk database-tilkobling her! Hvis databasen går ned, vil alle podene restarte samtidig i en evig loop.
Readiness Probe: «Er jeg klar til å motta trafikk?». Best Practice: Sjekk om applikasjonen faktisk kan gjøre jobb (f.eks. db-kobling ok, cache varm). Hvis denne feiler, tas poden ut av trafikkflyten uten å restartes.
Databasen: Den største utfordringen
Kode er flyktig, men data er persistente. Hvordan oppdaterer man et databaseskjema uten å låse tabeller eller krasje den gamle versjonen av koden som fortsatt kjører under en utrulling?
Løsningen er mønsteret Expand-Contract (Parallel Change).
Fase 1: Expand (Utvid)
Skal vi endre navn på en kolonne fra address til billing_address? Vi legger til den nye kolonnen, men beholder den gamle. Vi ruller ut koden. Nå eksisterer begge kolonnene.
Fase 2: Migrate (Dual Write)
Applikasjonen oppdateres til å skrive til begge kolonner, men lese fra den nye. Et bakgrunnsskript flytter gamle data.
Fase 3: Contract (Trekk sammen)
Når vi er sikre på at alle pods kjører ny kode som bruker billing_address, fjerner vi den gamle kolonnen i en siste migrering.
Dette krever disiplin, men garanterer at databasen aldri er «ute av synk» med noen versjon av applikasjonen som kjører live.
Applikasjonsnivå: Klargjøring for skyen
Uavhengig av om applikasjonen er skrevet i PHP, Python, Go eller Node.js, krever et «Zero Downtime»-miljø at applikasjonen følger 12-factor-prinsippene.
Konfigurasjon og Miljøvariabler
I et dynamisk cluster kan man ikke stole på .env-filer som endres på disk. All konfigurasjon må injiseres som Environment Variables fra Kubernetes ConfigMaps og Secrets.
- Node.js/Python/Go: Leser direkte fra miljøet (
process.env/os.environ). - PHP: Sørger for at konfigurasjon cachet under bygget (build time) ikke inneholder hardkodede stier som endrer seg i produksjon.
Kø-systemer og Serialisering
En ofte oversett felle er asynkrone jobber (RabbitMQ, Redis, Kafka). Når en ny versjon deployes, kan det ligge jobber i køen som er serialisert med den gamle kodestrukturen. Hvis en worker med ny kode plukker opp en gammel jobb-payload, kan applikasjonen krasje.
Løsning: Bruk versjonerte køer, eller sørg for at job-payloads alltid er bakoverkompatible. Ved store endringer («breaking changes») må køen tømmes (draining) før oppdatering.
Resultater og Forretningsverdi
Implementeringen av denne arkitekturen ga følgende resultater:
Deployment Frequency: Økte fra månedlig til 8.5 ganger per dag. Utviklere deployer nå små endringer kontinuerlig.
Lead Time: Redusert fra 5 dager til 45 minutter (fra commit til produksjon).
Tilgjengelighet: Oppnådde 99.99% oppetid det første året, selv gjennom store refaktoreringer.
Kultur: «Deployment-frykten» forsvant. Tirsdag kveld er ikke lenger «vakt-kveld», men frikveld.
Konklusjon
Null nedetid er ikke magi, og det er heller ikke noe man får «gratis» bare ved å velge Kubernetes. Det er resultatet av en bevisst arkitektonisk strategi som kombinerer robuste CI/CD-pipelines, deklarativ infrastruktur (GitOps) og en dyp forståelse av applikasjonens livssyklus.
For bedrifter som ønsker å konkurrere i et marked som krever 24/7 tilgjengelighet, er investeringen i denne arkitekturen ikke bare en IT-kostnad, men en fundamental forretningsfordel.
Hos PXL hjelper vi ambisiøse selskaper med å modernisere sin deployment-strategi. Vi har bred erfaring med å sette opp skalerbare, feiltolerante miljøer for applikasjoner bygget i alt fra PHP og Python til Go og Node.js. Vi bistår med hele reisen – fra containerisering og CI/CD-design til Kubernetes-drift og overvåkning.
