Docker containers
Levenscyclus container
Elke container heeft een bepaalde levenscyclus. Je vertrekt altijd van een image, dit kan ofwel een kant-en-klare image zijn die je in Dockerhub of een andere registry vindt, of een image die je zelf gebuild hebt zoals beschreven in de sectie images bouwen en beheren.
docker run
Een container kan gestart worden met docker run <my_container>. docker run wordt gebruikt als je de container voor de eerste keer wilt starten. Dit commando maakt een nieuwe container met de image die je wilt gebruiken.
docker run -d --name my_container my_image
- De
-doptie staat voordetached mode. Dit wilt zeggen dat de container op de achtergrond draait en dat de shell terug vrijgegeven wordt. Dit is handig als je de logs van de container niet per se wilt volgen en verder wilt werken in dezelfde terminal. - De naam van de container kan insteld worden met
--name. Als je geen naam meegeeft zal docker een random naam voor je container genereren.
Er zijn een paar handige opties die je kan meegeven wanneer je een docker container wilt runnen.
docker run [opties] <image> [commando]
De belangrijkste opties, waarvan enkele hierboven al vermeld, zijn:
-d: in detached mode draaien-p: portforwarding toevoegen--name: een naam geven aan de container-v: om een volume te mounten (zie de sectie over volumes)
docker start
Als je een container al ooit gestart hebt met run en daarna terug gestopt maar niet verwijderd dan hoef je niet opnieuw docker run te doen om dezelfde container te starten. Om een bestaande container te starten kan je docker start uitvoeren. Als je op zoek bent naar de container_id of container_name om te gebruiken kan je dat achterhalen met docker ps -a. De -a optie zorgt ervoor dat alle container getoond worden, niet alleen degene die aan het draaien zijn.
# Start een bestaande container die eerder was gestopt
docker start <my_container_id | my_container_name>
docker stop
Een container stoppen kan je doen door docker stop <my_container_id | my_container_name> te gebruiken. Dit stuurt een SIGTERM signaal naar de container zodat de applicatie in de container eerst netjes kan afsluiten. Na een bepaalde tijd, die je zelf kan instellen en standaar op 10 seconden staat, wordt er een SIGKILL command gestuurd en wordt de applicatie dus geforceerd gestopt.
docker stop <my_container_id | my_container_name>
docker restart
Soms wil je een container herstarten zonder die eerste te verwijderen en opnieuw aan te maken. Stel dat je bv een applicatie hebt die bij het opstarten nieuwe configuratie files of andere assets van een CDN (Content Delivery Network) binnenhaalt. Je kan dan de container herstarten om de applicatie opnieuw te laten runnen. Een container herstarten kan je doen met docker restart <my_container>.
docker restart <my_container_id | my_container_name>
docker kill
Als een container bijvoorbeeld is gecrasht of vasthangt kan het zijn dat je hem wilt "killen". Een kill zal de container onmiddellijk geforceerd stoppen (een SIGKILL sturen).
docker kill <my_container_id | my_container_name>
Gebruik van deze commando's in de praktijk
-
Opschalen: In een productieomgeving wil je mogelijk containers automatisch herstarten als ze crashes of fouten ondervinden. Dit kan via Docker’s restart policies, zoals --restart=always, zodat de container automatisch herstart wanneer deze stopt.
docker run -d --restart=always --name my_app my_image -
Onderhoud: Als je wijzigingen hebt aangebracht in een Docker-container (bijvoorbeeld nieuwe versies van een applicatie), kun je de container stoppen, een nieuwe versie van het image binnen trekken, de container opnieuw starten en de oude container verwijderen.
docker stop my_app
docker rm my_app
docker pull my_image:latest
docker run -d --name my_app my_image -
Monitoring: Als een container onverwacht vastloopt of vastzit in een "hanging" toestand, kun je het commando
docker killgebruiken om de container onmiddellijk te beëindigen en ervoor zorgen dat nieuwe containers worden opgestart.
Andere handige docker commando's
Er zijn een paar handige docker commando's die je zeker moet kennen om efficient containers te kunnen beheren.
docker ps
Het docker ps commando helpt ons om een overzicht te krijgen van de bestaande / draaiende containers.
docker ps [opties]
De belangrijkste opties:
-a: Toon ook de gestopte containers--filter: Filtert containers op basis van een bepaald criterium, zoals naam, status, of ID.--format: Hiermee kun je de uitvoer aanpassen (bijvoorbeeld alleen specifieke velden tonen).
docker exec
Het docker exec commando is belangrijk om interactief met de docker containers te kunnen werken. Het zorgt ervoor dat we commando's kunnen uitvoeren binnen een container. Hierover meer in de sectie debuggen.
docker exec [opties] <container> <commando>
docker exec wordt heel vaak gebruikt om een shell te openen in de container:
docker exec -it node-app /bin/bash
Mounten van volumes in containers
In een containerized omgeving zijn containers van nature tijdelijk en vergankelijk. Als een container wordt gestopt, verwijderd of opnieuw wordt opgestart, gaat de interne data verloren. Om dit probleem op te lossen, gebruikt Docker volumes om gegevens buiten de container op te slaan, zodat ze behouden blijven, zelfs als de container zelf wordt verwijderd of opnieuw wordt gestart.
Een volume in Docker is een speciaal opslagmechanisme dat wordt gebruikt om data op te slaan die onafhankelijk is van de levenscyclus van containers. Het volume kan worden gedeeld tussen containers, en de gegevens blijven behouden zelfs als de container gestopt of verwijderd wordt.
Docker biedt de mogelijkheid om drie typen opslag te gebruiken:
- Volumes: Beheerbare opslag die wordt beheerd door Docker en onafhankelijk is van de container.
- Bind mounts: Verwijzingen naar specifieke mappen op de host machine.
- tmpfs mounts: Geheugen-gebaseerde opslag die niet wordt opgeslagen op de harde schijf.
Waarom Volumes Gebruiken?
Volumes zijn de aanbevolen manier om persistente data te beheren in Docker. Ze hebben verschillende voordelen:
- Persistentie: Gegevens in een volume blijven bestaan zelfs als de container wordt verwijderd.
- Back-up en herstel: Je kunt eenvoudig een back-up maken of herstellen.
- Schaalbaarheid: Volumes kunnen worden gedeeld tussen meerdere containers, wat ideaal is voor microservices-architecturen.
- Efficiëntie: Volumes worden door Docker beheerd en geoptimaliseerd, wat beter is dan bijvoorbeeld bind mounts, die meer afhankelijk zijn van de configuratie van de host.
Volume mounten bij het starten
Je kunt een volume mounten bij het starten van een container met de docker run-opdracht door gebruik te maken van de -v of --mount optie. Dit zorgt ervoor dat de data in de container naar een volume wordt geschreven dat buiten de container bestaat.
docker run -v <volume_naam>:<pad_in_de_container> <image>
Voorbeeld van een container die een volume gebruikt
Stel dat je een container hebt die een MySQL database draait, en je wilt de databasegegevens persistent maken. Je kunt een volume mounten voor de databasebestanden:
docker run -d -v mysql-data:/var/lib/mysql --name mysql-container mysql:5.7
--mount biedt meer flexibiliteit en controle over volumes, bind mounts, en tmpfs mounts. Het wordt vaak gebruikt in plaats van -v omdat het duidelijker is, vooral bij complexere configuraties.
docker run --mount type=volume,source=<volume_naam>,target=<pad_in_de_container> <image>
Het voorbeeld hierboven omgezet naar een commando dat mount gebruikt:
docker run -d --mount type=volume,source=mysql-data,target=/var/lib/mysql --name mysql-container mysql:5.7
Volumes beheren
Je kunt de status van volumes inspecteren en beheren met de volgende Docker-opdrachten:
# Toon alle volumes
docker volume ls
# Inspecteer 1 volume in detail
docker volume inspect <volume_naam>
# Verwijder een volume
docker volume rm <volume_naam>
# Ruim alle niet gebruikte volumes op
docker volume prune
Volumes in de praktijk
In het echte leven wil je vaak de logs van je applicatie in een volume mounten om ervoor te zorgen dat wanneer de applicatie crasht en exit, je nog altijd kan inspecteren wat er fout is gegaan.
docker run -d -p 8081:80 --name web-app -v nginx-logs:/var/log/nginx nginx
docker exec -it webapp ls -al /var/log/nginx
docker exec -it webapp touch /var/log/nginx/my_own_log.log
docker exec -it webapp ls -al /var/log/nginx
docker restart webapp
docker exec -it webapp ls -al /var/log/nginx
Exposen van poorten
Een poort exposen
Wanneer je een container runt die een netwerkservice aanbiedt (bijvoorbeeld een webserver, database, ...), moet je bepaalde poorten buiten de container beschikbaar stellen om toegang te krijgen. Dit kan eenvoudig worden gedaan met de -p of --publish optie bij de docker run opdracht.
De basis van poortkoppeling in Docker is het openen van poorten van de container naar de hostmachine (jouw computer of de server), zodat de container met andere systemen of containers kan communiceren.
docker run -p <host_poort>:<container_poort> <image>
Poorten in de praktijk
- Webtoepassingen: Vaak wil je poort 80 of 443 exposen voor HTTP(S)-verkeer.
- Databases: Als je een container draait die een database (zoals MySQL of PostgreSQL) biedt, wil je poort 3306 (MySQL) of 5432 (PostgreSQL) exposen.
- Applicaties met API's: Expose poorten voor interne API's of microservices die andere containers of toepassingen moeten bereiken.
Netwerken tussen containers
Docker biedt ook de mogelijkheid om containers met elkaar te verbinden via netwerken. Dit maakt het mogelijk om containers met elkaar te laten communiceren, bijvoorbeeld voor een microservices-architectuur, waarbij de ene container een database bevat en de andere een webserver.
Als containers met elkaar moeten communiceren, kun je ze eenvoudig verbinden via netwerken. Containers kunnen elkaar bereiken via de containernaam, die fungeert als hun hostnaam binnen het netwerk.
Er zijn drie niveaus van netwerken in Docker:
- Bridge netwerk (standaard)
- Host netwerk
- Overlay netwerk
Bridge netwerk
Wanneer je geen specifiek netwerk opgeeft, maakt Docker standaard een bridge netwerk voor containers. Dit is een virtueel netwerk dat de containers met elkaar verbindt binnen dezelfde host. Dit netwerk is geïsoleerd van het externe netwerk.
Stel dat je twee containers hebt die met elkaar moeten communiceren. Als je bijvoorbeeld een webserver en een database in verschillende containers wilt draaien, kun je dit doen met het standaard bridge netwerk:
docker run -d --name webserver my-webserver
docker run -d --name database my-database
Beide containers kunnen met elkaar communiceren, omdat ze binnen hetzelfde bridge-netwerk draaien. Maar externe toegang (buiten de host) wordt geblokkeerd, tenzij je specifieke poorten openstelt, zoals eerder besproken in de sectie poorten exposen
Je zou ook handmatig een bridge netwerk kunnen instellen als je er iets meer controle over wilt:
docker network create my-bridge-network
docker run -d --name webserver --network my-bridge-network my-webserver
docker run -d --name database --network my-bridge-network my-database
Binnen een bridge netwerk kunnen container direct met elkaar communiceren via hun containernaam.
Host netwerk
Het host-netwerk maakt gebruik van het netwerk van de hostmachine zelf. Containers die op het host-netwerk draaien, delen de netwerkinterface van de host, wat betekent dat ze geen eigen IP-adres hebben, maar dezelfde IP-adresruimte gebruiken als de host.
Het host-netwerk is handig wanneer je zeer hoge prestaties nodig hebt of wanneer je een container wilt draaien die volledig toegang heeft tot het netwerk van de host (bijvoorbeeld voor netwerkdiagnose of wanneer de container zelf netwerkservices draait).
docker run -d --network host webapp
Met deze instelling heeft de container dezelfde netwerkinterface als de host en luistert op dezelfde poorten. Dit betekent dat je geen poorten hoeft te exposen (dit gebeurt automatisch).
Overlay netwerk
Het overlay-netwerk is bedoeld voor communicatie tussen containers die op verschillende Docker-hosts draaien. Dit netwerk is handig wanneer je een Docker Swarm-cluster of Docker Compose gebruikt om meerdere containers over verschillende machines te verdelen.
Overlay-netwerken maken gebruik van VXLAN (Virtual Extensible LAN) om de netwerkcommunicatie over verschillende hosts mogelijk te maken, zodat containers op verschillende machines kunnen communiceren alsof ze op dezelfde fysieke machine draaien.
docker network create -d overlay my-overlay-network
Best practices in netwerken
- Firewalls op de host om ongewenste toegang te blokkeren
- Docker heeft ingebouwde netwerkisolatie, wees dus voorzichtig met dit te bypassen
- Stel nooit meer poorten open dan nodig
Docker logs
Docker logs zijn de uitvoer (stdout en stderr) van de processen die binnen een container draaien. Deze logs worden gegenereerd door de applicaties die in de container draaien. Ze kunnen bestaan uit:
- Standaarduitvoer (stdout): Gebruikt door de applicatie om gewone informatie te loggen.
- Standaardfout (stderr): Gebruikt door de applicatie om fouten te loggen.
docker logs webapp
Veelgebruikte opties:
-f: Staat voorfollowen wordt gebruikt om de logs in realtime te kunnen volgen--since: Om vanaf een specifieke tijdsperiode op te halen--tail {number}: Hiermee kan je de laatstenumberlogs ophalen--details: Hiermee kan je iets gedetailleerdere logs zien