Mis de Nieuwjaarssale deals niet!
search

Docker tutorial: een complete gids voor het uitvoeren van containers

Docker tutorial: een complete gids voor het uitvoeren van containers

Docker is een open platform dat het ontwikkelen, distribueren en uitvoeren van applicaties vereenvoudigt. Het stroomlijnt softwarelevering met behulp van containerisatie – een technologie waarbij applicaties en hun afhankelijkheden worden verpakt in geïsoleerde, uitvoerbare eenheden: containers. Hierdoor draaien applicaties overal op dezelfde manier, ongeacht de omgeving.

Docker is opgebouwd rond een aantal kernonderdelen, zoals de Docker Engine, Docker Hub, images, containers, Dockerfiles en Docker Compose. Als je begrijpt hoe deze componenten samenwerken, kun je containerapplicaties efficiënt bouwen, uitrollen en beheren.

Je kunt Docker gebruiken via de command line, maar er is ook een desktopversie met een grafische interface. De installatie verschilt per optie: Docker Desktop installeer je als een standaard .dmg- of .exe-bestand, terwijl de CLI meestal via een pakketbeheerder zoals APT of Homebrew wordt geïnstalleerd.

Binnen het Docker-ecosysteem kunnen fouten optreden op verschillende niveaus – in een image, een Dockerfile of een draaiende container. Omdat problemen op één laag de hele containeropzet kunnen verstoren, is het belangrijk om te begrijpen welke fouten vaak voorkomen, wat de oorzaken zijn en hoe je ze oplost. Daar gaan we later dieper op in, nadat we eerst de basisconcepten van Docker hebben behandeld.

Wat is containerisatie?

Containerisatie is een vorm van virtualisatie op besturingssysteemniveau waarbij applicaties draaien in geïsoleerde omgevingen, containers genoemd.

Elke container bevat alles wat nodig is om een applicatie uit te voeren – zoals code, systeembibliotheken, afhankelijkheden en configuratiebestanden – samengebracht in één afgebakende omgeving.

In tegenstelling tot virtuele machines (VM’s) zijn containers lichtgewicht, omdat ze de kernel van het hostbesturingssysteem delen. Daardoor zijn ze minder afhankelijk van de onderliggende infrastructuur en draaien applicaties consistent in verschillende omgevingen.

Containerisatie heeft meerdere voordelen:

  • Draagbaarheid. Containers werken hetzelfde op elke omgeving, van een lokale computer tot een externe server bij providers zoals Hostinger. Dit voorkomt compatibiliteitsproblemen bij deployment of samenwerking.
  • Efficiëntie. Virtuele machines vereisen een volledig gastbesturingssysteem en een hypervisor. Containers niet. Dat maakt containerisatie een veel lichtere en efficiëntere vorm van virtualisatie.
  • Isolatie. Elke container draait zijn eigen processen met aparte software, configuraties, netwerkinstellingen en omgevingsvariabelen. Dit verhoogt de beveiliging en voorkomt conflicten tussen applicaties.

Waarom zou je Docker gebruiken?

Docker biedt een betrouwbare en gestandaardiseerde manier om applicaties te bouwen, te delen en uit te voeren. Het lost meerdere praktische problemen op binnen softwareontwikkeling en deployment:

  • Geen “maar het werkt op mijn machine”-problemen. Docker zorgt ervoor dat applicaties voor elke ontwikkelaar en in elke fase exact hetzelfde werken, waardoor omgevingsgerelateerde fouten verdwijnen.
  • Snellere ontwikkeling en uitrol. Docker maakt het eenvoudig om reproduceerbare omgevingen op te zetten. Ontwikkelaars kunnen functionaliteit zoals betaaloplossingen of kaarten integreren zonder alles opnieuw te bouwen, wat veel tijd bespaart.
  • Schaalbaarheid en portabiliteit. Met tools zoals Docker Compose definieer je complete applicatiestacks met meerdere containers in één configuratiebestand. Zo blijft alles consistent tussen teams en kun je services eenvoudig opschalen.
  • Efficiënt gebruik van systeembronnen. Omdat containers licht zijn en de kernel van het hostbesturingssysteem delen, gebruiken ze minder resources dan traditionele virtuele machines.

