Docker Image en Container
Op deze pagina:
- Het verschil tussen Docker containers en Virtuele Machines
- De werking van Docker
- Docker installeren
- Docker installeren in Ubuntu
- Docker installeren in Fedora
- Geen sudo meer
- Docker versie
- Controleren of de Docker deamon actief is
- Een Docker image starten
- Docker images opvragen
- Docker containers opvragen
- Een opdracht uitvoeren met exec
- Een terminalsessie stoppen zonder de container te stoppen
- Een Docker container stoppen
- Een Docker container herstarten
- Bestanden kopiëren naar een container
- Een Docker container verwijderen
- Een Docker image verwijderen
- Docker images, containers en volumes opschonen met prune
- Een image maken
- Labels gebruiken
- Tags gebruiken
- Docker Hub
- Docker logs
- Docker in productie omgevingen
- Schijfgebruik opvragen
- CPU, RAM en netwerk gebruik opvragen
- Docker API
- Containers automatisch herstarten
- Een image opslaan als .tar en weer inlezen
- Aanpassingen in een container opslaan als nieuwe image
Docker geeft een ontwikkelaar de mogelijkheid om een applicatie in te pakken samen met alle onderdelen die het nodig heeft, zoals bibliotheken en andere afhankelijkheden en deze aan te bieden als één pakket. Met Docker kun je op je eigen computer applicaties ontwikkelen en testen die later ergens anders moeten gaan draaien zonder je zorgen te maken over afhankelijkheden die op een andere computer mogelijk ontbreken.
Met Docker containers worden de afhankelijkheden geïsoleerd waardoor je meerdere containers kunt opzetten die allen de afhankelijkheden krijgen die ze nodig hebben. Dit maakt het ook eenvoudig om een app te verwijderen. Je hoeft alleen de container maar te verwijderen om de app kwijt te zijn zonder dat je bang hoeft te zijn dat er configuratiebestanden en tijdelijke bestanden achterblijven in het operating systeem.
Een Docker image is een pakket dat applicaties bevat met al hun afhankelijkheden. Wanneer een Docker image gestart wordt, dan wordt dat een Docker containter genoemd. Een dockerfile is een bestand waar de instructies in staan om een image te maken.
Docker Hub is een plaats waar je Docker images kunt vinden en waar jezelf Docker images kunt uploaden voor gebruik door anderen. Docker Registry is een lokale register service waar je Docker images opslaat en beheert.
Docker engine draait voornamelijk op Linux. Als je Docker op Windows of MacOS gebruikt, dan heb je eigenlijk een kleine Linux VM (Virtuele Machine) in de achtergrond draaien op je Windows of MacOS met daar boven op een Docker engine om je de Docker functionaliteit te geven op een niet-Linux platform.
Het verschil tussen Docker containers en Virtuele Machines
Docker containers virtualiseren het operating systeem en gebruiken één kernel om te functioneren, terwijl virtuele machines de hardware virtualiseren en elke virtuele machine zijn eigen kernel heeft. Containers zijn veel lichter en sneller dan virtuele machines. Meerdere containers kunnen op dezelfde host draaien zonder dat er meerdere exemplaren van het operating systeem nodig zijn.
De werking van Docker
Docker is een complete oplossing voor de productie, distributie en het gebruik van containers. Containers gebruiken eigenschappen van de Linux kernel om gedeeltelijk gevirtualiseerde omgevingen beschikbaar te maken.
Docker bestaat uit verschillende onderdelen. De Docker CLI is de opdrachtprompt voor Docker in de terminal. De CLI stuurt opdrachten naar de Docker deamon, die lokaal kan draaien, maar deze kan ook op een andere locatie draaien. De deamon is verantwoordelijk voor het beheer van containers en de images op basis waarvan die containers zijn gemaakt.
De container runtime gebruikt de mogelijkheden van de Linux kernel om containers te starten. Docker is compatibel met runtimes die voldoen aan de OCI (Open Container Initiative) specificatie. Deze open standaard zorgt voor interoperabiliteit tussen verschillende containerisatie gereedschappen.
De Docker workflow voor ontwikkelaars in stappen:
- Bouw een image met behulp van een Dockerfile, een Dockerfile is een gewoon tekstbestand waarin je de instructies zet voor wat je in de image wilt bundelen, zoals het basisbesturingssysteem, bibliotheken, toepassingen, omgevingsvariabelen en lokale bestanden.
- Verzend de image via de Docker Hub of een privérepository. Je kunt deze applicatie of ontwikkelomgeving nu heel eenvoudig verspreiden met Docker. Er zijn al vele officiële, vooraf gebouwde images aangeboden door softwareontwikkelaars, klaar voor gebruik.
- Voer een container uit op een hostcomputer. Het enige dat je nodig hebt, is dat Docker is geïnstalleerd om containers te kunnen uitvoeren, microservices te implementeren (dat wil zeggen verschillende containers met verschillende services te lanceren) en de omgeving te hebben die je nodig hebt voor ontwikkeling of implementatie.
Docker installeren
Je kunt Docker installeren op Linux, Windows of MacOS, de werking van Docker is verder gelijk.
Docker installeren in Ubuntu
# eerst zorgen dat alles is bijgewerkt:
sudo apt-get update
sudo apt-get dist-upgrade
# afhankelijkheden installeren, mochten die nog niet aanwezig zijn:
sudo apt-get install ca-certificates curl gnupg lsb-release
# Docker’s GPG sleutel toevoegen:
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# De repository voor Docker toevoegen:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# toegangsrechten aanpassen:
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# systeem weer bijwerken:
sudo apt-get update
# Docker installeren:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Controleren of Docker automatisch gestart is:
sudo systemctl status docker
# 'Hello World' als test:
sudo docker run hello-world
Meer info: docs.docker.com/engine/install/ubuntu/
Docker installeren in Fedora
dnf-plugins-core packages installeren:
sudo dnf -y install dnf-plugins-core
Docker repo instellen:
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
Docker installeren:
sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Docker starten:
sudo systemctl start docker
voortaan automatisch laten starten:
sudo systemctl enable docker
'Hello World' als test:
sudo docker run hello-world
Meer info: docs.docker.com/engine/install/fedora/
Geen sudo meer
Om te zorgen dat je niet steeds sudo moet gebruiken bij elke Docker opdracht, kun je jezelf toevoegen aan de docker groep. Meestal zal de docker groep al bestaan:
sudo groupadd docker
# je eigen gebruiker toevoegen aan de docker groep
sudo usermod -aG docker $USER
# controleren of het gelukt is:
groups kees
# 'kees' is hier de gebruiker
Je moet jezelf afmelden en weer aanmelden om deze wijzinging door te voeren, dan kun je Docker gebruiken zonder sudo. Je kunt dit testen door 'hello-world' te starten zonder sudo:
docker run hello-world
Mocht je toch nog een foutmelding krijgen ("WARNING: Error loading config file: ... permission denied") doordat je al eens Docker opdrachten hebt uitgevoerd via "sudo", dan kun je de rechten goed zetten met:
sudo chown "$USER":"$USER" /home/"$USER" /.docker -R
sudo chmod g+rwx "$HOME/.docker" -R
Docker versie
Je kunt kijken welke versie van Docker er geïnstalleerd is met:
docker info
Controleren of de Docker deamon actief is
Docker gebruikt een deamon die op de achtergrond draait om de CLI opdrachten te verwerken en om containers actief te houden. De melding "can’t connect to Docker daemon" kun je krijgen als de deamon niet draait.
Op een Linux systeem die met systemd werkt (dat zijn de meeste) kun je met systemctl controleren of de Docker deamon actief is:
sudo systemctl status docker
Als de deamon niet actief is (inactive), dan kun je deze starten met:
sudo systemctl start docker
Een Docker image starten
Als je nog niet weet welke Docker image je wilt hebben, dan kun je eerst zoeken met Docker search.
docker search ubuntu
Er zullen verschillende images beschikbaar zijn. Je kunt een Docker image ophalen van de Docker Hub en deze direct starten met de Docker run opdracht.
sudo docker run -it --name Ubuntu20 ubuntu:latest
Bovenstaande opdracht zal de image eerst lokaal zoeken, als deze daar niet te vinden is, dan zal het de image op de Docker Hub zoeken, ophalen en starten. De keren dat je run daarna gebruikt zal de image niet meer opgehaald hoeven te worden omdat deze dan lokaal te vinden is. De -it vlag ('interactive') zorgt ervoor dat je na het starten van de container in een shell terecht komt waar je opdrachten in kunt geven om uit te voeren. Met de --name vlag geef je de container een zelfgekozen naam.
Als je een image alleen wilt ophalen, zonder deze meteen te starten, dan kan dit met de pull opdracht:
sudo docker pull ubuntu:bionic
Poorten koppelen tussen de container en de host:
docker run -d -p 8080:80 mijn-website:v1
De -d vlag ('detached') zorgt ervoor dat de Docker CLI loskomt van de container, zodat deze op de achtergrond kan draaien. Het koppelen van de poort gebeurt met -p, hier wordt poort 8080 van de host gekoppeld aan poort 80 van de container.
Als je een image start, dan wordt het een container.
sudo docker run -it --name=Xenial -p 8080:80 5f981103eebc
De -it zorgt ervoor dat je in de container komt nadat deze is gestart. Met --name geef je de container een naam zodat je deze zelf eenvoudig kunt herkennen. Met -p verbind je een host poort met een container poort. De id is de unieke id van de image
Docker images opvragen
De docker pull opdracht zal de image van Ubuntu ophalen en lokaal neerzetten. Om deze image te starten heb je de id van de image nodig.
# opvragen welke images er zijn
# methode 1
docker images
# methode 2
docker image ls
Je kunt een filter gebruiken bij het opvragen van de images met de --filter optie. Je kunt filteren op reference, before, since, label en dangling. Filteren op reference kun je gebruiken om te filteren op images die een bepaalde naam of tag hebben:
docker images --filter "reference=ubuntu*"
Je kunt filteren op dangling. Je krijgt dan de images die ontdaan zijn van hun tag doordat je een nieuwe image hebt gemaakt met dezelfde naam en tag.
docker images --filter "dangling=true"
Om je images die "dangling" zijn op te ruimen kun je docker images purge gebruiken.
Filteren op datum met before of since werkt gek genoeg niet met datums, maar met het opgeven van een image als vergelijking.
# images die zijn aangemaakt voordat
# 'ubuntu' werd aangemaakt
docker images --filter "before=ubuntu"
# images die zijn aangemaakt nadat
# 'ubuntu' werd aangemaakt
docker images --filter "since=ubuntu"
De uitvoer van "docker images" kun je formatteren met --format. Hierbij kun je de volgende plaatshouders gebruiken: .ID, .Repository, .Tag, .Size, .CreatedSince, .CreatedAt en .Digest.
docker images --format "{{.Repository}} heeft de volgende ID: {{.ID}}"
Als je alleen maar de image id's wilt hebben, dan kun je -q of --quiet gebruiken:
docker images -q
Docker containers opvragen
De draaiende containers kun je opvragen met de docker container ls opdracht (dit is de opvolger van de "docker ps" opdracht die in oudere versies van Docker werd gebruikt), je krijgt dan een lijst met de draaiende containers met hun unieke container id, de image naam, de opdracht die wordt uitgevoerd als de container wordt gestart, de aanmaakdatum/tijd van de container, de status van de container, de poorten die de container gebruikt en de naam van de container:
docker container ls
Als je ook de containers wilt zien die zijn "^ gestopt "^, dan kun je -a of --all toevoegen aan de docker container ls opdracht:
docker container ls -a
Kolommen worden beperkt tot een bepaalde lengte. Indien de inhoud van een kolom te lang is wordt deze ingekort. Als je deze toch helemaal wilt zien, dan kun je --no-trunc gebruiken:
docker container ls --no-trunc
Als je ook de grootte van de containers wilt zien, dan kun je -s of --size gebruiken:
docker container ls -s
Met de -format optie kun je de uitvoer van de docker container ls opdracht verder vormgeven:
# alleen namen en statussen weergeven:
docker container ls --format 'table {{.Names}}\t{{.Status}}'
De \t in het bovenstaande voorbeeld is een tab.
Je kunt de uitvoer van docker container ls ook filteren met -f of --filter. Je kunt filteren op de volgende velden: id, name, label, exited, status, ancestor, since, volume, publish, health en isolation.
# filteren op de naam 'Xenial':
docker container ls --filter "name=Xenial"
# filteren op status 'exited':
docker container ls -f "status=exited"
# filteren op een id:
docker container ls --filter "id=5f981103eebc"
Voor het werken met de docker container ls opdracht in scripts kan het handig zijn om "^ alleen de id's "^ te krijgen van de draaiende containers in de uitvoer van docker container ls, zondere verdere informatie. Dit kan met -q:
docker container ls -q
Alleen de meest recent aangemaakt containers opvragen kan met de --last of -n optie:
# alleen de 2 meest recent aangemaakte containers tonen:
docker container ls -n 2
Alleen de laatst aangemaakte container tonen kan met de --latest of -l optie (dit is hetzelfde als "-n 1"):
docker container ls -l
Een opdracht uitvoeren met exec
Bij het starten van de container kom je via de -it (-i = verbinden met de terminal, -t = pseudo-TTY toewijzen) vlaggen in de container, met exit ga je er weer uit. Als je daarna in een draaiende container wilt komen, dan kun je de Docker exec opdracht gebruiken:
sudo docker exec -it Xenial /bin/bash
Hiermee start je een bash-shell. In plaats van het starten van een terminal zoals bash, kun je ook een 'losse' opdracht ingeven, dan kom je niet in een terminal, maar wordt alleen de opdracht uitgevoerd.
Je kunt ook een opdracht uitvoeren als root door gebruiker 0 aan te geven met -u 0:
docker exec -u 0 Xenial whoami
Je kunt ook meerdere opdrachten tegelijk opgeven om uit te voeren.
docker exec Xenial /bin/bash -c "uptime; whoami; date"
Een opdracht kun je uitvoeren vanaf een bepaalde locatie door deze op te geven met -w.
docker exec -w /usr/scripts Xenial mijnscript.py
Een terminalsessie stoppen zonder de container te stoppen
Docker containers hebben een interactieve modus waarmee je opdrachten via je terminal kunt laten uitvoeren in de container. Met Ctrl-C kun je deze interactieve modus stoppen, maar dit zal meestal ook de container stoppen. Docker heeft ook een mogelijkhed om je terminal sessie los te koppelen van een container zonder deze container te stoppen. De standaard toetscombinatie hiervoor is: Ctrl-P gevolgd door Ctrl-Q. Deze toetscombinatie kun je aanpassen als deze bijvoorbeeld een conflict geeft met een andere applicatie. Het aanpassen gaat door het configuratiebestand ~/.docker/config.json aan te passen.
Als voorbeeld het aanpassen van de 'detachKeys' naar Ctrl-D gevolgd door een D:
{
"detachKeys": "Ctrl-d,d"
}
Docker ondersteund voor de 'detachKeys' de a-z letters en de @, ^ en _ symbolen en ook de linker vierkante haak ([) en twee back slashes (\\). Deze moet je allemaal gebruiken in combinatie met de Ctrl-toets. Letters mogen ook afzonderlijk gebruikt worden, zonder de Ctrl-toets. De toetscombinaties moet je opgeven als een lijst die door komma's is gescheiden.
Je kunt de 'detachKeys' ook afzonderlijk per container aanpassen door toevoeging van de --detach-keys vlag aan de opdrachten docker run, docker start, docker exec of docker attach. Deze aanpassing heeft dan voorraang op wat je eventueel in het bestand ~/.docker/config.json hebt gezet.
Voorbeeld waarbij de 'detachKeys' voor 'mijn-container' worden aangepast naar Ctrl-D gevolgd door een D:
docker attach mijn-container --detach-keys="Ctrl-d,d"
Als de toetscombinatie voor de 'detachKeys' om de terminalsessie te stoppen zonder de container te stoppen niet werkt, dan kun je een tweede terminalsessie openeen en daar het docker.attach proces beëindigen dat bij de container hoort. Je moet dan eerst achter het PID-nummer van dit proces komen:
ps -ef | grep attach
Met het gevonden PID-nummer kun je het proces 'killen', in dit voorbeeld '678':
kill -9 678
Je kunt een terminal weer verbinden met de container via de docker attach opdracht:
docker attach mijn-container
Je kunt de invoer uitsluiten via de --no-stdin vlag. Je zult dan alleen uitvoer in de terminal zien, maar niets kunnen invoeren.
Als je de sessie stopt via Ctrl-C of exit, dan zal de $? variabele de exitcode van de container bevatten die je dan in je shell kunt opvragen.
Een Docker container stoppen
Een Docker container stoppen, in dit geval 'Xenial' kan met:
sudo docker stop Xenial
Een Docker container herstarten
Een gestopte container bestaat nog steeds en kun je herstarten met "docker start naam-van-container", in het volgende voorbeeld heet die container "Xenial":
sudo docker start Xenial
Containers draaien meestal zolang hun hoofdproces nog actief is. De "restart policies" bepalen wat er gebeurt als een container stopt of als een host herstart. Voeg --restart toe aan de "run" opdracht om een container onmiddelijk te herstarten als deze is gestopt.
Bestanden kopiëren naar een container
De Docker cp opdracht kun je gebruiken om bestanden van het host-systeem naar de container te kopiëren en andersom. Je hebt hiervoor de container id nodig of de naam van de container. De container id of de naam van de container wordt gevulgd door een dubbele punt en dan het pad en de naam van het te kopiëren bestand.
Als voorbeeld wordt hier de container id "5f981103eebc" gebruikt en het bestand "data.txt" en de locatie in de container "/var/files":
# bestand van host naar container kopiëren:
sudo docker cp data.txt 5f981103eebc:/var/files/data.txt
# bestand van container naar host kopiëren:
sudo docker cp 5f981103eebc:/var/files/data.txt data.txt
Je kunt met cp ook hele directories kopiëren.
docker cp /home/demo/website apache-container:/var/www/html/
Docker zal alles in "/home/demo/website" kopiëren en plaatsen in "/var/www/html".
Als je een bestand kopiëert, dan maakt Docker een nieuw bestand aan op de bestemming als deze nog niet bestaat. Als het bestand al wel bestaat, dan zal het worden overschreven. Als de bestemming een directory is, dan wordt het bestand gekopiëert en geplaatst in de directory met de naam van het originele bestand. Uitzondering is als de bestemming eindigt op een slash /, wat een directory aangeeft en als die directory nog niet bestaat, dan zal er een foutmelding komen.
Bij het kopiëren van directories zal een nieuwe directory gemaakt worden op de bestemming met de inhoud van de bron directory als de directory op de bestemming nog niet bestaat. Als deze al wel bestaat, dan hangt het er van af of er een slash aan het einde van het pad staat.
Wel een slash op het einde: de bron directory wordt in de bestemming gekopiëert.
Geen slash op het einde: de inhoud van de bron directory wordt in de bestemming gekopiëert.
Het verschil tussen wel of geen slash bepaalt of er wel of geen nieuwe directory wordt aangemaakt in de bestemming
De docker cp opdracht lijkt op de shell cp opdracht, echter, de docker cp opdracht is veel beperkter en ondersteund slechts 2 vlaggen: -a en -L.
-a – Archival mode, dit behoudt de gebruiker en groep instellingen op gekopiëerde bestanden.
-L – Volgt symlinks in de bron directory om de inhoud van de link doelen te kopiëren, in plaats van de links zelf.
Een Docker container verwijderen
Om een Docker container te verwijderen, moet je deze eerst stoppen en dan kun je deze verwijderen met de rm opdracht:
sudo docker rm Xenial
Alle containers in één keer stoppen en verwijderen kan met:
# alle containers stoppen:
docker stop $(docker container ls -a -q)
# alle containers verwijderen:
docker rm $(docker container ls -a -q)
Een Docker image verwijderen
Een image die je lokaal hebt staan kun je verwijderen met de rm opdracht. Je moet eerst de containers stoppen en verwijderen die gebruik maken van die image. Daarna kun je de image zelf verwijderen, je hebt daarvoor de id van de image nodig (in dit voorbeeld: "5f981103eebc").
sudo docker image rm 5f981103eebc
Docker images, containers en volumes opschonen met prune
Docker images kunnen erg groot zijn en als je veel met containers werkt, dan kunnen deze veel opslagruimte in beslag nemen. Je kunt grote schoonmaak houden met de Docker prune opdracht. De docker system prune opdracht verwijdert ongebruikte gegevens uit je Docker systeem. Standaard verwijdert deze opdracht gestopte containers, dangling images en niet gebruikte netwerken en volumes.
Images zijn read-only bestanden die zijn gebouwd van Dockerfiles en gepushed zijn naar de Docker Hub. Elke keer als je een nieuwe versie download moet Docker de bestanden voor die nieuwe versie downloaden. Oude versies blijven opgeslagen op je systeem. Containers worden gemaakt van images. Wanneer je een container stopt zullen gegevens die niet in een volume zijn opgeslagen worden gewist. Dus om ruimte die door containers wordt gebruikt op te schonen, hoef je ze alleen maar te stoppen en hun volumes te wissen.
De docker system prune opdracht heeft een --force vlag waarmee je automatisch zonder verdere vragen ongebruikte gegevens kunt verwijderen. Dit is makkelijk, maar het verwijderen is definiteif en kan niet ongedaan worden gemaakt, dus je moet er voorzichtig mee zijn, zeker in een productie omgeving.
Het hele systeem opschonen:
sudo docker system prune
De images opschonen:
docker image prune -a
Met de -a vlag geef je aan dat alleen images die actief worden gebruikt bewaard moeten worden.
Docker verwijdert containers en volumes niet automatisch, tenzij je containers start met de --rm vlag.
De overbodige containers verwijderen:
docker container prune
Overbodige volumes verwijderen:
docker volume prune
Overbodige netwerken verwijderen:
docker network prune
Om bestanden en directories uit te sluiten van toevoeging aan een image, kun je een .dockerignore bestand maken in de context directory. De syntax van een .dockerignore bestand lijkt op Git’s .gitignore bestand.
Een image maken
Op basis van een Dockerfile kan een image gemaakt worden:
docker build -t mijn-website:v1 .
In de terminal zie je de uitvoer van de instructies uit je Dockerfile voorbij komen als je image wordt gemaakt.
De -t in de opdracht geeft je image een "tag" met de naam die je opgeeft (mijn-website:v1). Dit maakt het eenvoudiger om naar deze image te verwijzen. Tags bestaan uit twee gedeelten, deze worden gescheiden door een dubbele punt ':'. Het eerste deel is de naam van de image en het tweede deel is de versie. Als je de dubbele punt weglaat, dan zal Docker latest als de versie gebruiken.
De . aan het einde van de opdracht geeft aan dat de Dockerfile uit je lokale "working directory" gebruikt moet worden. Deze directory wordt vervolgens ook gebruikt bij de COPY opdrachten in je Dockerfile.
Docker images worden gevormd in lagen. Iedere opdracht in je Dockerfile maakt een nieuwe laag. Je kunt geavanceerde bouw mogelijkheden gebruiken om te verwijzen naar meerdere basis images en tussenliggende lagen van eerdere images negeren.
Labels gebruiken
Met Docker labels kun je willekeurige metadata toevoegen aan containers, images, volumes en andere bronnen. Labels zijn bedoeld als een vrij te gebruiken klassificatiesysteem die je kunt aanpassen aan je eigen behoeften. Je kunt labels gebruiken met de volgende Docker objecten: Containers, Images, Volumes, Netwerken, Daemons en Swarm nodes en services. Deze ondersteunen allemaal de label vlag als onderdeel van de opdrachten voor deze objecten.
Een label wordt toegevoegd tijdens het maken van een object, ze kunnen later niet meer worden aangepast. Uitgezonderd zijn labels die zijn toegevoegd aan Docker Swarm nodes en services, deze kunnen altijd dynamisch worden aangepast.
De --label vlag wordt gebruikt om labels in te stellen. Elk label is een sleutel-waardekey-value paar waarbij de sleutel en de waarde worden gescheiden door het "is gelijk" teken (=):
docker run mijn-image:latest --label demo-label=voorbeeld-waarde
Label sleutels mogen kleine letters en cijfers, punten (.) en streepjes (-) bevatten. Ze moeten starten en eindigen met een kleine letter of cijfer. De DNS notatie regels worden gevolgd wat betekent dat meerdere punten of streepjes achter elkaar niet zijn toegestaan.
Label waarden mogen elke tekst bevatten.
Voor het soepeler laten verlopen van de uitwisseling in het Docker ecosysteem zijn er enkele rcihtlijnen met betrekking tot de benamimg van de labels. Het advies is om net zoals bij "app stores" en "package managers" de omgekeerde DNS notatie te gebruiken:
docker run mijn-image:latest --label nl.voorbeeld.demo-label=voorbeeld-waarde
Deze methode voorkomt benamingsconflicten wanneer labels worden ingesteld door gereedschappen in je build systeem. Deze gereedschappen stellen vaak zelf labels in voor de Docker objecten die ze maken om deze te kunnen volgen en beheren. Docker staat geen dubbele labelsleutels toe en zal de laatst toegewezen gebruiken als er een labelsleutel meerdere malen wordt toegewezen.
Docker reserveert enkele -namespaces* voor intern gebruik door de CLI. Deze kun je daarom maar beter niet gebruiken: com.docker.*, io.docker.*, org.dockerproject.* (niet verboden, maar sterk afgeraden). Begin al je labels met je eigen domeinnaam tenzij je een belangrijke reden hebt om dat niet te doen.
Labels kun je bekijken met de Docker inspect opdracht voor containers en images. Voor netwerken en volumes zijn er de inspect sub-opdrachten zoals docker network inspect mijn-netwerk
De uitvoer van de Docker inpect opdracht kan onoverzichtelijk zijn, maar met behulp bam de --format vlag en het programma jq (moet dan wel geïnstalleerd staan) kun je daar iets aan doen:
docker inspect mijn-container --format='{{json .Config.Labels}}' | jq
Het aan te raden om de Pre-Defined Annotation Keys te gebruiken om te zorgen dat je LABELs bruikbaar zijn in gereedschappen die op LABELs filteren. Enkele 'standaard' labels: .created, .url, .version, .licenses en .title.
Tags gebruiken
Docker gebruikt tags om verschillende versies van een image te onderscheiden. Als je images ook door anderen kunnen worden gebruikt, dan moet je tags gebruiken om de verschillen tuusen de verschillende versies aan te geven zodat gebruikers weten welke ze moeten kiezen. Behalve de versie kun je met een tag ook nog de variant meegeven:
mijn-website:1.1.0-apache
mijn-website:1.1.0-nginx
mijn-website:1.2.0-apache
mijn-website:1.2.0-nginx
Bovenstaande tags laten een gebruiker niet alleen de versie kiezen, maar ook de variant: Apache of NGINX.
Bij het bouwen ("docker build") van een image kun je met de -t vlag de image een tag geven. Je kunt een reeds bestaande image een nieuwe tag geven met de Docker tag opdracht.
De tag opdracht kent twee argumenten: een bestaande tag die een image aangeeft en een nieuwe tag die moet worden toegewezen aan deze image:
docker tag mijn-website:1.1.0 mijn-website:1.1.0-apache
Beide tags zullen nu verwijzen naar dezelfde image en je kunt ze beide willekeurig gebruiken. De opdracht docker pull mijn-website:1.1.0 uitvoeren zal echter geen effect hebben op de "1.1.0-apache" tag. De verwijzing van een tag wordt niet bijgewerkt tenzij je deze handmatig toevoegt in een CLI opdracht. De enige uitzondering op deze regel is de latest tag. Wanneer je met de "pull" opdrachte een 'kale' image zonder een tag opvraagt, zoals "docker pull mijn-website", dan gebruikt Docker impliciet latest als tag.
Als je een "latest" image al in je systeem hebt en je nogmaals een "latest" ophaalt via de "pull" opdracht, dan zal alleen de laatst opgehaalde image de tag "latest" hebben, de eerder opgehaalde image zal nu geen tag meer hebben. Om deze tag-loze image toch weer een tag te geven, mag je naar deze immage ook verwijzen met de image id:
docker tag 5f981103eebc mijn-website:oud
Je kunt tags verwijderen van een image met de rmi opdracht, maar als er geen tag meer overblijft, dan zal Docker de hele image verwijderen. Docker zal in dat geval geen tag-loze image achterlaten.
docker rmi mijn-website:1.1.0-apache
Docker Hub
Je kunt je image naar een register sturen (push). Registers zorgen voor een centrale opslag zodat je je images kunt delen met anderen. Het standaard register is Docker Hub.
Als je een opdracht geeft die verwijst naar een image, dan zal Docker eerst kijken of deze lokaal te vinden is, als dat niet het geval is, dan zal Docker gaan zoeken op Docker Hub.
Je kunt een image ophalen met de pull opdracht:
docker pull httpd:latest
Als je een image wilt publiceren, dan moet je eerst een account op Docker Hub aanmaken. Meldt je dan aan via docker login en geef je gebruikersnaam en je wachtwoord op.
Tag je image met je gebruikersnaam:
docker tag mijn-image:latest docker-hub-gebruikersnaam/mijn-image:latest
Dan is het tijd om je image via de "push" opdracht naar de Docker Hub te sturen:
docker push docker-hub-gebruikersnaam/mijn-image:latest
Andere gebruikers kunnen nu ook jouw image gaan gebruiken om containers te starten.
Docker logs
Wanneer iets niet werkt zoals het zou moeten werken, dan wil je graag de logs inzien om uit te zoeken wat er misgaat. Docker verzamelt automatisch de uitvoer van draaiende containers. Alle uitvoer van stdout (standard output) en stderr (standard error) van alles wat in de container draait wordt in de logs opgeslagen.
Het "loggen" in Docker is niet hetzelfde als het loggen wat je normaal in een Linux systeem ziet. In Docker wordt alles wat naar stdout en stderr streams geschreven wordt impliciet naar een logging stuurprogramma gezonden. Dit stuurprogramma geeft een methode om de streams in te zien en slaat de logs op in een bestand. Het standaard stuurprogramma voor Docker logs is 'json-file', deze slaat de logs op in JSON formaat. Logs opgeslagen in een container zullen worden gewist als de container wordt gestopt of wordt beëindigd.
Met de volgende opdracht kun je het huidige Logging stuurprogramma opvragen:
docker info --format '{{.LoggingDriver}}'
Als je het standaard stuurprogramma gebruikt voor het loggen, dan worden de logs in JSON formaat opgeslagen in: /var/lib/docker/containers/ in de directory met als naam de ID van de container.
Om de logs te bekijken, kun je de Docker logs opdracht gebruiken in combinatie met de ID van de container:
docker logs 5f981103eebc
De --follow vlag stelt een doorlopende stream in zodat je de logs in 'real-time' kunt volgen.
docker logs -follow 5f981103eebc
Alleen de laatste regels zien van een log kan met de --tail vlag:
docker logs --tail 10 5f981103eebc
Logs bekijken vanaf een bepaald moment kan met de --since vlag:
docker logs --since 30m 5f981103eebc
Bovenstaande toont de logs van de laatste 30 minuten. Je kunt ook een datum in ISO formaat gebruiken met de --since vlag:
docker logs --since 2023-01-10T08:00:00 5f981103eebc
Logs bekijken tot een bepaald moment kan met de --until vlag:
docker logs --until 30m 5f981103eebc
docker logs --until 2023-01-10T08:00:00 5f981103eebc
Docker in productie omgevingen
Docker wordt meestal niet zelfstandig in productie omgevingen gebruikt. Vaak worden Kubernetes of Docker Swarm mode gebruikt. Deze gereedschappen zijn ontworpen om meerdere replica's van containers te beheren om zodoende de schaalbaarheid en de betrouwbaarheid te verhogen.
Schijfgebruik opvragen
Als je wilt weten hoeveel schijfruimte gebruikt, dan kun je de Docker opdracht docker system df gebruiken of de Linux opdracht du om de omvang van de hele directory te krijgen.
# via Docker:
docker system df
# via Linux:
sudo du -sh /var/lib/docker/
Deze opdracht toont statische images, containers die aanpassingen hebben gedaan aan hun bestandssysteem, zoals logbestanden, en volumes gekoppeld aan de containers. Wat niet wordt meegenomen zijn de "bind mounts" op de host.
De locaties die Docker gebruikt verschillen per operating systeem:
- Linux: /var/lib/docker/
- Windows: C:\ProgramData\DockerDesktop
- macOS: ~/Library/Containers/com.docker.docker/Data/vms/0/
Een lijst van de containers met hun schijfgrootte erbij (wederom zonder de "bind mounts"):
docker container ls --size
Om het "mount" gebruik te bepalen, voor zowel directe bind mounts als voor beheerde volumes, zul je de grootte hiervan moeten opvragen bij de host. Als je niet weet waar deze zich bevinden, dan kun je deze opvragen. Vraag eerst de "id" van de container op met docker container ls en gebruik dan docker inspect om de mount informatie op te vragen:
docker inspect 5f981103eebc -f '{{json .Mounts}}'
Vervolgens kun je de totale omvang opvragen met du -sh:
sudo du -sh /pad/naar/mount/
De gebruikte schijfruimte vna een container kun je ook vanuit de container zelf opvragen. Open een shell in de container (in dit voorbeeld met de id '5f981103eebc'):
sudo docker exec -it 5f981103eebc /bin/bash
Je kunt nu met de opdracht sudo du -sh / alle gebruikte schijfruimte opvragen, inclusief de image grootte, de bind mounts en de volumes.
CPU, RAM en netwerk gebruik opvragen
Docker neemt minder systeembronnen in beslag als traditionele VM's, maar als je meerdere containers tegelijk hebt draaien kan het toch nuttig zijn om te zien welke systeembronnen in beslag worden genomen door deze containers. De Docker opdracht om het gebruik van systeembronnen te bekijken is docker stats.
Om het huidige CPU, RAM en netwerk gebruik te zien van draaiende containers:
docker stats
Gestopte containers kun je erbij krijgen met de -a (--all) vlag.
Je kunt de gegevens van een beperkt aantal zelf op te geven containers opvragen door de ID's of namen van deze containers als lijst mee te geven (gescheiden door spaties), de gegevens van de andere containers worden dan weg gelaten.
docker stats eerste-container tweede-container
Met de --format vlag kun je een formaat opgeven voor de uitvoer.
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
De aanduiding 'table' in het bovenstaande zorgt ervoor dat ook de kolomkoppen worden getoond, als je deze aanduiding weglaat, dat krijg je alleen de gegevens van de containers zonder kolomkoppen erbij.
Om Docker's netwerk configuratie te zien:
docker network ls
Processen in een bepaalde container zien kan met docker top:
docker top mijn-container
Om het gebruik van systeembronnen per proces in een container te bekijken kun je top of htop installeren in de container. Hier een voorbeeld met 'apt' als package manager:
docker exec -it mijn-container sh
apt update && apt install htop -y
htop
Docker API
De Docker API kun je gebruiken via de Docker daemon’s Unix socket. Het /containers/{id}/stats eindpunt geeft uitgebreide details over het gebruik van systeembronnen. Vervang {id} door de ID van je container. De versie van de Docker API (hier: v1.41) kun je opvragen met docker version.
curl --unix-socket /var/run/docker.sock "http://localhost/v1.41/containers/{id}/stats" | jq
In het bovenstaande voorbeeld wordt curl gebruikt met de --unix-socket vlag. De Docker API geeft informatie terug in JSON formaat. Deze informatie wordt via een "pipe" naar jq gestuurd (dit moet dan wel al op je systeem geïnstalleerd staan) om beter leesbaar te zijn in de terminal.
De draaiende processen in een container kun je ook via de Docker API opvragen:
curl --unix-socket /var/run/docker.sock "http://localhost/v1.41/containers/{id}/top
Containers automatisch herstarten
Een webserver als NGINX wil je waarschijnlijk non-stop hebben draaien. Docker heeft hier een aantal mogelijkheden voor:
Een container starten en automatisch laten herstarten tenzij deze is gestopt of Docker is herstart kan met --restart unless-stopped:
docker run -d --restart unless-stopped nginx
Een reeds draaiende container automatisch laten herstarten kan met --restart unless-stopped:
docker update --restart unless-stopped nginx
Alle containers automatisch laten herstarten tenzij deze expliciet zijn gestopt kan met --restart unless-stopped $(docker ps -q):
docker update --restart unless-stopped $(docker container ls -q)
Een container altijd laten herstarten, zelfs als deze handmatig is gestopt kan met --restart always:
docker update --restart always nginx
Een container alleen automatisch herstarten als er een fout is geweest kan met --restart on-failure:
docker update --restart on-failure nginx
Het automatisch herstarten weer uitzetten kan met --restart no:
docker update --restart no nginx
Een image opslaan als .tar en weer inlezen
Je kunt een Docker image opslaan als .tar bestand en dat .tar bestand, bijvoorbeeld op een ander systeem, weer inlezen. Hiervoor heeft Docker de save en load opdrachten.
Vraag de naam van de image op die je wilt opslaan, bijvoorbeeld met docker image list:
docker image list
Je kunt met de Docker save opdracht een image opslaan, gebruik -o of --output om een bestandsnaam op te geven voor het .tar bestand:
docker save -o ubuntu.tar ubuntu
Een image inladen kan met de Docker load opdracht, gebruik -i of --input om een bestandsnaam op te geven:
docker load -i ubuntu.tar
Aanpassingen in een container opslaan als nieuwe image
Aanpassingen die je doet in een container verdwijnen weer zodra de container ophoudt met bestaan. Om de aanpassingen in een bestaande container permanent te maken moet je van de container een nieuwe image maken. De beste methode om dit te doen is het maken van een dockerfile. Soms is het echter eenvoudiger om van een bewerkte bestaande container een nieuwe image te maken. Dit kan met de docker commit opdracht.
De "docker commit" opdracht heeft twee parameters: naam van de container en naam van de nieuwe image.
docker commit originele_container nieuwe_image
Docker zal alleen het verschil tussen de twee images opslaan. De nieuwe image erft de basislaag van de originele image en alleen de aanpassingen worden als nieuwe laag opgeslagen, zo wordt er zuinig omgesprongen met de opslagruimte.