Azure DevOps fyller fortsatt en sentral rolle i 2026 for team som bygger på Microsofts skyplattform, og Azure Pipelines er motoren som binder kode, testing og utrulling sammen. Denne guiden viser hvordan du setter opp en komplett CI/CD-pipeline fra bunnen, fra Azure Repos til en kjørende container i Azure Kubernetes Service (AKS). Du får kode du kan lime rett inn, en prisoversikt for 2026, og en liste over feil som stopper nye pipelines før de kommer i produksjon.
Guiden er skrevet for utviklere og driftsteam som allerede har et Azure-abonnement, men som ikke har bygget en full pipeline til Kubernetes før. Vi bruker YAML-baserte pipelines, ikke det gamle klassiske grensesnittet, fordi det er standarden Microsoft anbefaler for nye prosjekter.
Hva er Azure DevOps og Azure Pipelines i 2026
Azure DevOps er en samling tjenester fra Microsoft: Boards for oppgavestyring, Repos for kildekode, Pipelines for bygg og utrulling, Test Plans for testhåndtering, og Artifacts for pakkelagring. Azure Pipelines er den delen som kjører byggejobber og deployerer kode, og den støtter både Microsoft-hostede agenter og dine egne selvhostede maskiner.
En pipeline defineres i en YAML-fil som ligger i selve kodelageret. Det betyr at pipelinen versjoneres sammen med koden, og endringer i bygge- eller utrullingslogikken går gjennom samme kodegjennomgang som resten av prosjektet. Strukturen bygger på tre nivåer: stadier (stages), jobber (jobs) og steg (steps). Stadier kan kjøre i sekvens eller parallelt, jobber kan kjøre på forskjellige agenter, og steg kjører i rekkefølge inne i en jobb.
I mars 2026 rullet Microsoft ut en oppdatert visning kalt Stages i Azure Pipelines, med artefakt-ID-er og stadiebasert oversikt over hver utrulling, ifølge Sprint 271-oppdateringen fra Microsoft Learn. Endringen gjør det lettere å se nøyaktig hvilken artefakt som ble deployert til hvilket miljø, noe som tidligere krevde manuell sporing i loggene.
For team som drifter containere, er koblingen mellom Azure Pipelines og Azure Kubernetes Service (AKS) det mest brukte mønsteret i 2026. Pipelinen bygger et image, pusher det til et register, og bruker en Kubernetes-spesifikk oppgave til å oppdatere klyngen. Denne guiden dekker nettopp den kjeden, fra tom Azure DevOps-organisasjon til en kjørende pod i en ekte AKS-klynge, med et rollback-stadium på toppen som de fleste innføringsguider hopper over.
Forutsetninger: verktøy, kontoer og versjoner
Før du starter, sjekk at du har følgende på plass. Manglende rettigheter er den vanligste årsaken til at guider som denne stopper allerede i steg 1.
- Et Azure-abonnement der du har rollen Owner eller Contributor
- En Azure DevOps-organisasjon (det gratis nivået holder for hele denne guiden)
- Azure CLI, nyeste versjon, installert lokalt eller i Cloud Shell
- kubectl, i en versjon som ligger innenfor ett minor-versjonstrinn fra AKS-klyngen din
- Docker Desktop eller Docker Engine, nyeste stabile versjon
- Git installert lokalt, samt en konto med skriverettigheter til Azure Repos eller GitHub
- En enkel applikasjon å containerisere. Eksemplene i denne guiden bruker en Node.js-tjeneste, men prinsippene er identiske for .NET, Python eller Java
- Grunnleggende kjennskap til YAML-syntaks (innrykk styrer alt)
Sett av rundt 60 minutter til hele oppsettet hvis du følger stegene i rekkefølge, inkludert tid for at AKS-klyngen skal bli klar (dette tar normalt 5 til 10 minutter).
Steg 1: Opprett Azure DevOps-organisasjon og prosjekt
Gå til dev.azure.com og logg inn med samme konto du bruker i Azure-portalen. Klikk “New organization” hvis du ikke har en fra før, og gi den et navn som følger firmaets navnekonvensjon. Inne i organisasjonen klikker du “New project” og oppretter et prosjekt, for eksempel “aks-demo”. Velg Git som versjonskontroll og Agile som arbeidsprosess, med mindre teamet allerede bruker noe annet.
Et privat prosjekt får automatisk én gratis Microsoft-hostet parallell jobb med 1 800 minutter per måned, tilsvarende 30 timer, ifølge Microsofts dokumentasjon for hostede agenter. Hver enkelt jobbkjøring kan normalt vare opp til 60 minutter. Dette er nok til demoen i denne guiden, men et team med flere daglige bygg bør regne med å måtte kjøpe flere parallelle jobber etter noen ukers bruk.
Steg 2: Installer og konfigurer Azure CLI og kubectl
Logg inn med Azure CLI og velg riktig abonnement før du gjør noe annet. Feil abonnement valgt her er en klassisk kilde til at ressurser dukker opp i feil miljø senere.
az login
az account list --output table
az account set --subscription "Ditt-Abonnement-Navn-Eller-ID"
# Installer kubectl via Azure CLI hvis du ikke har det
az aks install-cli
Bekreft at begge verktøyene fungerer med az version og kubectl version --client. Hvis kommandoene feiler med “command not found”, er det nesten alltid en PATH-variabel som ikke er satt riktig etter installasjonen, spesielt på Windows.
Steg 3: Opprett en AKS-klynge og et Container Registry
Neste steg er infrastrukturen pipelinen skal deployere til. Opprett en ressursgruppe, en AKS-klynge og et Azure Container Registry (ACR). Vi kobler registeret direkte til klyngen slik at AKS kan hente images uten ekstra autentisering.
az group create --name rg-aks-demo --location norwayeast
az acr create --resource-group rg-aks-demo \
--name akscidemoregistry --sku Basic
az aks create --resource-group rg-aks-demo \
--name aks-demo-cluster \
--node-count 2 \
--generate-ssh-keys \
--attach-acr akscidemoregistry
az aks get-credentials --resource-group rg-aks-demo \
--name aks-demo-cluster
Kommandoen --attach-acr setter opp rolletildelingen mellom AKS og ACR automatisk, så du slipper å håndtere en egen pull-secret manuelt. Region “norwayeast” er valgt for lav ventetid mot norske brukere, men velg samme region som resten av arkitekturen din ligger i.
Hvis klyngen kjører en eldre nodeavbildning, er det verdt å sjekke node-OS-versjonen før produksjonsbruk. AKS sluttet å levere sikkerhetsoppdateringer for Azure Linux 2.0 fra 30. november 2025, og noder som fortsatt kjører denne avbildningen bør oppgraderes før pipelinen settes i produksjon. Vi går gjennom flere AKS-relaterte sikkerhetshull i avsnittet om AKS-sårbarheter senere i artikkelen.
Steg 4: Push kildekoden til Azure Repos
Med infrastrukturen på plass er det tid for koden. Opprett et lokalt Git-repository hvis du ikke har et, koble det til Azure Repos, og push første commit.
git init
git remote add origin https://dev.azure.com/DinOrg/aks-demo/_git/aks-demo
git add .
git commit -m "Initial commit"
git push -u origin main
Legg til en enkel Dockerfile i rotmappen hvis appen ikke har en fra før. For en Node.js-tjeneste holder det med et minimalt oppsett basert på et offisielt Node-image, med EXPOSE for riktig port og en CMD-linje som starter serveren. Denne filen er det pipelinen bygger fra i steg 8.
Steg 5: Opprett en tjenestetilkobling til Azure
Pipelinen trenger en identitet for å få lov til å bygge images i ACR og deployere til AKS. Dette løses med en tjenestetilkobling (service connection). Gå til Project Settings, deretter Service connections, og velg “Azure Resource Manager”. Velg autentiseringsmetoden “Workload identity federation (automatic)” der det er tilgjengelig i organisasjonen din, siden den unngår langlevde hemmeligheter.
Begrens tilkoblingen til ressursgruppen rg-aks-demo i stedet for hele abonnementet. Dette er et av de enkleste tiltakene du kan gjøre for å redusere skaden hvis en pipeline eller et prosjekt blir kompromittert. Gi tilkoblingen et gjenkjennelig navn, for eksempel sc-aks-demo, siden du refererer til det senere i YAML-filen.
Steg 6: Skriv build-stadiet i YAML
Opprett en fil kalt azure-pipelines.yml i rotmappen. Første stadie installerer avhengigheter og kjører byggeprosessen. Trigger-blokken sørger for at pipelinen kjører automatisk ved push til main.
trigger:
- main
pool:
vmImage: ubuntu-latest
variables:
acrName: akscidemoregistry
imageName: aks-demo-app
stages:
- stage: Build
jobs:
- job: BuildAndUnitTest
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Installer Node.js'
- script: npm ci
displayName: 'Installer avhengigheter'
- script: npm run build
displayName: 'Bygg applikasjon'
Bruk npm ci i stedet for npm install i pipelinen. Kommandoen leser låsefilen direkte og feiler hvis den ikke stemmer med package.json, noe som fanger opp avhengighetsdrift langt tidligere enn en vanlig install ville gjort.
Steg 7: Skriv teststadiet i YAML
Legg til et testjobb-steg som kjører etter bygget. Sett dependsOn slik at teststadiet ikke starter før bygget er ferdig, og publiser testresultatene slik at de vises i Azure DevOps-grensesnittet.
- stage: Test
dependsOn: Build
jobs:
- job: RunTests
steps:
- script: npm ci
- script: npm test -- --reporter=junit --reporter-option output=test-results.xml
displayName: 'Kjør enhetstester'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: 'test-results.xml'
condition: always()
condition: always() er avgjørende her. Uten den blir testresultatene aldri publisert når testene feiler, og du sitter igjen med en rød pipeline og ingen informasjon om hvilken test som faktisk brøt.
Steg 8: Bygg og push Docker-image til ACR
Nå bygger vi selve container-imaget og pusher det til registeret. Bruk build-ID som tag i stedet for latest. Dette er et av punktene erfarne team er strengest på, fordi det avgjør om du faktisk kan rulle tilbake til en tidligere versjon senere.
- stage: PublishImage
dependsOn: Test
jobs:
- job: BuildAndPushImage
steps:
- task: Docker@2
inputs:
containerRegistry: 'sc-acr-connection'
repository: '$(imageName)'
command: 'buildAndPush'
Dockerfile: '**/Dockerfile'
tags: |
$(Build.BuildId)
Tjenestetilkoblingen sc-acr-connection må opprettes separat for ACR, adskilt fra den generelle Azure Resource Manager-tilkoblingen fra steg 5, siden Docker-tasken forventer en registerspesifikk tilkobling. Du finner denne under Service connections med typen “Docker Registry”.
Steg 9: Deploy containeren til AKS
Siste hovedstadie tar imaget vi nettopp bygget og ruller det ut til AKS-klyngen med en Kubernetes-manifest-fil. Sørg for at manifestet ligger i en manifests/-mappe i repositoriet, med en deployment.yml og en service.yml.
- stage: DeployToAKS
dependsOn: PublishImage
jobs:
- deployment: DeployWeb
environment: 'production'
pool:
vmImage: ubuntu-latest
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
inputs:
action: 'deploy'
kubernetesServiceConnection: 'sc-aks-demo'
namespace: 'production'
manifests: |
manifests/deployment.yml
manifests/service.yml
containers: |
akscidemoregistry.azurecr.io/$(imageName):$(Build.BuildId)
Legg merke til at vi bruker et deployment-jobbobjekt, ikke et vanlig job. Det gir tilgang til miljøer (environments) og godkjenningssteg, som vi setter opp i neste avsnitt. Kubernetes-tjenestetilkoblingen sc-aks-demo opprettes på samme måte som ACR-tilkoblingen, men med typen “Kubernetes Service Connection” pekende mot AKS-klyngen din.
Steg 10: Flertrinns-miljøer og godkjenninger
En pipeline som går rett fra kodepush til produksjon uten menneskelig kontroll er en risiko de fleste driftsteam ikke bør ta. Gå til Pipelines, deretter Environments, og opprett et miljø kalt “production”. Legg til en godkjenner (approval check) på miljøet, slik at en utrulling stopper og venter på manuell godkjenning før den treffer klyngen.
For team med flere miljøer, kopier DeployToAKS-stadiet og lag et separat staging-miljø uten godkjenningskrav, og et production-miljø med krav om minst én godkjenner. Sett dependsOn: DeployToStaging på produksjonsstadiet, slik at koden alltid går gjennom staging før den kan nå produksjon. Dette mønsteret er det som gir størst effekt for lavest innsats blant alle tiltakene i denne guiden.
Godkjenningen selv konfigureres under miljøets “Approvals and checks”. Legg til minst én, helst to, personer som kan godkjenne, slik at en utrulling ikke stopper opp fordi eneste godkjenner er på ferie. Sett også en tidsavbrudd, for eksempel 24 timer, slik at en glemt godkjenning ikke blokkerer pipelinen på ubestemt tid. Mange team legger i tillegg til en “Branch control”-sjekk her, som krever at koden kommer fra main-grenen før produksjonsmiljøet i det hele tatt tillater en utrulling, uavhengig av hva som står i selve YAML-filen.
Steg 11: Hemmeligheter, variabelgrupper og Key Vault
Hemmeligheter skal aldri ligge direkte i YAML-filen. Opprett en variabelgruppe under Pipelines, deretter Library, og marker sensitive verdier som “secret” der. For større organisasjoner er det bedre å koble variabelgruppen til Azure Key Vault, slik at hemmeligheter administreres ett sted og roteres uavhengig av pipeline-koden.
variables:
- group: 'production-secrets'
steps:
- script: |
echo "Kobler til database med brukt hemmelighet, men logger aldri verdien"
env:
DB_PASSWORD: $(dbPassword)
Unngå å bruke echo $(dbPassword) eller lignende debug-linjer, selv midlertidig. Azure Pipelines maskerer kjente hemmelighetsvariabler i loggen, men maskeringen er ikke garantert å fange opp hemmeligheter som blir omformet, delt opp eller sendt videre som kommandolinjeargumenter til andre verktøy.
Steg 12: Triggere, branch-policyer og overvåking
Siste steg handler om å beskytte selve prosessen rundt pipelinen. Gå til Repos, deretter Branches, og sett en branch-policy på main som krever minst én godkjent pull request og en grønn pipeline-kjøring før merge er tillatt. Aktiver også “Build validation” slik at PR-en kjører pipelinen automatisk før den kan merges.
For overvåking, aktiver e-postvarsling eller en webhook mot Slack eller Teams for mislykkede kjøringer på main-grenen. Et vanlig feiltrinn er å varsle om alle kjøringer, inkludert utviklerens egne feature-grener, noe som fort fører til at teamet ignorerer varslene helt. Begrens varslingsregelen til grener som faktisk går mot produksjon.
Legg til et rollback-stadium for mislykkede utrullinger
Selv en godt testet pipeline vil av og til deployere noe som feiler i produksjon på en måte testene ikke fanget opp. Et rollback-stadium som kan trigges manuelt sparer deg for stress midt i en hendelse. Fordi vi allerede tagger images med $(Build.BuildId), kan vi peke tilbake på en tidligere, kjent god build.
- stage: Rollback
condition: failed()
dependsOn: DeployToAKS
jobs:
- deployment: RollbackWeb
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
inputs:
action: 'deploy'
kubernetesServiceConnection: 'sc-aks-demo'
namespace: 'production'
manifests: 'manifests/deployment.yml'
containers: |
akscidemoregistry.azurecr.io/$(imageName):$(previousStableBuildId)
condition: failed() gjør at stadiet kun kjører hvis det forrige stadiet faktisk feilet, ikke ved hver kjøring. Variabelen previousStableBuildId må settes manuelt eller hentes fra en lagret verdi fra siste vellykkede kjøring, siden Azure Pipelines ikke sporer dette automatisk for deg.
AKS-sikkerhet i pipelinen: unngå disse hullene
En pipeline som deployerer til AKS arver også ansvaret for klyngens sikkerhetstilstand. Microsoft har i 2026 publisert flere sikkerhetsbulletiner for AKS, blant annet AKS-2026-0003, som beskriver en lokal rettighetseskalering i Linux-kjernens algif_aead-modul (CVE-2026-31431), offentliggjort 29. april 2026. Svakheten lar en pod eskalere til root på den underliggende noden, selv uten spesielle capabilities i pod-spesifikasjonen.
Konsekvensen for pipelinen din er konkret: nodebilder og kjerneversjon må oppdateres regelmessig, ikke bare containerimaget. Sett et fast intervall for å kjøre az aks nodepool upgrade eller aktiver automatisk node-image-oppgradering i klyngen. Vi går mer i detalj på AKS-spesifikke sårbarheter i vår tidligere gjennomgang av en AKS-sårbarhet med CVSS 9,4, som er relevant lesning for team som drifter egne noder.
Hvis du vurderer AKS mot alternativene, er en direkte sammenligning av kostnad og funksjoner mellom EKS, AKS og GKE et naturlig neste steg før du låser arkitekturen for et nytt prosjekt.
Hva koster Azure Pipelines i 2026?
Prisstrukturen for Azure Pipelines er uendret i kjernen gjennom 2025 og 2026, men den er lett å misforstå fordi begrepet “parallell jobb” beskriver samtidighet, ikke antall minutter eller antall registrerte agenter. Tabellen under viser de offisielle prisene fra Microsoft.
| Type | Gratis nivå | Pris utover gratis nivå | Tidsbegrensning |
|---|---|---|---|
| Microsoft-hostet, privat prosjekt | 1 jobb, 1 800 min/mnd | 40 USD/jobb/mnd | Maks 60 min per kjøring |
| Microsoft-hostet, offentlig prosjekt | Opptil 10 jobber | Ikke nødvendig for de fleste | Maks 360 min per kjøring |
| Selvhostet agent | 1 jobb, ubegrenset tid | 15 USD/jobb/mnd | Ingen Microsoft-satt grense |
| Azure Artifacts | 2 GiB lagring | Fakturert per GiB utover | Ikke tidsbegrenset |
Kilde: Azure DevOps Services Pricing og Microsofts dokumentasjon for parallelle jobber.
Parallelle jobber kjøpes på organisasjonsnivå og deles av alle prosjekter i organisasjonen. Det betyr at et stort bygg i ett prosjekt kan spise opp hele det gratis kvantumet og legge kø for et helt urelatert prosjekt i samme organisasjon. Fakturering skjer normalt fordelt jevnt over måneden, med en trettien-dels sats per dag, ifølge Azure DevOps sine faktureringsspørsmål. For et norsk team betyr det at listeprisene over er i amerikanske dollar, og faktisk faktura kan avvike på grunn av valutakurs, merverdiavgift og avtalevilkår hos Microsoft-forhandleren.
Visual Studio Enterprise-abonnenter i organisasjonen påvirker også det gratis kvantumet for selvhostede jobber. Ifølge Microsofts egen dokumentasjon legges det til én ekstra gratis selvhostet parallell jobb per aktivt Visual Studio Enterprise-medlemskap i organisasjonen, i tillegg til grunnjobben alle får. For et team med flere slike lisenser kan dette i praksis dekke behovet for selvhostet kapasitet helt uten ekstra kostnad, og det er verdt å sjekke lisensoversikten før man går til innkjøp av flere parallelle jobber.
6 vanlige fallgruver ved oppsett av Azure Pipelines
De fleste problemene med nye Azure Pipelines-oppsett følger et gjenkjennelig mønster, uansett om teamet kommer fra Jenkins, GitLab CI eller ingen tidligere pipeline i det hele tatt. Feilene handler sjelden om selve YAML-syntaksen, og nesten alltid om antakelser som stemte i et annet verktøy, men ikke i Azure Pipelines. Her er de vi ser gå igjen oftest.
- Å blande CI-trigger med utrullingsgodkjenning. En trigger validerer at koden bygger og passerer tester. Selve utrullingen bør styres separat med miljøer og godkjenninger, ikke av samme betingelse som trigget bygget.
- Å anta at hostede agenter husker installerte verktøy. Hver kjøring på en Microsoft-hostet agent starter fra et rent image. Verktøy installert manuelt i forrige kjøring er borte i neste, og må installeres på nytt i pipelinen selv eller via et egendefinert image.
- Å bruke
latestsom image-tag. Uten en unik tag per build vet ingen med sikkerhet hvilken kode som faktisk kjører i produksjon, og rollback blir tilfeldig i stedet for presist. - Å lekke hemmeligheter via logger. Verbositet i skript, utskrift av hele Kubernetes-manifester, eller hemmeligheter sendt som kommandolinjeargumenter kan omgå Azure Pipelines sin automatiske maskering.
- Å gi tjenestetilkoblingen for mye tilgang. En tilkobling med rettigheter på hele abonnementet, når den bare trenger tilgang til én ressursgruppe, øker skadepotensialet dramatisk hvis en pipeline-konfigurasjon eller en avhengighet blir kompromittert.
- Å ikke rydde opp på selvhostede agenter. Vedvarende arbeidsmapper, mellomlagrede credentials og Docker-sockets som deles mellom jobber kan la en jobb påvirke en annen, spesielt farlig for pipelines som bygger pull requests fra eksterne bidragsytere.
Feilsøking: 8 vanlige feil og løsninger
Når en pipeline feiler, er feilmeldingen ofte kryptisk. Denne tabellen dekker de feilene vi oftest ser i nye AKS-orienterte pipelines, og hvor du bør lete etter roten til problemet. Start alltid med å åpne det enkelte steget som feilet, ikke bare det generelle stadiet, siden Azure Pipelines samler mye detaljert informasjon i et eget undernivå som er skjult som standard.
| Feil | Vanligste årsak | Løsning |
|---|---|---|
| “No hosted parallelism has been purchased or granted” | Gratis nivå er ikke aktivert for organisasjonen | Be om aktivering via Microsofts kontaktformular, eller kjøp en parallell jobb |
| Docker@2-steget feiler med “unauthorized” | Feil eller manglende ACR-tjenestetilkobling | Opprett en dedikert Docker Registry-tilkobling, ikke bare en generell ARM-tilkobling |
| KubernetesManifest@1 finner ikke navnerommet | Namespace opprettet aldri i klyngen | Kjør kubectl create namespace production manuelt før første kjøring |
| Image pull-feil i AKS-podder | ACR ikke koblet til klyngen med --attach-acr | Kjør az aks update --attach-acr på eksisterende klynge |
| Pipeline finner ikke YAML-filen | Filen ligger ikke i roten, eller feil filnavn er angitt i pipeline-oppsettet | Bekreft sti under Pipelines, deretter Edit, og sjekk YAML-file-path-innstillingen |
| Godkjenningssteget vises aldri | Jobben bruker job i stedet for deployment | Endre jobbtype til deployment og koble den til et miljø |
| Hemmelighet vises som tom streng i loggen | Variabelgruppen er ikke lenket til pipelinen | Legg til variables: - group: 'gruppenavn' i YAML-filen |
| Testresultater vises ikke i fanen “Tests” | PublishTestResults@2 mangler, eller kjører kun ved suksess | Legg til tasken med condition: always() |
Avanserte tips for produksjonsklare pipelines
Når grunnoppsettet fungerer stabilt, er det noen forbedringer som gir stor effekt for relativt lav innsats. Legg pipeline-logikken i en delt mal (template) i et separat repository hvis flere prosjekter deler samme bygge- og deployeringsmønster. En sentral mal for byggetrinn, sikkerhetsskanning og signering reduserer duplisering og gjør det enklere å rulle ut sikkerhetsforbedringer til alle prosjekter samtidig.
Pin viktige task-versjoner der reproduserbarhet betyr noe, som KubernetesManifest@1 eller AzureCLI@2, i stedet for å anta at en oppgaves oppførsel aldri endrer seg innenfor samme hovedversjon. På samme måte er ubuntu-latest et bevegelig image, ikke en fast operativsystemversjon. Pipelines i produksjon bør sjekke image-endringer periodisk, og heller pinne et konkret image hvis verktøykjeden er sårbar for uventede oppdateringer.
Bruk canary- eller blue-green-mønstre for utrulling til AKS når trafikkmengden rettferdiggjør det. En enkel variant er å deployere til et andre sett podder bak samme Service, og gradvis flytte trafikk over med en Ingress-kontroller. Kubernetes sin egen dokumentasjon om Deployment-objektet beskriver hvordan rullerende oppgraderinger fungerer under overflaten, noe som er nyttig å forstå før du bygger mer avanserte utrullingsstrategier på toppen.
Sett også en fast rutine for å gå gjennom hvor mange parallelle jobber organisasjonen faktisk bruker versus hvor mange som er kjøpt. Ubrukt kapasitet her er ren bortkastet kostnad, mens for lite kapasitet skaper kø og frustrerte utviklere som venter på byggejobber sent på ettermiddagen.
Sett en oppbevaringspolicy (retention policy) på både bygg og utrullinger. Uten en grense vokser artefaktlagringen ukontrollert, og gamle, ubrukte images blir liggende i ACR og koste lagringsplass. Et vanlig oppsett er å beholde de siste 30 vellykkede byggene og slette resten automatisk, samtidig som byggene som faktisk er deployert til produksjon merkes og unntas fra opprydding.
Legg til en enkel skanning av avhengigheter og container-image som eget steg før PublishImage-stadiet, slik at kjente sårbarheter fanges opp før imaget noen gang når produksjon. Dette krever ikke en stor sikkerhetsplattform for å ha verdi. Selv en enkel skanner som feiler bygget ved kritiske funn er bedre enn ingen skanning i det hele tatt, og gir deg et konkret tidspunkt i pipelinen der sårbarheter kan stoppes før de sprer seg videre til klyngen.
Kjør selvhostede agenter direkte inne i AKS-klyngen
Et mønster flere team går over til i 2026 er å kjøre de selvhostede agentene som podder inne i samme AKS-klynge pipelinen deployerer til. Dette kutter nettverksventetiden mellom agent og klynge nesten helt bort, og gjør det enklere å style agentens ressursbruk med de samme kvotene og nettverkspolicyene som resten av arbeidslastene i klyngen.
Den enkleste tilnærmingen er å kjøre den offisielle Azure Pipelines-agenten som en Deployment i et eget namespace, dedikert til CI/CD, adskilt fra applikasjonsnavnrommene. Registrer agentpoolen i Azure DevOps under Project Settings, deretter Agent pools, og hent tilkoblingstoken derfra.
kubectl create namespace devops-agents
kubectl create secret generic azp-token \
--from-literal=AZP_TOKEN='DITT-PERSONLIGE-TILGANGSTOKEN' \
--from-literal=AZP_URL='https://dev.azure.com/DinOrg' \
--from-literal=AZP_POOL='aks-selvhostet-pool' \
-n devops-agents
kubectl apply -f azp-agent-deployment.yml -n devops-agents
Denne tilnærmingen krever litt mer driftsarbeid enn å bruke Microsoft-hostede agenter, siden du selv må holde agent-imaget oppdatert og overvåke ressursbruken. Til gjengjeld unngår du kaldstart-tiden som følger med hostede agenter, og kan skalere antall agenter opp og ned med en Horizontal Pod Autoscaler basert på kølengde, i stedet for å betale for flere parallelle jobber hos Microsoft. For team som allerede kjører store AKS-klynger med ledig kapasitet, er dette ofte den mest kostnadseffektive veien når byggevolumet vokser forbi det som dekkes av 15 dollar per ekstra selvhostede jobb.
Pass på isolasjonen mellom agent-poddene. En agent som bygger kode fra eksterne pull requests bør aldri dele node med arbeidslaster som har tilgang til produksjonshemmeligheter, siden en kompromittert avhengighet i byggeprosessen i verste fall kan lese ut alt agentpodden har tilgang til på samme node.
Azure DevOps vs. GitHub Actions: hva bør du velge?
Valget mellom Azure Pipelines og GitHub Actions kommer sjeldent ned til en enkelt funksjon. Azure DevOps er tettere integrert med Boards, Repos, Test Plans og Artifacts, og passer godt for organisasjoner som allerede styrer prosjekter gjennom Azure-økosystemet med Entra ID-baserte tilganger. GitHub Actions er tettere vevd inn i GitHub-repositoriet selv, med pull request-integrasjon, miljøer og et stort marketplace av forhåndsbygde actions.
| Kriterium | Azure DevOps Pipelines | GitHub Actions |
|---|---|---|
| Naturlig integrasjon | Azure-ressurser, Entra ID, Boards | GitHub-repositorier, pull requests |
| Kostnadsmodell for ekstra kapasitet | 40 USD/mnd (hostet), 15 USD/mnd (selvhostet) | Varierer med runner-type, ikke dekket i denne prisoversikten |
| Styringsverktøy | Boards, Test Plans innebygd | Prosjektstyring via tredjeparts- eller GitHub Projects |
| Utvidelser | Azure DevOps Marketplace | GitHub Marketplace, større økosystem |
Det finnes ikke noe pålitelig, direkte sammenlignbart tall for markedsandel mellom de to plattformene i Norden per 2026, siden ulike kilder måler repositorier, organisasjoner eller kjøringer, som ikke er sammenlignbare størrelser. Et fornuftig utgangspunkt for de fleste team er derfor å velge basert på hvor koden allerede ligger, ikke basert på antatte adopsjonstall. Ligger koden i Azure Repos eller er organisasjonen allerede tungt investert i Azure-styring, gir Azure Pipelines minst friksjon. Ligger koden i GitHub, er GitHub Actions det mer naturlige valget.
Validering før produksjonssetting
Før du kobler pipelinen til en reell branch-policy, kjør en full test-runde manuelt. Push en liten, ufarlig endring, som en kommentar i koden, og følg kjøringen gjennom alle stadier: bygg, test, image-push, utrulling til staging, godkjenning, og utrulling til produksjon. Bekreft at podden faktisk kjører ny kode med kubectl get pods -n production og kubectl describe pod for å se image-tag på den kjørende containeren.
Test også rollback-stadiet med en villet feil, for eksempel en syntaksfeil i et manifest, slik at du vet stadiet faktisk trigges og fungerer før du trenger det i en reell hendelse klokken tre om natten. Et rollback-stadium som aldri er testet er i praksis udokumentert kode, og bør ikke stoles på i en krisesituasjon.
Legg gjerne inn en enkel røyktest (smoke test) som eget steg rett etter DeployToAKS, i stedet for å stole blindt på at “successfully rolled out” betyr at applikasjonen faktisk svarer riktig. Et minimalt HTTP-kall mot et helse-endepunkt, med en kort ventesløyfe og noen få forsøk, fanger opp tilfeller der podden starter og blir klar, men applikasjonen inni likevel krasjer ved første forespørsel. Dette steget koster noen sekunder ekstra per kjøring, men det er ofte det som skiller en pipeline teamet stoler på fra en pipeline ingen tør å lene seg på når det haster.
Eksempel: slik ser en vellykket kjøring ut
Det er lettere å feilsøke en pipeline når du vet hvordan en frisk, vellykket kjøring faktisk skal se ut i loggen. Under Build-stadiet vil du typisk se noe i denne stilen i konsollvisningen til Azure Pipelines.
Starting: Installer Node.js
==============================================================================
Tool: node 20.x
Task : Node.js tool installer
Version : 0.246.1
==============================================================================
Node 20.11.1 hentet og lagt til PATH
Finishing: Installer Node.js
Starting: Installer avhengigheter
==============================================================================
> npm ci
added 412 packages in 9.821s
Finishing: Installer avhengigheter
##[section]Async Command Start: Bygg applikasjon
> npm run build
webpack 5.x compiled successfully in 4102 ms
##[section]Async Command End: Bygg applikasjon
Når DeployToAKS-stadiet kjører, bekrefter KubernetesManifest@1-oppgaven utrullingen med en oppsummering som ligner på dette:
##[section]Starting: Deploy to Kubernetes
deployment.apps/aks-demo-app configured
service/aks-demo-app unchanged
##[section]Async Command Start: Check rollout status
Waiting for deployment "aks-demo-app" rollout to finish: 1 of 2 updated replicas are available...
deployment "aks-demo-app" successfully rolled out
##[section]Finishing: Deploy to Kubernetes
Linjen “successfully rolled out” er det viktigste tegnet på at utrullingen faktisk fullførte, ikke bare at manifestet ble sendt til API-serveren. En pipeline kan rapportere grønt selv om podden aldri blir klar, hvis du ikke sjekker rollout-status eksplisitt. Kjør alltid kubectl get pods -n production som et ekstra sjekkpunkt hvis du er usikker på om oppgaven faktisk venter på en vellykket utrulling.
Det komplette pipeline-oppsettet samlet i én fil
Stegene over bygger opp filen stykke for stykke, men i et ekte prosjekt ligger alt i én sammenhengende azure-pipelines.yml. Under følger hele filen samlet, slik den ser ut når byggestadiet, teststadiet, image-bygget, utrullingen til AKS og rollback-stadiet er satt sammen til ett komplett, kjørbart prosjekt.
trigger:
- main
pool:
vmImage: ubuntu-latest
variables:
acrName: akscidemoregistry
imageName: aks-demo-app
stages:
- stage: Build
jobs:
- job: BuildAndUnitTest
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: npm ci
- script: npm run build
- stage: Test
dependsOn: Build
jobs:
- job: RunTests
steps:
- script: npm ci
- script: npm test -- --reporter=junit --reporter-option output=test-results.xml
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: 'test-results.xml'
condition: always()
- stage: PublishImage
dependsOn: Test
jobs:
- job: BuildAndPushImage
steps:
- task: Docker@2
inputs:
containerRegistry: 'sc-acr-connection'
repository: '$(imageName)'
command: 'buildAndPush'
Dockerfile: '**/Dockerfile'
tags: |
$(Build.BuildId)
- stage: DeployToAKS
dependsOn: PublishImage
jobs:
- deployment: DeployWeb
environment: 'production'
pool:
vmImage: ubuntu-latest
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
inputs:
action: 'deploy'
kubernetesServiceConnection: 'sc-aks-demo'
namespace: 'production'
manifests: |
manifests/deployment.yml
manifests/service.yml
containers: |
akscidemoregistry.azurecr.io/$(imageName):$(Build.BuildId)
- stage: Rollback
condition: failed()
dependsOn: DeployToAKS
jobs:
- deployment: RollbackWeb
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
inputs:
action: 'deploy'
kubernetesServiceConnection: 'sc-aks-demo'
namespace: 'production'
manifests: 'manifests/deployment.yml'
containers: |
akscidemoregistry.azurecr.io/$(imageName):$(previousStableBuildId)
Denne filen, sammen med en Dockerfile og manifestene i manifests/-mappen, er alt som trengs for å kjøre hele kjeden fra kodepush til overvåket produksjonsutrulling i AKS. Legg til variabelgruppen fra steg 11 og godkjenningen fra steg 10 direkte i Azure DevOps-grensesnittet, siden de styres utenfor selve YAML-filen.
Ofte stilte spørsmål
Er Azure DevOps gratis å bruke?
Ja, for mindre team. Hvert privat prosjekt får en gratis Microsoft-hostet parallell jobb med 1 800 minutter per måned og en selvhostet parallell jobb med ubegrensede minutter. Kostnaden dukker først opp når teamet trenger flere samtidige kjøringer enn det gratis nivået tillater.
Hvor lang tid tar det å sette opp en full pipeline til AKS?
For et team som følger stegene i denne guiden, bør 60 minutter være realistisk for et grunnleggende oppsett med bygg, test, image-push og utrulling til ett miljø. Legg til 15 til 20 minutter ekstra hvis du også setter opp staging-miljø og godkjenninger.
Må jeg bruke YAML, eller kan jeg bruke det klassiske grensesnittet?
Klassiske pipelines fungerer fortsatt, men Microsoft anbefaler YAML for alle nye prosjekter, siden det versjoneres sammen med koden og er lettere å gjenbruke via templates. Nye funksjoner prioriteres også for YAML-baserte pipelines først.
Hvordan unngår jeg at hemmeligheter lekker i byggeloggen?
Lagre hemmeligheter i en variabelgruppe merket som secret, eller koble gruppen til Azure Key Vault. Unngå å skrive ut variabler i debug-formål, og vær bevisst på at maskering av kjente hemmeligheter ikke fanger opp verdier som blir omformet eller delt opp før de skrives til loggen.
Kan jeg bruke selvhostede agenter for å spare kostnad?
Ja, en selvhostet parallell jobb koster 15 USD per måned mot 40 USD for en ekstra Microsoft-hostet jobb, og har ingen Microsoft-satt tidsgrense per kjøring. Du tar da selv ansvar for oppdatering, sikkerhet og drift av maskinen agenten kjører på.
Hva gjør jeg hvis pipelinen kjører kø i lang tid?
Sjekk først om organisasjonen har nok parallelle jobber til antall samtidige kjøringer teamet faktisk trenger, siden dette kjøpes på organisasjonsnivå og deles mellom prosjekter. Hvis kapasiteten er riktig, se etter én stor pipeline som blokkerer andre, og vurder å dele den opp i mindre, mer parallelle stadier.
Bør jeg deployere direkte til produksjon uten staging?
Det anbefales ikke for de fleste team. Et staging-miljø som speiler produksjon, kombinert med en manuell godkjenning før produksjonsutrulling, fanger opp feil som tester ikke dekker, uten å bremse leveransehastigheten nevneverdig.
Kan jeg bruke samme pipeline til flere AKS-klynger?
Ja. Bytt ut den enkelte kubernetesServiceConnection-verdien med en variabel som settes per stadie, og opprett en egen tjenestetilkobling per klynge. Dette er den vanligste måten å håndtere flere miljøer på tvers av regioner eller kunder, uten å måtte vedlikeholde en separat YAML-fil for hver klynge.