Wat zijn de kernconcepten van Docker?

Docker organiseert containerisatie in een reeks onderling afhankelijke kerncomponenten. Samen vormen ze een platform waarmee je de volledige levenscyclus van een gecontaineriseerde applicatie beheert – van het bouwen van de eerste blauwdruk tot het draaien van een complete applicatie met meerdere services.

Docker-engine

Docker Engine is de kern van Docker en vormt de open source technologie voor het bouwen en uitvoeren van containers. Het maakt gebruik van een client-serverarchitectuur om alle Docker-objecten te beheren, zoals images, containers en netwerken.

De Docker Engine bestaat uit drie hoofdonderdelen:

  1. De server – een continu draaiend daemonproces (dockerd) dat verantwoordelijk is voor taken zoals het aanmaken, starten en verwijderen van containers.
  2. De API’s – interfaces waarmee programma’s, waaronder de Docker CLI, met de daemon communiceren en opdrachten doorgeven.
  3. De CLI-client – de Docker command-line tool, waarmee gebruikers Docker aansturen.

Om dit concept eenvoudig uit te leggen, kun je Docker Engine vergelijken met een restaurant:

  • De server (dockerd) is de chef die het gerecht bereidt – ofwel de container uitvoert.
  • De API’s zijn het menu en de bestelbonnen die aangeven wat er moet worden gemaakt.
  • De Docker CLI is de ober die je bestelling (commando’s) opneemt en doorgeeft aan de keuken.

Om te controleren of Docker Engine actief is en correct is verbonden met de client, voer je het volgende commando uit:

docker ps

Dit commando vraagt de Docker daemon om alle actieve containers te tonen. Als Docker correct werkt, zie je hier een overzicht van draaiende containers.

Docker hub

Docker Hub is het standaard openbare Docker-registry – een opslag- en distributieservice voor Docker-images. Het host officiële images voor populaire software zoals nginx, Node.js en Python en stelt gebruikers in staat om privé-repositories aan te maken voor hun eigen images.

Wanneer je een container bouwt, gebruik je images waarin softwarepakketten en afhankelijkheden zijn vastgelegd. Docker Hub vereenvoudigt dit proces door images centraal beschikbaar te stellen, zodat je ze eenvoudig kunt downloaden vanuit één repository.

Docker Hub gebruikt tags om images te labelen en te identificeren. Deze tags geven een specifieke versie van een image aan, zoals latest. Dit zorgt voor consistente werking en voorspelbaar gedrag van containers in verschillende omgevingen.

Je kunt Docker Hub vergelijken met een gemeenschappelijke kookboekenbibliotheek. Het bevat vooraf geschreven recepten voor veelvoorkomende toepassingen die iedereen kan downloaden en gebruiken. Daarnaast kun je ook je eigen recepten uploaden om ze te delen of als privéback-up te bewaren.

Je kunt met Docker Hub werken via het Docker-commando. Gebruik bijvoorbeeld het volgende om een image uit het registry te downloaden:

docker pull <name>:<tag>

Bijvoorbeeld om de nieuwste officiële Ubuntu image te downloaden:

docker pull ubuntu:latest

Docker-images

Een Docker-image is een alleen-lezen template dat alle instructies en bestanden bevat die nodig zijn om een Docker-container te maken. Het verpakt applicatiecode, configuratiebestanden, systeembibliotheken en bestanden van het onderliggende besturingssysteem.

Images worden opgebouwd op basis van een Dockerfile. Elke instructie in het Dockerfile creëert een aparte, onveranderlijke laag die bepaalt wat de image bevat of doet.

Eenvoudig gezegd is een image de blauwdruk van een container. Het bevat een set instructies die exact vastlegt hoe het eindresultaat eruitziet, maar kan niet meer worden aangepast zodra het is gebouwd. Door deze blauwdruk te gebruiken, maak je een Docker-container.

Gebruik het volgende commando om een overzicht te krijgen van de Docker-images die je lokaal hebt gedownload:

docker images

Met het volgende commando bouw je in je huidige map een image op basis van een specifieke image. Als deze image nog niet lokaal beschikbaar is, downloadt Docker deze automatisch van Docker Hub:

docker build -t your-image-name:latest .

