Det pratas mycket om sådant som containers, docker, mikrotjänster och kubernetes med olika typer av managed services, men vad är detta egentligen? Här ska jag försöka gå igenom några av de begrepp som finns och vad de betyder. Om du inte redan märkt det så är nästan alla verktyg lite ordvitsigt döpta till sådant som har med havet, båtar och containers att göra. Detta är absolut inte en komplett lista över allt du stöter på, men det gör att du kanske får några av alla ord som flyger runt bland utvecklarna förklarade.
Mikrotjänst - microservice
En mikrotjänst är en programvarukomponent som är utformad för att utföra uppgifter inom ett område eller kategori och som är en del i ett system med flera mikrotjänster som kommunicerar med varandra. Man ska kunna byta ut en mikrotjänst utan att andra tjänster påverkas och det är här funktioner som kubernetes kommer in för att kunna styra över en massa mikrotjänster utan behov av en massa manuell övervakning och omstarter.
Mikrotjänster kommunicerar ofta med varandra med hjälp av en meddelandebuss som t.ex. Rabbit MQ, Kafka, Azure Service Bus eller andra liknande tjänster.
Tanken är att om en mikrotjänst behöver åtkomst till data i en databas så har den en egen databas i en databasserver och man delar inte anslutning till samma databas med flera olika tjänster.
Här är ett exempel där man har ett antal tjänster som kommunicerar med varandra men också exponerar information så att man komma åt dem via ett externt gränssnitt.
graph TD;
PROXY[Web proxy] --> SERVICE1[Kategoritjänst /service/categories]
PROXY --> SERVICE2[Produkttjänst /service/products]
PROXY --> SERVICE3[Pristjänst /service/prices]
SERVICE2 --> SERVICE1
SERVICE3 --> SERVICE2
Mikrotjänster använder ofta ett väldigt strikt sätt att använda HTTP-metoderna enligt så som de är tänkta att användas.
Sökväg | Method | Beskrivning |
---|---|---|
/service/prices | GET | Hämta en lista på samtliga priser. Ev avgränsningar skickas som parametrar till anropet som t.ex. ?num=10&sort=part_no |
/service/prices/1000 | GET | Hämta ett specifikt pris givet dess id som den sista delen av sökvägen. |
/service/prices | POST | Skapa en ny prispost i systemet där man skickar in det prisobjekt som skapas. |
/service/prices/1000 | PUT | Uppdatera ett specifikt pris där hela prisobjektet skickas och det befintliga ersätts |
/service/prices/1000 | PATCH | Uppdatera endast fält som skickas med och låt övriga uppgifter på prisposten vara kvar som de var |
/service/prices/1000 | DELETE | Radera en prispost givet dess identitet. |
Det som blir lite smart med mikrotjänster så här är att det är enkelt att lägga dem på baksidan av en proxy som tar emot samtliga anrop och sedan skickar dem vidare till rätt tjänst medan den som anropar tjänsterna inte känner till var gränserna går mellan tjänsterna.
Containers och docker
Principen med en container är att det ska vara som en liten dator som kör en och endast en tjänst med bara exakt det som behöver finnas på datorn för att funktionen ska fungera. Man ska kunna separera systemfiler och applikation från det data som behöver lagras. Skillnaden mellan en virtuell maskin och en container är att man kan köra flera containers i samma dator och att en container har möjlighet till eget nätverk och sina egna resurser. En container exponerar sedan tjänster till omvärlden antingen till ett nätverk eller till maskinen den kör på. Den vanligaste komponenten för att köra containers i en och samma dator är docker.
Nu var det nog ingen som blev klokare av den beskrivningen, så vi behöver nog plocka isär den lite ytterligare.
Docker
Den programvara du behöver för att kunna jobba med att köra en container på en dator är t.ex. docker. Det är en programvara som utnyttjar din dator eller virtuella dator för att köra en container. Med docker på din dator har du t.ex. en möjlighet att testa en programvara utan att installera en enda av delarna av den programvaran på din dator, den kan installeras helt och hållet i docker.
Man använder oftast kommandoradsverktyg för att styra docker. Om man använder docker utan att använda kubernetes finns det fina verktyg som t.ex. Portainer för att göra hanteringen av miljön enklare.
En docker image
Det här är en avbild som kan installeras i din docker som innehåller sitt eget filsystem och den programvara som behövs för att starta upp den inom ramen för docker. Innan man kan använda en image behöver man antingen ladda hem den från ett container registry eller bygga upp en definition på vad den ska innehålla med en så kallad Dockerfile. När man pekar ut en docker image så pekar man ut den givet ett container registry där den finns, en identitet på den den samt en versionstagg eller annan tagg för att avgöra vilken version och utgåva av en image som ska laddas ner.
Det finns massor av sätt att bygga en docker image, men när man jobbar med att utveckla programvara och vill köra en mikrotjänst så används ofta en Dockerfile som bestämmer vilken programvarukomponent som ska användas och vilka inställningar som ska gälla i den för uppstart etc.
Container registry
När det gäller docker finns det en gigantisk samling docker container images där man publicerar officiella utgåvor, då man om man inte anger en placering för var en docker image finns automatisk hämtar från docker hub (hub.docker.com).
Nu är det så att när man jobbar med sina egna tjänster kanske man inte vill lägga upp dem så att alla kan ladda ner dem, då finns det några alternativ att välja på för att ha ett privat register som man kan komma åt genom att peka ut det som en del i adressen till din docker container image.
- Github Registry är nog den absolut enklaste att komma igång med och som kommer både med en fri version och möjligheten att betala för sig. Här kan man hantera sina docker images, sina programvarupaket inom .NET-världen nuget eller javascriptpaket i NPM-formatet.
- Azure Container Registry om man använder devops i Microsofts värld, helt integrerad och mycket smidig att använda i sina flöden med devops och om man använder Microsofts tjänster för kubernetes eller att köra enstaka containers. Går utmärkt att använda externt också. Även här får man använda den rätt mycket innan det börjar kosta pengar.
- Google Container Registry är Googles alternativ. Smidigt att använda om man använder tjänster hos Google, men fungerar lika bra om du använder andra tjänster som behöver åtkomst.
- Docker private registry där du registrerar dig på docker hub och kan publicera dina egna docker images. Kostar från första byten.
- Finns ett helt gäng andra såklart i AWS, Digital Ocean men även möjligheten att köra sitt eget.
Kubernetes
Kubdernetes eller k8s som det ibland förkortas är en teknik som används för att styra en miljö med containers där själva kubernetes fixar funktionerna för att starta om när en tjänst går segt eller med funktioner för att automatiskt skala upp miljöerna. Med Kubernetes kommer det några fler begrepp att hålla reda på.
graph TD;
NS[Namespace] --> INGRESS[Ingress / proxy]
INGRESS --> SERVICE[Service]
NS --> SERVICE
INGRESS --> NODEPORT[Node Port]
SERVICE --> DEPLOYMENT[Deployment]
DEPLOYMENT --> IMAGE[Docker Image]
DEPLOYMENT --> VOLUME[Volymer]
DEPLOYMENT --> CONFIGMAP[Configuration map]
DEPLOYMENT --> SECRET[Secret]
Det som är lite speciellt med kubernetes är att oavsett hur noderna ser ut så ligger de alla i ett virtuellt nätverk som kan konfigureras olika baserat på önskemål och kravbild. Den kod som kör kommer inte behöva gå ut på utsidan klustret för att prata med en annan tjänst, de kan kommunicera internt då det i klustret ingår en DNS-tjänst som förenklar kommunikation mellan tjänster.
Control Plane
I en kluster med kubernetes behöver det finnas en del där man kör den administrativa funktionen som sköter noderna och deras tjänster. Det finns en möjlighet att använda den lösning som är open source som finns hos kubernetes.io . Denna tjänst passar såklart utmärkt att göra produkt av för våra stora leverantörer av infrastruktur i molnet och när man ska börja använda kubernetes är det verkligen mina starkaste rekommendationer att välja en av dessa lösningar för att styra din miljö.
- AKS - Azure Kubernetes Services är Micosofts lösning där man startar upp ett kuberneteskluster och har möjlighet att styra den och får ett gränssnitt dä rman kan få en överblick av som pågår i lösningen och sköta konfiguration av den i ett azuregränssnitt. Innehåller egentligen allt man behöver inklusive möjlighet att lägga en API-gateway framför för att kunna skapa förutsättningar för en stabil drift.
- GKE - Google Kubernetes Engine är Googles lösning som ligger i deras molntjänster. Den är väldigt smidig att använda då man i sina tjänster har en "Cloud Console" som gör att du har ett filsystem med en kodeditor och en kommandoprompt från vilken du kan styra alla dina tjänster.
- EKS - Amazon Web Services lösning med sin tjänst är nog den mest tekniska av tjänsterna som har väldigt många funktioner och är helt integrerad i hela AWS-lösningen. Kan vara lite klurig att komma igång med om man är ny både på AWS och Kubernetes, men när man fått ordning på alla säkerhetsprinciper och förstått vad man gett sig in i så är den väldigt tydlig och lätt att jobba med.
- Digital Ocean och ett antal andra har också lösningar som börjar väldigt priseffektivt om man ännu är tidigt i skedet med att jobba med containers.
Gemensamt för alla är att man styr dem med ett kommandoradsverktyg som heter kubectl, man använder alltså inte längre docker-kommandon när man kör i sammanhanget av ett kluster.
Pod
När man kör en tjänst i en kubernetesmiljö så kallas den instans som kör för en pod. Flera poddar kan köra samma programvara och klustret sköter automatiskt fördelningen av lasten till respektive pod.
Nodpool och noder
I en kubernetesmiljö så har man en eller några maskiner som kör den administrativa delen, sedan lägger man upp minst en pool med noder som de poddar som ska köras. En nodpool består av virtuella maskiner som är exakt likadana vad gäller minne, CPU, nätverk och disk. Man kan i en nodpool ange vilket som är det minsta antalet noder som ska vara igång och sedan om man aktiverar automatisk skalning växla upp dessa så att man kör på flera olika noder.
Ur ett driftperspektiv med lite erfarenhet i ryggen säger jag att man inte ska ha färre än två noder för att få en bra möjlighet att starta om komponenter utan att påverka sin driftmiljö t.ex. vid uppgraderingar.
Det går utmärkt att ha flera olika nodpooler.
graph TD;
KLUSTER[Kluster] --> NODEPOOL[Node pool]
KLUSTER --> ADMINPOOL[Node pool admin]
ADMINPOOL --> ADMINNODE1[Admin node 1]
NODEPOOL --> NODE1[Node 1]
NODEPOOL --> NODE2[Node 2]
NODEPOOL --> NODE3[Node 3]
NODEPOOL --> NODE4[Node 4]
Namespaces
I ett kluster finns det möjlighet att lagra flera uppsättningar applikationer och till med olika miljöer. För detta finns namespaces och varje objekt är unikt i kubernetes baserat på sitt namn och sitt namespace. Man kan t.ex. ha en webbsajten-dev, webbsajten-qa och webbsajten-prod i samma kluster och med samma tjänster men där de skiljer sig åt i namespace.
Deployment
Man ska för varje komponent man ska köra i ett kluster peka ut en deploymentbeskrivning som beskriver hur en miljö ser ut. Det är i en deployment man pekar ut en docker image, man styr upp vilken konfiguratom som ska gälla med miljövariabler, man styr väldigt mycket konfiguration med environmentvariabler. Man anger också i en sådan här deploymentbeskrivning hur många instanser som ska köra. Man kan peka ut länkar till konfiguration i config maps, i secrets eller koppla upp extern disk här. I slutändan publicerar en deploymentbeskrivning en applikation.
Filerna underhålls antingen i JSON-format eller YAML-format. Dessa kan antingen vara sådana man underhåller och skriver själv för hand, eller något man genererar genom att använda ett speciellt verktyg som t.ex. Helm eller kustomize.
Service
En service kopplar ihop en applikation med en definition av vilka tjänster som exponeras av applikationen och vilka av dessa som sedan ska exponeras ut på utsidan.
Det är sedan servicarna man jobbar med för att koppla samman i sin ingress. Jag brukar hantera både deploymant och service i samma fil.
Konfiguration i configmap
Det finns en fiffig del i kubernetes där man kan återanvända konfiguration över flera deployments så att man använder en och samma definition av deployment och service oavsett om det är en utvecklingsmiljö, en stagemiljö eller en produktionsmiljö.
Dessa kan man underhålla med en uppsättning per miljö eller så använder man ett verktyg som helm eller kustomize för att skapa dem utifrån mallar.
Det man ska tänka på med configmaps är att de innehåller är läsbara av alla som har åtkomst till klustret och det namespace i vilket de är upplagda i. Man använder det ofta för namn på databaser, urlar till tjänster och sådant som inte är hemligt, däremot lägger man inte connection strings eller känsligt data i en configmap.
Hemligheter i secrets
Funktionen för att lagra känsliga uppgifter som lösenord, connection strings till databaser eller andra miljöer är något man gärna hanterar i hemligheter. Här finns dels möjligheten med filer som i vart fall kräver en flerstegsövning för att komma åt ett lösenord, men kanske mer användbart möjligheten att lagra lösenord och uppkopplingsinformation i en key vault, t.ex. Azure Key Vault som kan användas så att man pekar ut en nyckel i ett nyckelvalv i konfigurationen och så löser AKS så att rätt nyckel når fram till den som behöver den i okrypterat format.
Volymer och claims till volymer och monteringspunkter
När man startar upp en pod kommer den att utgå från hur filsystemet ser ut från den image som den skapas utifrån. Om en pod skapas om kommer inget av det data som ligger lagrat i dess lokala filsystem att bli kvar. Därför har man möjligheten att montera in ett filsystem från klustret in i en deployment så att data och konfiguration ligger på ett centralt ställe i klustret oavsett på vilken nod en pod kör på.
Just volymer och delning av disk är något som lätt blir krånligt om man försöker köra ett kluster själv bara på kubernetes.io och som man sparar många timmar på att använda en av de tjänster som löser detta åt en. Det gäller egentligen både diskvolymer och nätverk.
I en pod för en webbserver vill man antagligen ha en katalog /var/www/html som ligger utanför podden, en konfigurationskatalog kanske /etc/nginx och en katalog där certifikaten ligger där själva webbservern bara har läsåtkomst till.
Ingres - klustrets proxy
Det här är där man exponerar tjänsterna ut mot utsidan och det är klustrets inbyggda funktion för proxy. I en konfiguration av en ingress så kan man styra vart ett anrop ska gå vanligtvis baserat på dess hostnamn eller sökväg.
I en ingress-konfiguration styr man till vilken tjänst trafiken ska skickas till.
De olika tjänsteleverantörerna har ofta sina egna lösningar för ingressen så att man får stöd för HTTPS-trafik, lastbalansering och kontroll av tjänsters tillgänglighet genom att ställa kontrollfrågor för att ta reda på om de är igång.
Man exponerar hela sin ingress med en nodeport som man får åtkomst till antingen från utsidan eller från någon av de tjänster som rent brandväggsmässigt har åtkomst till klustrets externa adresser.
Det är är ett stort område
För att kunna komma igång att jobba med containers, styrning av dem med kubernetes och hur man kopplar in det i devops är inget man gör på en eftermiddag. Det kräver planering och mycket arbete att få till det på ett bra vis.
Jag har själv testat tjänsterna hos samtliga de tre stora drakarna och har olika system som ligger hos var och en av de stora tre. Jag kan nog våga mig på att säga att den lösning som har den kortaste startsträckan och som har enormt mycket bra googlingsbart material på är den tjänsten från Google.
Passar allt att gå som containers?
Svaret på den frågan är nog olika beroende på vem man frågar. Själv har jag valt att lyfta in våra egna tjänster som ska kunna skala vertikalt genom att starta upp fler instanser som kan fördelas över flera noder.
Sådant som redan innehåller funktioner för klustring så som några av dessa tjänster kan fungera bra i traditionell datadrift med antingen en tjänst som infrastrukturleverantören hanterar eller att du kör dem som egna VPSer.
- Databasen, här finns det väldigt fina hanterade databaser med hög driftsäkerhet hos alla leverantörer.
- Meddelandebussen, den är så central och kan även ha ett behov av att vara tillgänglig utanför klustret så här kan det vara smidigt att lägga den på utsidan.
- Extern cache. Om man kör en redis för cache så finns det fina tjänster hos alla leverantörer att köra den på utsidan för att inte dra värdefull minneskapacitet ur klustret.
- Loggning och hantering av telemetri kan gärna också ske utanför klustret och det finns ofta fina funktioner inbyggda i de förpaketerade lösningarna för att hantera detta i plattformarnas lösningar.
Hur kommer man igång?
Om du är nyfiken på hur det fungerar med att börja jobba med mikrotjänster och kubernetes, ta gärna kontakt med oss på Jolix som lagt många timmar på att lära oss hur det fungerar och som gärna hjälper andra i rätt riktning. Boka ett möte och köp några konsulttimmar så kommer du igång snabbare än om du försöker göra allt själv.