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

  1. Ladda hem och installera Docker Desktop till din dator om du inte redan har det installerat.
  2. Ladda hem och installera git till din dator om du inte redan har det.
  3. Skapa en lokal katalog som heter DevOpsHackaton eller liknande.
  4. Öppna en kommandoprompt och gå till den nyskapade foldern.
  5. 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?

Installera Docker Desktop från https://www.docker.com/products/docker-desktop/ och git från https://git-scm.com/downloads.

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.

  1. Starta Docker Desktop så att Docker-daemons är igång.
  2. Hämta hem en grund-docker-image som innehåller en webbserver (t.ex. med docker pull httpd).
  3. 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/).
  4. Bygg en egen docker-image utifrån denna Dockerfile (utan punkt eller filändelse).
  5. Studera output från byggandet i din konsol. Vad gör Docker när den bygger? Hur lång tid tar det?
  6. Kontrollera status på images i det grafiska användargränssnittet i Docker Desktop.
  7. Använd kommandot docker images i en kommandoprompt för att se en listning på de images som din docker har tillgängliga.
  8. 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>?
  9. 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.

Ladda hem en grundimage med 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 80
    
                    
Bygg 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

  1. 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.
  2. Googla skillnaderna mellan docker start och docker run. De låter snarlika men har olika beteende.
  3. Undersök även vad docker run --rm gör som inte vanliga docker run gör.
  4. 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).
  5. Prova att starta och stoppa din container från Docker Desktop.
  6. Använd kommandoprompts-kommandot docker ps för att se vilka containers som körs.
  7. 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.
  8. 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.

Starta containern från din image med 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.

  1. Städa bort de images och containers som inte längre används.
I denna övning kan det ånyo vara bra att ta till kommandon som 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.

  1. Installera Visual Studio Code om du inte redan har den installerad.
  2. Öppna Visual Studio Code.
  3. Lägg till extension Docker och Docker Explorer om du inte redan har dessa installerade.
  4. Notera hur det finns en Docker-ikon i vänstermarginalen. Klicka på denna. Vad ser du?
  5. Högerklicka på de entrys du ser. Vad har du för val?
  6. 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.

  1. 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.
  2. Gå till katalogen lab5-restserver och studera den Dockerfile som finns där. Vad kommer denna image att göra när den byggs?
  3. Prova att bygga en image från den Dockerfile som finns i katalogen lab5-restserver.
  4. 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.

  1. Skapa en fil som heter .dockerignore (lägg märke till den inledande punkten) i samma katalog som din Dockerfile.
  2. Öppna filen .dockerignore och lägg till raden node_modules i filen.
  3. Spara och stäng filen.
  4. 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.
  5. 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.

  1. Öppna katalogen lab8-cachning och jämför dess Dockerfile med den i föregående övning. Vilka skillnader finns?
  2. 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.

  1. Öppna katalogen lab10-volumes och studera dess Dockerfile.
  2. Starta upp en container baserat på denna och prova att göra en HTTP GET med en webbläsare.
  3. Ä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.

  1. Öppna katalogen lab12-react och kika på dess docker-compose.yaml-fil. Förstår du strukturen?
  2. Förflytta dig till denna katalog och skriv kommmandot docker-compose up. Första gången tar det några sekunder.
  3. Kolla så att du kan nå REST-servicen via en webbläsare på port 4000.
  4. 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.
  5. Proga kommandot docker-compose down i samma katalog. Nu ska tjänsten vara nerstängd.
  6. Starta upp tjänsten igen (docker-compose up) och denna gång stänger du ner den med docker-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.