Een best practice bij het werken met images is het gebruik van een minimale basisimage. Dit verkleint de imagegrootte en beperkt het potentiële aanvalsoppervlak dat vaak ontstaat door onnodige pakketten of componenten.

Docker-containers

Een container is een uitvoerbare instantie van een image. Het is de geïsoleerde omgeving waarin je applicatie draait, samen met de bijbehorende configuratie, afhankelijkheden en benodigde softwarepakketten.

Wanneer je een Docker-container aanmaakt, wordt er een schrijfbare laag toegevoegd boven op de alleen-lezen lagen van de image. Hierdoor kun je bestandswijzigingen aanbrengen binnen het lokale bestandssysteem van de container.

Containers zijn ontworpen om tijdelijk of stateless te zijn. Dit betekent dat ze met minimale configuratie kunnen worden gestopt, verwijderd, herbouwd en vervangen. Een individuele container beheer je met de Docker CLI, terwijl meerdere containers worden beheerd met Docker Compose of een orkestratietool zoals Kubernetes.

In dezelfde analogie is een container de daadwerkelijk draaiende machine die is gebouwd op basis van de blauwdruk, oftewel de image. Wanneer je een Docker-container maakt, stel je die machine samen en start je deze om de processen uit te voeren die in de image zijn gedefinieerd.

Om een Docker-container te starten en er een commando in uit te voeren, gebruik je het run-commando:

docker run -it ubuntu /bin/bash

Dit commando start een interactieve container op basis van de Ubuntu-image en voert de /bin/bash-shell uit.

Dockerfiles

Een Dockerfile is een tekstbestand dat een reeks stapsgewijze instructies bevat voor het bouwen van een Docker-image. Het definieert alles, van het basisbesturingssysteem tot omgevingsvariabelen en applicatiecode.

Hier zijn enkele van de meest gebruikte Dockerfile-instructies en hun functie:

  • FROM. Geeft de basisimage op voor een nieuwe build stage.
  • RUN. Voert commando’s uit tijdens het buildproces van de image.
  • COPY of ADD. Kopieert bestanden vanuit de build context naar de image.
  • CMD of ENTRYPOINT. Definieert het commando dat wordt uitgevoerd wanneer de container start.
  • ENV. Stelt omgevingsvariabelen in die beschikbaar zijn tijdens het buildproces en tijdens runtime.
  • WORKDIR. Stelt de werkdirectory in voor de daaropvolgende RUN-, CMD-, ENTRYPOINT-, COPY- en ADD-instructies.

Sommige Dockerfile-instructies maken een layer aan – een stap in het buildproces van een image. Instructies die alleen configuratie of metadata instellen, zoals WORKDIR, doen dat echter niet.

Hieronder zie je een voorbeeld van een Dockerfile:

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Docker Compose

Docker Compose is een tool die het definiëren en beheren van multi-containerapplicaties vereenvoudigt met behulp van één configuratiebestand, meestal docker-compose.yml.

In dit configuratiebestand kunnen ontwikkelaars alle containers, netwerken en volumes definiëren die nodig zijn om een complexe applicatiestack op te bouwen. Vervolgens kunnen ze alle containers – in de context van Docker Compose ook wel services genoemd – met één commando starten en beheren.

Zonder Docker Compose moet je elke container handmatig configureren en afzonderlijk beheren via de Docker CLI. Bestaat je applicatie uit meerdere onderling verbonden services, dan wordt dit al snel een omslachtig en tijdrovend proces.

Als een container te vergelijken is met één apparaat, dan is Docker Compose het bedradingsschema van een volledige keuken. Het beschrijft hoe de oven, koelkast en broodrooster met elkaar verbonden zijn en samen met één schakelaar worden ingeschakeld.

Hieronder zie je een voorbeeld van een Docker Compose-bestand:

services:
  web:
    build: ./web  # Bouw de image op basis van het Dockerfile in de map ./web
    ports:
      - "8000:8000"  # Koppel hostpoort 8000 aan containerpoort 8000
    depends_on:
      - db     # Wacht tot de db-service is gestart
      - redis  # Wacht tot de redis-service is gestart

  db:
    image: postgres:15  # Gebruik de officiële PostgreSQL 15-image
    environment:
      POSTGRES_USER: myuser       # Stel de gebruikersnaam van de database in
      POSTGRES_PASSWORD: mypassword  # Stel het databasewachtwoord in
      POSTGRES_DB: mydb           # Stel de initiële databasenaam in
    volumes:
      - db-data:/var/lib/postgresql/data  # Sla databasegegevens persistent op via een named volume

  redis:
    image: redis:alpine  # Gebruik een lichte Redis-image voor caching

