Kubernetes

Introduktion till Kubernetes

Vad Kubernetes löser när containrarna blir fler än en dator klarar

Hoppa till

Var vi är

I Docker-serien lämnade vi Lisa och teamet med ett e-handelssystem som startar med ett kommando: docker compose up. Frontend, API och databas ligger i varsin container, och alla i teamet får samma miljö.

Det fungerar på en dator. Sedan går applikationen live, kunderna blir fler, och systemet måste spridas över flera servrar. Då dyker en ny sorts frågor upp, och ingen av dem handlar om hur en container byggs.

Den här delen ger överblicken över vad Kubernetes är och vilka fyra begrepp du behöver för att läsa vilken introduktion som helst. Detaljerna kommer i senare delar.

Vad Kubernetes är

Kubernetes är ett system som kör containrar över flera servrar åt dig. Det förkortas ofta K8s — åtta bokstäver mellan K och s.

Du ger Kubernetes en beskrivning av vad som ska köras och i hur många kopior. Kubernetes väljer vilka servrar det ska köras på, startar om det som kraschar, och håller antalet rätt över tid.

Kubernetes bygger inte images. Det kör dem genom en container runtime, ofta containerd. Du kan bygga imagen med Docker eller ett kompatibelt verktyg; här använder vi Docker som den bekanta vägen från föregående serie.

Kubernetes vs Docker

De två ställs ofta mot varandra som alternativ. De är olika lager.

Docker paketerar en applikation till en image och kör den som en container — på en maskin.

Kubernetes tar färdiga images och kör dem som containrar över många maskiner, och håller reda på att rätt antal är igång.

Kubernetes ersätter alltså inte Docker. Docker Compose är fortfarande ett bra verktyg för lokal utveckling på en dator. Kubernetes kan ta över när samma system ska köras över flera maskiner i drift.

Deklarativt vs imperativt

Skillnaden är hela idén bakom Kubernetes, och den är värd att fästa direkt.

Imperativt betyder att du ber Kubernetes göra en konkret ändring: “sätt Deploymenten till tre kopior.” Kubernetes uppdaterar sedan sitt önskade läge och fortsätter hålla det.

Deklarativt betyder att YAML-filen säger hur det ska se ut: “det ska alltid finnas tre kopior av API:et.” Filen blir då den granskbara källan för önskat läge.

I båda fallen arbetar Kubernetes controllers mot det önskade läget. Skillnaden är var teamet beskriver och granskar förändringen.

Det är samma deklarativa idé som i Terraform-serien, med en skillnad: Terraform jämför när du kör apply, Kubernetes jämför oavbrutet.

Klustret

Ett kluster är de servrar Kubernetes har till sitt förfogande, hanterade som en enhet.

Varje server i klustret kallas en nod. En nod kan vara en fysisk maskin eller en virtuell — Kubernetes bryr sig inte om vilket.

Du pratar aldrig med en enskild nod. Du pratar med klustret, och klustret bestämmer var saker hamnar. Det är därför “vilken server körs den här på” är en fråga du sällan ställer.

Control plane pod pod pod pod pod pod Nod 1 Nod 2 Nod 3
Pilarna går bara åt ett håll — nedåt, från en låda till tre.

Control plane och noder

Klustret har två sorters delar.

Control plane är hjärnan. Den tar emot dina beskrivningar, bestämmer vilken nod som ska köra vad, och bevakar att verkligheten stämmer. Det är hit ditt kommando går.

Noderna är musklerna. De kör de containrar de blir tilldelade och rapporterar tillbaka hur det går.

I ett hanterat kluster hos en molnleverantör sköts control plane åt dig, och du ser bara noderna. Vad control plane består av internt — API-server, schemaläggare, en databas som heter etcd — behöver du inte kunna nu. Det räcker att veta att den finns och att det är den du talar med.

Pod

Den minsta enheten i Kubernetes är inte en container, utan en pod.

En pod är ett skal runt en eller några containrar som alltid ska köras på samma nod. Containrarna i en pod delar nätverk och lagring, och kan nå varandra på localhost.

I praktiken innehåller de flesta poddar exakt en container. Flera förekommer när en hjälpcontainer hör så tätt ihop med huvudcontainern att de aldrig får hamna isär — en som samlar in loggar, till exempel.

Pod vs container

En container är den körande instansen av en image. Det är samma sak som i Docker.

