DevOps-labbar: Docker
Förberedelser
DevOps
Följande labbar handlar om den tekniska sidan av DevOps.
Det är i sammanhanget värdefullt att påminna om att DevOps egentligen är ett begrepp som beskriver en kultur som främjar att utvecklare själva kan ta ansvar för driften av det de skapar så att de snabbt och effektivt får insikt i driftproblem med de tjänster de skapat - så att de kan förebygga driftstörningar snarare än att reaktivt fixa dessa i efterhand.
Docker
Dessa labbövningar är koncentrerade runt verktyget Docker som är ett verktyg för att paketera ihop körbara isolerade instanser av allt som behövs för en tjänst att fungera - och bara exponera just detta.
Innan du börjar
- Ladda hem och installera Docker Desktop till din dator om du inte redan har det installerat.
- Ladda hem och installera git till din dator om du inte redan har det.
- Skapa en lokal katalog som heter DevOpsHackaton eller liknande.
- Öppna en kommandoprompt och gå till den nyskapade foldern.
- Hämta hem labb-repositoryt antingen genom att klona ner det från GitHub eller ladda hem som zip-fil och zippa upp det lokalt i din skapade lokala folder.
Det finns även en medföljande PowerPoint, som egentligen är tänkt att förklaras igenom, men kanske hjälper den någon?
För att klona ner repositoryt från GitHub används kommandot:
git clone https://github.com/kejsardamberg/docker-hackaton.git
.
Lab
Skapa en image för en webbserver
Denna övning syftar till att skapa en image med en enkel webbserver. Den byggs på en image med webbservern httpd
.
Likt alla webbservrar serverar den innehåll över HTTP som använder standardport 80.
httpd hämtar det content den serverar från sin egen katalog /usr/local/apache2/htdocs/ så för att vi ska ha något att visa från vår webbserver behöver vi lägga in en fil där. I denna övning används en fil (/lab1/index.html från den filsamling som hämtades i förra steget.
Tanken med övningen är att öva på att skapa en första Dockerfile och få den körklar med både portexponeringsinstruktioner och filkopiering.
- Starta Docker Desktop så att Docker-daemons är igång.
-
Hämta hem en grund-docker-image som innehåller en webbserver (t.ex. med
docker pull httpd
). -
Skapa en fil med namnet Dockerfile (utan punkt eller filändelse) i rooten på den filstruktur du hämtade hem via git eller zip i förra steget.
Om det redan ligger en Dockerfile där kan du istället använda denna som bas.
Se till att den som bas-image använder den image du hämtade hem i steget innan (httpd) och sedan kopierar filen
/lab1/index.html
till imagens servers publicerade web-root-katalog (/usr/local/apache2/htdocs/). - Bygg en egen docker-image utifrån denna Dockerfile (utan punkt eller filändelse).
- Studera output från byggandet i din konsol. Vad gör Docker när den bygger? Hur lång tid tar det?
- Kontrollera status på images i det grafiska användargränssnittet i Docker Desktop.
-
Använd kommandot
docker images
i en kommandoprompt för att se en listning på de images som din docker har tillgängliga. -
Vad får din image för namn om du inte själv uttalat tilldelar den ett namn (eller tag, med
docker build -t <namn>
? - Bygg en image med namnet lab1-image från din Dockerfile.
Användbara instruktioner i Dockerfile kan vara t.ex. FROM
, COPY
och EXPOSE
.
Användbara styrkommandon i kommandofönstret kan vara docker build
och docker images
.
Man kan alltid skriva --help
efter kommandot för att se vilka extra växlar/attribut man kan lägga på kommandot.
docker pull httpd
för att ladda hem en enkel linux-kärna med en Apache webbserver på.
Den Dockerfile du skapar ska ligga i rooten på ditt relevanta filträd och kan se ut som så här:FROM httpd COPY /lab1/index.html /usr/local/apache2/htdocs/ EXPOSE 80Bygg en ny anpassad image med
docker build -t lab1-image .
(säkerställ att få med den sista punkten också).
Lab
Starta en container från din image från förra labben
I denna labb startar och stoppar vi en docker-container och lär oss hantera denna både i Docker Desktop och från kommandoprompten.
Den image vi skapade i förra steget exponerar port 80 för HTTP, men vi vill mappa om denna eftersom port 80 möjligen redan är upptagen i host-datorns OS.
Eftersom vi kan skapa flera containers (t.ex. flera likadana frontend-servrar) från samma image så mappar vi portar när vi startar containern.
Man startar en container genom att ange vilken image den baseras på.
För att undvika ett generiskt namn på den kan du använda attributet --name
enligt t.ex. docker run --rm -dit --name lab1-container -p 8080:80 lab1-image
.
-p 8080:80
är den parameter som mappar containerns port 80 till host-datorns port 8080
- Starta en container av den image du skapade i förra labben och säkerställ att du med en webbläsare kan nå den fil du lade in i webbservern.
-
Googla skillnaderna mellan
docker start
ochdocker run
. De låter snarlika men har olika beteende. -
Undersök även vad
docker run --rm
gör som inte vanligadocker run
gör. -
Se efter hur körläget ser ut i det grafiska gränssnittet i Docker Desktop, och från kommandoprompten genom att där skriva
docker images
(som visar status för images). - Prova att starta och stoppa din container från Docker Desktop.
-
Använd kommandoprompts-kommandot
docker ps
för att se vilka containers som körs. - Prova gärna att starta en container till så att du har två containrar av samma image igång, men på olika portar. Detta kan vara användbart vid t.ex. lastbalansering.
-
Surfa därefter med en webbläsare till
https://localhost:8080
och se så att du ser samma fil som ligger i katalogen /lab1/index.html.
Vill man se alla containers, även de som inte körs, kan man se dessa med docker ps -a
. Detta kan vara användbart om man vill städa upp och ta bort containers.
docker run --rm -dit --name lab1-container -p 8080:80 lab1-image
.
Lab
Städa bland containers och images
Snart när man jobbar med containers och images blir det stökigt och många av dessa och man behöver städa. Man kan vara väldigt osentimental med containers (och faktiskt även images) eftersom man sparar receptet för att skapa nya sådana i Dockerfile och i docker-compose.
I denna labb ska vi därför prova att stoppa körande containers och sedan ta bort både containers och images. Vi har ju redan ritningen för infrastrukturen klar och kvar i vår Dockerfile så containers och images är inte något att vara nostalgisk över.
För att stänga ner eller ta bort images eller containrar refererar man till dem med deras ID eller namn.
- Städa bort de images och containers som inte längre används.
docker images
och docker ps -a
.Det kan också vara bra att känna till kommandot
docker stop
, docker remove
och docker image rm
.
Lab
Docker i Visual Studio Code
Docker kan vara väldigt användbart under tiden man utvecklar kod. Man kan köra sin applikation direkt i Visual Studio Code - för testmiljöer och liknande.
- Installera Visual Studio Code om du inte redan har den installerad.
- Öppna Visual Studio Code.
- Lägg till extension Docker och Docker Explorer om du inte redan har dessa installerade.
- Notera hur det finns en Docker-ikon i vänstermarginalen. Klicka på denna. Vad ser du?
- Högerklicka på de entrys du ser. Vad har du för val?
- Om du nu öppnar katalogen lab5-restserver i Visual Studio Code kan du direkt komma åt Docker både i GUI och genom VS Codes inbyggda terminal.
Lab
Simpel REST-server
Statiska filer har ju begränsat användningsområde.
Nu ska vi fyra igång en enkel webbserver med möjlighet till mer dynamiskt beteende.
Denna server baseras på Alpine Linux och Node.js och finns färdig i lab5.
Denna gång kör vi en Linux och en specifik version av Node.js.
-
Börja med att hämta en ny image för en slim Linux med Node.js:
docker pull node
. Om du vill ha en specifik version av node.js anger du vilken, t.ex.:17-alpine
. - Gå till katalogen lab5-restserver och studera den Dockerfile som finns där. Vad kommer denna image att göra när den byggs?
- Prova att bygga en image från den Dockerfile som finns i katalogen
lab5-restserver
. - Starta containern och använd webbläsaren för att hämta serverns enkla JSON-data.
Detta funkar ganska smidigt, och går relativt snabbt. Men när vi ändrar något är det krångligt att omdistribuera en ny image och ny container. Det finns smidigare sätt: Volumes (som vi ska träna på i kommande labb).
Det går också att trimma tiderna betänkligt genom att ändra ordningen så att mindre data läses över till imagen och mer är cachat av Docker.
Du kan behöva se över sökvägar när du bygger en image från denna Dockerfile.
Du kan behöva mappa om IP-portar när du kör denna som en container.
Lab
Den användbara filen .dockerignore
När vi bygger koden för vår lilla REST-server från förra labben så hämtas beroenden och läggs in i en underkatalog till vår filkatalog. Som vår Dockerfile är utformad så kopierar den hela innehållet i denna katalog till vår image. Då följer ju dessa beroenden med, vilket är onödigt eftersom de ändå hämtas hem i bygget.
Vi kan undvika detta genom att skapa en .dockerignore-fil i samma katalog som vår Dockerfile.
Filen .dockerignore fungerar ungefär som en .gitignore för git och har samma syntax, men för Docker istället för git.
- Skapa en fil som heter .dockerignore (lägg märke till den inledande punkten) i samma katalog som din Dockerfile.
- Öppna filen .dockerignore och lägg till raden
node_modules
i filen. - Spara och stäng filen.
- När du nu bygger en ny image med denna fil utelämnas det som angivits i .dockerignore-filen oavsett om det är en katalog som anges eller en specifik fil.
- Bygg denna image och starta en container och noter hur lång tid det tar och vilka steg som docker anger är cachade (vilket syns i output).
Lab
Optimerad cachning
Ett av dockers huvudnummer är att det är snabbt och smidigt och välpaketerat. Om det tar för lång tid i anspråk att jobba med docker förlorar det lite av sitt existensberättigande.
Samma server som i föregående lab kan fås att funka betydligt snabbare om man ändrar lite i Dockerfile.
- Öppna katalogen lab8-cachning och jämför dess Dockerfile med den i föregående övning. Vilka skillnader finns?
- Jämför vilka steg som nu är cachade med den föregående övningen. Nu ska det gå liiite snabbare.
Lab
Koppla in lokala kataloger som Volumes till din container
Det är ju ändå tråkigt att behöva bygga om image och starta container för varje förändring. Det finns stöd i Docker som gör detta förfarande onödigt.
I denna övning gör vi oss befriade från att behöva kopiera in filen i docker-containern och länkar istället in en katalog från host-maskinen som att den vore en katalog inne i docker-containern. Containern tycker att den katalogen alltså finns internt på servern medan den egentligen finns på host-maskinen.
Det gör det enkelt att ändra i filer utan att behöva starta om containern.
För denna labb använder vi också ett tillägg till vår Node.js. Detta tillägg gör att Node.js automatiskt startar om denna när den känner av förändringar i sina filer.
- Öppna katalogen lab10-volumes och studera dess Dockerfile.
- Starta upp en container baserat på denna och prova att göra en HTTP GET med en webbläsare.
- Ändra nu något data i filen app.js och ladda om sidan.
I detta upplägg ska resultatet ha ändrats direkt eftersom servern detekterade att det var en förändring i filerna den baseras på och startade om sig och servar nya resultat.
Lab
docker-compose
Har man flera containrar som är beroende av varandra, som en DB-server, en frontend-server och så vidare kan det snabbt bli trassligt med alla kommandon och filer. För dessa sitationer kan man använda en docker-compose.yaml-fil.
En docker-compose.yaml-fil ligger alltid i en rotfolder. Eftersom den är tänkt att sammanföra flera olika containers till en fungerande enhet är denna rotfolder ofta en nivå ovanför där Dockerfile skulle hamna.
Med docker-compose kan man alltså hantera hela applikationssystem i en och samma infrastrukturfil. Det kan t.ex. vara en databas-server, en backend-server, några front-end-servrar och kanske en testautomatiserings-container utanpå det - allt deklarerat i en och samma fil.
Som filnamnet anger är det en YAML-fil, så håll ordning på indenteringen.
I övningen nedan har vår REST-tjänst nu även fått en front-end i form av en react-app.
- Öppna katalogen lab12-react och kika på dess docker-compose.yaml-fil. Förstår du strukturen?
- Förflytta dig till denna katalog och skriv kommmandot
docker-compose up
. Första gången tar det några sekunder. - Kolla så att du kan nå REST-servicen via en webbläsare på port 4000.
- Kolla så att du når GUI för webbtjänsten via en webbläsare på port 3000. Denna webbtjänst ropar i sin tur på REST-tjänsten som synes.
- Proga kommandot
docker-compose down
i samma katalog. Nu ska tjänsten vara nerstängd. - Starta upp tjänsten igen (
docker-compose up
) och denna gång stänger du ner den meddocker-compose down -rmi all
så tar den även bort images. Lägger du till växeln-v
tar den även bort volymerna.
Att använda en docker-compose.yaml-fil kan underlätta arbetet med många containers med beroenden väsentligt.
Lab
Testautomatisering i docker
Det är inte bara exekveringsmiljöer som gagnas av docker. Även test och annat QA-arbete är hjälpta av containerisering.
Det finns färdiga containrar för att exekvera allehanda typer av scriptade tester.
Skapa en container som exekverar ett valfritt automations-script mot sidan från föregående lab. Det bör finnas en lämplig image att börja med på https://hub.docker.com.
Kolla också efter t.ex. JMeter-images.
Lab
Docker i release-processen: Bygg-pipelines
Effektivitet i DevOps bygger mycket på automation för snabbhet, buggrättningsbara processer och förutsägbarhet. Byggpipelines är ett förträffligt hjälpmedel för detta.
Det finns inte något som hindrar att köra CLI-kommandon i något verktyg för byggpipelines. Det borde vara nog för att exekvera och managera docker-miljöer i byggpipelines, men många byggpipelines har färdiga steg och moduler för att underlätta användningen av containers.
Kika t.ex. på en Azure DevOps Pipelines olika möjligheter om du har tillgång till en sådan.
Lab
Snapshots för testeffektivitet
Med hjälp av kommandot docker commit
kan man skapa snapshots av containers.
Lab
Kubernetes
Kubernetes används för enkel, smidig, monitorerbar, skalbar och robust drift av Docker-containers.