volumes:
  db-data:  # Definieer een named volume voor het opslaan van databasegegevens

Om alle services die zijn gedefinieerd in je docker-compose.yml-bestand op de achtergrond te bouwen en te starten, gebruik je het commando met de -d-optie (detached):

docker compose up -d

Daarnaast zijn er meerdere Docker Compose-commando’s beschikbaar waarmee je alle containers gedurende de volledige levenscyclus van je applicatie centraal kunt beheren.

Docker installeren

De manier waarop je Docker installeert, hangt af van de variant die je gebruikt. Werk je met Docker Desktop, dan kun je het installatiepakket eenvoudig downloaden via de officiële website. Je installeert het vervolgens net zoals elke andere applicatie.

Gebruik je liever de Docker CLI, dan installeer je Docker via de pakketbeheerder van je besturingssysteem. Op Ubuntu gebeurt dit bijvoorbeeld met APT, terwijl macOS Homebrew gebruikt. Raadpleeg altijd de officiële documentatie voor de juiste installatiecommando’s voor jouw systeem.

Houd er rekening mee dat de Docker CLI niet standaard alle functionaliteiten bevat. Docker Compose wordt bijvoorbeeld niet automatisch meegeleverd en moet je apart installeren. Gebruik je echter Hostinger’s Docker-hosting, dan hoef je dit niet zelf te regelen. De ingebouwde Docker Manager bevat namelijk al ondersteuning voor Compose.

Basis Docker-commando’s begrijpen

Met de Docker CLI communiceer je met Docker Engine en beheer je je containers. Hieronder vind je enkele van de meest gebruikte Docker-commando’s, verdeeld over verschillende taken:

  • docker ps -a. Toont alle containers, inclusief containers die zijn gestopt.
  • docker pull <name>:<tag>. Downloadt een image vanuit het registry naar je lokale machine.
  • docker rmi <image>. Verwijdert een lokaal image.
  • docker stop <container>. Stopt een draaiende container netjes.
  • docker rm <container>. Verwijdert een container.

Docker-volumes beheren

Volumes zijn de belangrijkste manier om data persistent op te slaan in Docker. Ze zorgen ervoor dat gegevens beschikbaar blijven, zelfs nadat een container is verwijderd.

Dit is belangrijk omdat containers tijdens hun levenscyclus regelmatig worden gestopt of vervangen, bijvoorbeeld bij updates of onderhoud. Draait een container een applicatie zoals een database, waarbij dataconsistentie essentieel is, dan zijn volumes onmisbaar.

Docker ondersteunt drie soorten opslag:

  • Volumes. Persistente data die Docker opslaat in zijn eigen opslagstructuur, meestal in /var/lib/docker/volumes/ op het hostsysteem.
  • Bind mounts. Koppelen een bestand of map van het hostsysteem rechtstreeks aan een container.
  • tmpfs mounts. Slaan data op in het geheugen van de host. Deze data gaat verloren zodra de container stopt.

Hier zijn de stappen om een volume aan te maken en te beheren voor persistente data:

  1. Maak een named volume aan met het volgende commando. Dit voorbeeld maakt een volume aan met de naam my-database-data:
docker volume create my-database-data
  1. Start vervolgens je databasecontainer met de -v-optie om het volume te koppelen aan de interne datamap van de container. Het commando ziet er als volgt uit:
docker run -d \
  --name my-database \
  -e MYSQL_ROOT_PASSWORD=securepassword \
  -v my-database-data:/var/lib/mysql \
  mysql:latest
  1. Inspecteer de details en de locatie van het volume op de host door het volgende commando uit te voeren:
docker volume inspect my-database-data
  1. Om ongebruikte volumes te verwijderen die niet aan een container zijn gekoppeld en schijfruimte vrij te maken, gebruik je:
docker volume prune -a