En pod är Kubernetes omslag runt en eller flera sådana containrar. Controllers schemalägger, ersätter och räknar poddar. Kubelet kan samtidigt starta om en container i samma pod när containerns process kraschar.

Därför heter kommandot kubectl get pods och inte kubectl get containers.

Poddar är tillfälliga

Det viktigaste att förstå med poddar är att de är utbytbara.

En pod startas, kör en stund och försvinner. När processen i en container kraschar kan kubelet starta om containern i samma pod.

När en pod som ägs av en Deployment tas bort eller avslutas skapar Deploymenten en ny pod i dess ställe, med nytt namn och ny IP-adress.

Det låter opraktiskt, men är själva poängen. När ingen enskild pod är viktig kan systemet flytta runt, byta ut och skapa fler av dem fritt. Att poddar är utbytbara är det som gör självläkning, skalning och utrullning utan driftstopp möjliga.

En pod är inte en server. Behandla den aldrig som en plats där något ska sparas.

Deployment

Om poddar är tillfälliga behöver något beskriva vad som alltid ska finnas. Det är en Deployment.

En Deployment säger vilken image som ska köras och i hur många kopior. Kubernetes jämför den beskrivningen med verkligheten, oavbrutet, och rättar skillnaden.

DeploymentBeskriver vad som alltid ska finnas: vilken image, hur många kopior.PodDet minsta Kubernetes hanterar. Tillfällig och utbytbar.ContainerDin applikation, startad ur precis den image du byggde i Docker-serien.
Noden — den server podden råkar köra på just nu
Tre nivåer, varje inuti den ovanför. Det är den här kedjan kubectl get pods visar dig ett utsnitt av.

Mellan Deployment och pod ligger egentligen ett lager till som heter ReplicaSet. Det är den som räknar kopiorna. Du skapar den aldrig själv och rör den sällan — men namnet dyker upp i utskrifter, så det är värt att känna igen.

Manifestet

En Deployment beskrivs i en YAML-fil, ett manifest.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: registry.example.com/searchapi:v2
          ports:
            - containerPort: 5000

Lisa känner igen sig: samma image från teamets registry som i Docker-serien, men med ett tillägg Docker Compose aldrig hade — replicas: 3.

Manifestet är en textfil. Den hör hemma i Git, granskas i en merge request och körs av en pipeline, precis som Terraform-filerna.

Fältet selector matchar etiketten app: api och är det som binder ihop Deployment med rätt poddar. Etiketter är genomgående hur Kubernetes hittar saker, och de återkommer i nästa begrepp.

Service

Om poddar hela tiden byter IP-adress — hur hittar frontend fram till API:et?

En Service ger en stabil adress framför en grupp poddar så länge Service-objektet finns kvar. Namnet api används för att nå den, och Servicen fördelar anropen mellan endpoints som Kubernetes markerat som redo.

Readiness-proben avgör när en pod ska räknas som redo. Servicen gör ingen egen hälsokontroll.

Frontend anropar http://api:5000 och behöver aldrig veta hur många poddar som finns bakom eller var de kör. En pod som startas läggs till i växeln på egen hand; en som försvinner plockas bort.

Frontend api:5000 pod pod borttagen Servicen
Pilen in är heldragen, pilarna ut är streckade. Skylten är det enda som står stilla.

Deployment vs Service

Två beskrivningar som ofta blandas ihop, eftersom de nästan alltid skrivs i par.

Deployment svarar på vad som ska köras och i hur många kopior.

Service svarar på hur något annat ska nå det.

Du behöver båda. En Deployment utan Service kör poddar som ingen kan nå på en stabil adress. En Service utan Deployment är en adress som pekar på ingenting.

kubectl

kubectl är kommandoradsverktyget du använder för att prata med klustret. Det uttalas oftast “kube-control”.

Kommandot skickar din begäran till control plane. Det gör alltså ingenting självt — utan ett kluster att tala med kan det bara läsa sin egen version.

kubectl apply -f api.yaml     # skicka in beskrivningen
kubectl get pods              # vad kör just nu?
kubectl describe pod api-7f9c # varför startar den?
kubectl logs api-7f9c         # vad skriver appen?

apply är deklarativ: du skickar in hur det ska se ut, inte vad som ska göras. Kör du samma fil igen utan ändringar händer ingenting, eftersom verkligheten redan stämmer.

Självläkning

Kubernetes har ingen förvald HTTP-fråga om din applikations hälsa. Definierar du en probe i manifestet kör kubelet den kontrollen.

Utan probe kan Kubernetes se containerstatus, men inte om just din applikation svarar som du tänkt.

Går en hel nod sönder flyttas dess poddar över till de noder som är kvar. Ingen behöver bli väckt, och ingen behöver skriva skriptet som gör det.

Hur frågan ställs — vilken adress som pingas och hur ofta — konfigureras med probes. Det tar vi i del 1.2. Här räcker det att veta att självläkningen bygger på att någon frågar.

Skalning

Inför rean höjer Lisa replicas från 3 till 10 och kör kubectl apply igen. Kubernetes startar sju poddar till, fördelade över noderna.

Det går också automatiskt: en regel som säger “kör fler poddar när processorlasten går över 70 procent” skalar upp under toppen och ner igen efteråt.

Samma mekanism kan ge utrullning utan driftstopp. Byter Lisa searchapi:v2 mot v3 rullar Deploymenten ut nya poddar enligt sin strategi.

Antalet som får saknas eller skapas extra styrs av exempelvis maxUnavailable och maxSurge. Med en readiness-probe får en ny podd trafik först när den är redo.

När du inte behöver Kubernetes

Den här delen hoppas ofta över, och den är den viktigaste. Kubernetes är inte gratis.

Hoppa över Kubernetes

En applikation på en server med jämn trafik — Docker Compose räcker, och du slipper ett helt lager att lära dig.

Ett hobbyprojekt eller en tidig produkt — en hanterad tjänst som Azure Container Apps ger dig utrullning och skalning utan att du driftar ett kluster.

Ett litet team utan driftserfarenhet — ett kluster ingen förstår är en risk, inte en trygghet.

Ta Kubernetes

Många tjänster, flera servrar, krav på tillgänglighet — då är Kubernetes rätt verktyg, och svårt att bygga bättre själv.

Signalen att titta efter: du har börjat bygga det själv. Skript som startar om kraschade containrar, fördelar trafik och håller reda på vilken server som har plats.

Då finns problemet på riktigt, och då är komplexiteten värd sitt pris.

Frågan är inte om Kubernetes är bra. Frågan är om du har problemet det löser.

Ett kluster innebär nätverk, behörigheter, certifikat, övervakning och uppgraderingar som någon måste förstå och underhålla. Tumregeln: börja med Docker och Compose, gå vidare den dag du märker att du håller på att bygga en sämre version av Kubernetes.

Vad det här betyder i ditt arbete

Som utvecklare kommer du sällan att sätta upp ett kluster. Du kommer att skriva manifest, läsa kubectl get pods, och felsöka med kubectl logs och kubectl describe.

Det som är värt din tid nu är alltså inte hur control plane fungerar internt. Det är att kunna läsa ett manifest och veta vilket av de fyra begreppen ett felmeddelande handlar om.

Är du på väg mot en driftsroll byter det skepnad. Då blir noder, nätverk, behörigheter och uppgraderingar ditt jobb — men ingen av de sakerna går att förstå innan pod, Deployment och Service sitter.

Vanliga nybörjarförväxlingar

Kubernetes ersätter inte Docker eller Docker Compose. Compose passar fortfarande lokal utveckling; Kubernetes passar när systemet ska köras över flera maskiner. Images kan byggas med Docker eller ett kompatibelt verktyg.

En pod är inte en container. Den är ett skal runt en eller flera, och det är poddar Kubernetes räknar och flyttar.

En pod är inte en server. När en Deployment ersätter podden får ersättaren nytt namn och ny IP.

kubectl är inte Kubernetes. Det är en klient som skickar begäran till ett kluster, och utan kluster kan den nästan ingenting.

Att köra kubectl apply två gånger gör inte saken två gånger. Beskrivningen jämförs med verkligheten, och stämmer den redan händer ingenting.

Prova själv

Första steget kräver inget kluster. Kontrollera att klienten finns:

kubectl version --client

Fråga sedan efter poddar:

kubectl get pods

Har du inget kluster får du ett fel om att anslutningen till servern nekades. Det är inte ett fel i installationen — det är hela poängen med avsnittet om kubectl. Det är en klient, och den har ingen control plane att fråga.

Vill du gå vidare: slå på Kubernetes i Docker Desktop under Settings → Kubernetes. Då får du ett kluster med en nod på din egen maskin.