In plaats van losse commando’s kun je een volume ook declareren en koppelen door de configuratie op te nemen in het YAML-bestand van Docker Compose. Dit maakt het eenvoudiger om bij te houden welke volumes door welke containers worden gebruikt, vooral wanneer je met meerdere services werkt.

Het onderstaande YAML-voorbeeld komt overeen met de bovenstaande stappen voor het aanmaken van een volume en het koppelen aan een container:

services:

  my-database:

    image: mysql:latest

    container_name: my-database

    environment:
      MYSQL_ROOT_PASSWORD: securepassword

    volumes:
      - my-database-data:/var/lib/mysql

volumes:
  my-database-data:

Een Docker-netwerk aanmaken

Docker-netwerken zorgen voor isolatie en maken communicatie mogelijk tussen containers en externe systemen. Standaard worden containers gekoppeld aan een bridge-netwerk. Voor een applicatie met meerdere services is het aan te raden om een user-defined bridge network aan te maken.

Docker-netwerken maken het mogelijk dat containers met elkaar en met externe systemen communiceren.

Standaard verbindt Docker een container met het zogenoemde default bridge-netwerk. Dit netwerk maakt communicatie met de host mogelijk, maar is minder geschikt voor multi-containeropstellingen, omdat het beperkte ondersteuning biedt voor communicatie tussen services.

Voor applicaties met meerdere services is het best practice om een user-defined bridge network te gebruiken. Hiermee kunnen containers onderling communiceren via hun servicenamen. Dit vereenvoudigt service discovery, geeft meer controle over de interactie tussen containers en voorkomt ongewenste interferentie tussen services.

Je kunt een container verbinden met een user-defined bridge network door de networks-directive toe te voegen aan de configuratie van de service in het Docker Compose YAML-bestand. Hieronder zie je een voorbeeld:

services:

  my-database:

    image: mysql:latest

    container_name: my-database

    environment:
      MYSQL_ROOT_PASSWORD: securepassword

    volumes:
      - my-database-data:/var/lib/mysql

    networks:
      - my-app-network #create a network

Als alternatief kun je een user-defined bridge network aanmaken via de Docker CLI. In het volgende voorbeeld is my-app-network de naam van het netwerk:

docker network create my-app-network

Vervolgens start je een container met Docker CLI door de –name-optie te gebruiken om de servicenaam in te stellen en –network om aan te geven met welk netwerk de container wordt verbonden. Het commando ziet er als volgt uit:

docker run -d \
  --name my-database \
  --network my-app-network \
  -e MYSQL_ROOT_PASSWORD=securepassword \
  -v my-database-data:/var/lib/mysql \
  mysql:latest

Wil je nog een container starten en deze verbinden met hetzelfde netwerk, dan herhaal je het commando met aangepaste servicegegevens. In het onderstaande voorbeeld voegen we de -p-optie toe om poort 80 van de container beschikbaar te maken op poort 8080 van de host, zodat de service extern toegankelijk is:

docker run -d \
  --name my-webapp \
  --network my-app-network \
  -p 8080:80 \
  my-web-app-image:latest

Veelvoorkomende Docker-problemen oplossen

Bij het werken met Docker ontstaan problemen vaak binnen het gelaagde systeem, zoals images, containers, volumes en netwerken. Hieronder bespreken we veelvoorkomende issues en laten we zien hoe je ze oplost.

Container stopt direct na het starten

Een container kan direct stoppen nadat deze is gestart wanneer het hoofdproces, gedefinieerd via CMD of ENTRYPOINT in de Dockerfile, is afgerond of crasht. Een veelvoorkomende oorzaak is dat Docker Engine een service probeert te starten die bedoeld is om op de achtergrond te draaien, zonder gebruik te maken van detached mode.

Enkele mogelijke oplossingen:

  • Logs controleren. Gebruik docker logs <container_name> om de standaarduitvoer (stdout) en foutmeldingen (stderr) te bekijken en de oorzaak van de crash te achterhalen.
  • Dockerfile-instructies controleren. Controleer of de container een langlopend proces uitvoert en of de Dockerfile een correcte CMD of ENTRYPOINT bevat. Een webserver moet bijvoorbeeld actief blijven om verzoeken te kunnen verwerken.
  • Detached mode gebruiken. Als de applicatie een langlopende service is die op de achtergrond moet draaien, gebruik dan de -d– of –detach-optie bij docker run of docker compose run.

Problemen met image layer caching

Als wijzigingen in je Dockerfile, zoals het updaten van een pakketversie, geen effect lijken te hebben, kan Docker’s layer caching de oorzaak zijn. Dit mechanisme hergebruikt bestaande image-lagen om het buildproces te versnellen, in plaats van alles opnieuw op te bouwen.

Hoewel dit efficiënt is, kan het problemen opleveren wanneer wijzigingen worden aangebracht in eerdere lagen van de Dockerfile. In dat geval worden de daaropvolgende instructies mogelijk niet opnieuw uitgevoerd.

De eenvoudigste oplossing is om een volledige rebuild af te dwingen en de cache te negeren. Dit doe je door de –no-cache-optie toe te voegen aan het buildcommando:

docker build --no-cache -t my-app:latest .

Bij het installeren van pakketten via een Dockerfile is het daarnaast belangrijk om te voorkomen dat verouderde pakketlijsten worden hergebruikt. In Debian-gebaseerde distributies kun je dit oplossen door apt-get update en apt-get install te combineren in één RUN-instructie, bijvoorbeeld:

RUN apt-get update && apt-get install -y --no-install-recommends

Authenticatiefouten bij registries

Krijg je bij het pushen van een image naar een registry, zoals Docker Hub, een foutmelding als “denied: requested access to the resource is denied“, dan is de Docker CLI niet geauthenticeerd bij de registry.

De oplossing is om in te loggen en je account te authenticeren bij de registry. Volg hiervoor deze stappen:

  1. Log in bij de registry met het volgende commando. Hierbij staat my-registry.example.com voor het daadwerkelijke adres van de registry. Gebruik je Docker Hub, dan kun je het adres weglaten:
docker login my-registry.example.com
  1. Voer je gebruikersnaam en wachtwoord in wanneer hierom wordt gevraagd.
  2. Tag de image correct met de registry-host, repository en tag voordat je deze pusht:
docker tag my-local-image:latest my-registry.example.com/my-repo/my-local-image:latest
  1. Push de image naar de registry met het volgende commando:
docker push my-registry.example.com/my-repo/my-local-image:latest

Wat zijn de volgende stappen om Docker onder de knie te krijgen?

Om Docker echt goed te beheersen en toe te passen in productieomgevingen, is het nodig om verder te gaan dan één container en basiscommando’s. De volgende stap is het begrijpen van geavanceerde technieken voor het deployen en beheren van complexe applicaties met hoge beschikbaarheid.

Naast Docker Compose is het belangrijk om orkestratietools zoals Docker Swarm of Kubernetes te leren gebruiken. Deze tools zijn essentieel voor het beheren en schalen van meerdere containers binnen een cluster van machines.

Daarnaast is het aan te raden om je te verdiepen in netwerkdrivers, zoals de Overlay Network Driver die wordt gebruikt in Docker Swarm-modus. Waar het verbinden van meerdere hosts via Docker’s standaardnetwerk complex en handmatig is, maken overlay-netwerken communicatie tussen hosts eenvoudiger, schaalbaar en betrouwbaarder.

Tot slot helpt het om verschillende Docker-usecases te verkennen. Zo krijg je een beter beeld van hoe je Docker kunt inzetten voor uiteenlopende taken tijdens ontwikkeling en deployment.

Alle tutorials op deze website voldoen aan de strenge edactionele standaarden en waarden van Hostinger.

Author
De auteur

Faradilla Ayunindya

Faradilla, or Ninda, is a Content Marketing Specialist at Hostinger with over 5 years of experience and a 10-year background as a linguist. She is dedicated to making technology accessible by localizing complex guides into easy-to-follow tutorials. When she’s not keeping up with the latest tech and digital marketing trends, Ninda enjoys learning about life sciences or watching funny animal videos. Connect with her on LinkedIn.

Wat onze klanten zeggen

Leave a reply

Please fill the required fields.Please accept the privacy checkbox.Please fill the required fields and accept the privacy checkbox.

Thank you! Your comment has been successfully submitted. It will be approved within the next 24 hours.