kubectl get nodes

Nu svarar klustret med en nod, ofta med namnet docker-desktop. Spara manifestet ovan som api.yaml, byt ut image: mot något som faktiskt går att hämta — nginx duger — och kör:

kubectl apply -f api.yaml
kubectl get pods

Tre poddar, med namn som api-6d4cf56db-xk29p. Radera en av dem och fråga igen direkt:

kubectl delete pod api-6d4cf56db-xk29p
kubectl get pods

Det finns fortfarande tre. En av dem har ett nytt namn. Det är självläkningen, och det är det enskilt tydligaste beviset för att beskrivningen — inte kommandot — är det som styr.

Två saker som förvirrar: poddarna står först som ContainerCreating medan imagen hämtas, och kubectl get pods visar bara det aktuella namnrummet. Vad ett namnrum är tar vi i del 1.3, där det behövs för att sätta ett tak per team.

Kom ihåg
  • Kubernetes är deklarativt: du beskriver önskat läge, systemet håller det sant — oavbrutet.
  • Kubernetes ersätter inte Docker eller Docker Compose. Compose passar lokal utveckling.
  • En pod är minsta enheten och är tillfällig. En ersättningspodd får ett nytt namn och kan få en annan IP-adress.
  • En Deployment beskriver vad som alltid ska finnas. En Service ger det en fast adress.
  • Har du inte problemet många containrar på många servrar är Docker Compose fortfarande rätt svar.
Kolla att du hänger med
Ersätter Kubernetes Docker?
Nej. Docker kan bygga images och köra containrar på en maskin. Kubernetes kör images över många maskiner. Docker Compose passar fortfarande lokal utveckling, medan Kubernetes kan ta över i drift över flera maskiner.
Du raderar en pod med kubectl delete pod api-7f9c. Vad händer?
Deploymenten skapar en ersättningspodd med nytt namn och kan ge den en annan IP-adress. Om bara processen i en container kraschar kan kubelet i stället starta om containern i samma pod. Deploymenten håller sedan det önskade antalet poddar.
Om poddarna hela tiden byter IP-adress — hur hittar frontend till API:et?
Via en Service. Så länge Service-objektet finns kvar är namnet en stabil adress, och Servicen fördelar anropen mellan endpoints som Kubernetes markerat som redo. Frontend anropar http://api:5000 och behöver inte veta hur många poddar som finns bakom.
Vad är skillnaden mellan en Deployment och en Service?
Deployment beskriver vad som ska köras och i hur många kopior. Service beskriver hur något annat når det, via en adress som inte ändras. De skrivs nästan alltid i par.
Du kör kubectl apply -f api.yaml två gånger utan att ändra filen. Vad händer andra gången?
apply skickar beskrivningen igen. Om det önskade läget redan stämmer behöver Kubernetes normalt inte ändra arbetsbelastningen, men kommandot kan fortfarande rapportera att objektet konfigurerats.
När är Kubernetes fel verktyg?
När du inte har problemet det löser — en applikation på en server med jämn trafik, ett hobbyprojekt, eller ett team utan driftserfarenhet. Komplexiteten med nätverk, behörigheter, certifikat och uppgraderingar betalar sig först vid många tjänster på många servrar.

Snabb sammanfattning

  • Kubernetes kör images över flera servrar. Det bygger dem inte, och ersätter inte Docker Compose.
  • Kubernetes är deklarativt: du beskriver önskat läge, systemet håller det sant, oavbrutet.
  • Ett kluster är servrarna hanterade som en enhet. Varje server är en nod.
  • Control plane tar emot beskrivningar och bestämmer var saker körs. Noderna kör dem.
  • En pod är minsta enheten — ett skal runt en eller några containrar på samma nod.
  • Poddar är tillfälliga och utbytbara. En Deployment-ersättare får nytt namn och kan få en annan IP.
  • En Deployment beskriver vad som alltid ska finnas och i hur många kopior.
  • En Service ger poddarna en stabil adress medan Service-objektet finns och fördelar trafiken mellan redo endpoints.
  • kubectl är klienten. Utan kluster att fråga kan den nästan ingenting.
  • Har du inte problemet många containrar på många servrar är Docker Compose fortfarande rätt svar.

Nästa del

En mening lämnades hängande här: att frontend ska nås utifrån. En Service ger en adress inuti klustret — men hur når en besökare på internet ända fram till en pod?