SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-13

Docker installeren op Rocky Linux en AlmaLinux

Installeer Docker Engine op Rocky Linux of AlmaLinux via dnf. Leer hoe u conflicten met podman oplost en SELinux-fouten bij bind-mounts voorkomt voor een veilige configuratie.

Docker installeren op Rocky Linux en AlmaLinux

Om Docker te installeren op Rocky Linux of AlmaLinux voegt u de eigen dnf-repository van Docker toe, installeert u de engine inclusief de compose-plugin en schakelt u de service in. Dit proces bestaat uit vier commando's en is identiek op beide distributies, aangezien beide rebuilds zijn van Red Hat Enterprise Linux (RHEL) en dezelfde pakketstructuur delen. CentOS Stream werkt op dezelfde manier.

De installatie is kort, dus het grootste deel van deze handleiding behandelt de verschillen tussen Enterprise Linux (EL) en Ubuntu. Podman kan het docker-commando op uw image al hebben geclaimd. SELinux blokkeert bind-mounted bestanden totdat deze het juiste label hebben gekregen. Firewalld filtert de gepubliceerde poorten van Docker niet, waardoor een containerpoort open kan staan voor het internet terwijl firewall-cmd rapporteert dat er niets openstaat.

Gebruik niet het gemaksscript van Docker via get.docker.com. De eigen documentatie van Docker geeft aan dat dit niet wordt aanbevolen voor productieomgevingen. Het herschrijft uw repository-configuratie zonder toestemming en kan niet veilig opnieuw worden uitgevoerd voor upgrades. Door de repository handmatig toe te voegen, behandelt dnf upgrade Docker als elk ander pakket op het systeem.

Beantwoordt podman al het docker-commando?

Rocky Linux en AlmaLinux leveren podman in hun standaardrepositories en veel VPS-images installeren dit automatisch voor u. Sommige images gaan verder en installeren podman-docker, wat een shellscript plaatst op /usr/bin/docker dat podman aanroept. Elk docker-commando dat u typt, voert vervolgens podman uit, waardoor een handleiding die voor Docker is geschreven resultaten geeft die u niet verwachtte.

Het eerste teken is een banner. Het /usr/bin/docker-script controleert op het bestand /etc/containers/nodocker, en wanneer dat bestand ontbreekt, print het één regel voordat het iets uitvoert:

Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.

Iemand kan dat bestand hebben aangemaakt om de banner te onderdrukken, dus vertrouw hier niet alleen op. Vraag de pakketdatabase welk pakket de binaire eigenaar is:

command -v docker
rpm -qf "$(command -v docker)"

Een antwoord dat begint met podman-docker betekent dat podman antwoordt. Een antwoord dat begint met docker-ce-cli betekent de echte Docker. Als rpm -qf rapporteert dat geen enkel pakket eigenaar is van het bestand, heeft iemand het handmatig geïnstalleerd en dient u het script te lezen voordat u het vertrouwt.

Podman voert dezelfde OCI-images uit en is een redelijke keuze. Als u dit wilt, stop dan hier. Als u Docker Engine wilt, verwijder dan eerst de conflicterende pakketten. Dit is de lijst die Docker documenteert voor RHEL:

sudo dnf remove docker docker-client docker-client-latest docker-common \
  docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc

Lees wat dnf van plan is mee te nemen voordat u bevestigt. Op een verse VPS-image is de lijst kort. Op een server die al in gebruik is, kan het verwijderen van podman leiden tot het verwijderen van cockpit-podman of een andere tool die ervan afhankelijk is.

Het behouden van podman naast Docker is in principe mogelijk: verwijder alleen podman-docker, zodat de naam docker vrijkomt, en runc, dat door het pakket containerd.io wordt vervangen. De documentatie van Docker behandelt podman als een conflicterend pakket, dus deze configuratie wordt niet door Docker ondersteund. Als de installatie nog steeds een conflict rapporteert, gebruik dan de volledige verwijderingslijst hierboven.

Docker-repository toevoegen met dnf config-manager

Docker publiceert RPM's voor Enterprise Linux op download.docker.com. Het repository-bestand verwijst naar de CentOS-tree, waarop Rocky Linux en AlmaLinux hun afhankelijkheden oplossen. Gecontroleerd in augustus 2026: Docker documenteert deze repository voor CentOS Stream 9 en CentOS Stream 10.

sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Versie 5 van dnf heeft het --add-repo-argument verwijderd, waardoor het tweede commando op nieuwere releases faalt. Controleer welke versie u heeft en kies de bijbehorende vorm:

dnf --version

Als de output een 5.x-versie toont, gebruik dan de subcommand-vorm:

sudo dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/centos/docker-ce.repo

Beide commando's schrijven hetzelfde bestand naar /etc/yum.repos.d/docker-ce.repo. De onjuiste vorm resulteert in een foutmelding over een onbekend argument in plaats van een stille fout, dus u zult dit niet missen.

Dat repo-bestand stelt baseurl in op een pad dat $releasever bevat, en dnf breidt die variabele uit op basis van uw release-pakket. Rocky Linux en AlmaLinux stellen dit in op het major-versienummer, dus 9 op EL 9 en 10 op EL 10. Daarom wordt een CentOS-repository correct opgelost op een Rocky-systeem. Controleer de uitbreiding voordat u de installatie uitvoert:

sudo dnf repoinfo docker-ce-stable

Lees de Repo-baseurl-regel. Deze moet eindigen op /9/x86_64/stable of /10/x86_64/stable. Als uw release $releasever instelt op een puntversie zoals 9.6, rapporteert dnf Status code: 404 voor die URL bij het ophalen van metadata. Los dit op door /etc/yum.repos.d/docker-ce.repo te bewerken en $releasever te vervangen door het kale major-nummer.

De engine en de compose-plugin installeren

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Er zijn vijf pakketten, die elk een specifieke taak uitvoeren. docker-ce is de daemon, dockerd. docker-ce-cli is het docker-commando dat u invoert. containerd.io is de container-runtime die door de daemon wordt aangestuurd. docker-buildx-plugin bouwt images. docker-compose-plugin levert docker compose als subcommando.

Deze pakketten installeren geen docker-compose-binary met een koppelteken. Dat was Compose v1, waarvan de ondersteuning in juli 2023 is beëindigd. Alles wat docker-compose met een koppelteken aanroept, moet worden bijgewerkt naar docker compose met een spatie.

De eerste installatie pauzeert om de ondertekeningssleutel van Docker te importeren en toont u de vingerafdruk. De sleutel is afkomstig van gpgkey=https://download.docker.com/linux/centos/gpg in het repo-bestand dat u zojuist heeft toegevoegd; vergelijk de vingerafdruk die dnf toont met die URL voordat u deze accepteert.

Eén fout komt vaak genoeg voor om te benoemen. Als dnf meldt dat containerd.io afhankelijk is van container-selinux en dit niet kan worden gevonden, dan is uw AppStream-repository uitgeschakeld. Voer dnf repolist uit en controleer of appstream in de lijst staat, aangezien container-selinux daar wordt geleverd op EL 9 en EL 10.

Start Docker en bevestig dat het draait

sudo systemctl enable --now docker
sudo systemctl status docker --no-pager
sudo docker run --rm hello-world

De RPM-pakketten van Docker laten de daemon na installatie gestopt en uitgeschakeld. Daarom staat deze stap op de CentOS-pagina van Docker en niet op de Ubuntu-pagina, waar het deb-pakket de service automatisch voor u start. Sla enable over en Docker draait tot de volgende herstart, waarna het uitgeschakeld blijft en alle containers meeneemt.

systemctl status hoort Active: active (running) te tonen. De hello-world container hoort This message shows that your installation appears to be working correctly. te printen en af te sluiten. Als er in plaats daarvan een permissiefout op /var/run/docker.sock verschijnt, heeft u sudo overgeslagen; de sectie over de docker-groep hieronder lost dit op.

Controleer de compose-plugin afzonderlijk, aangezien dit een ander pakket is dat kan ontbreken terwijl de engine correct functioneert:

docker compose version

Een correct resultaat ziet eruit als Docker Compose version v2.x.x. Het automatisch herstellen van uw services na een herstart is een andere kwestie dan het inschakelen van de daemon, en restart policies bepalen of Compose-services automatisch opstarten.

Waarom geeft een bind mount een permission denied-fout?

Rocky Linux en AlmaLinux draaien SELinux (Security-Enhanced Linux) standaard in enforcing-modus. Controleer dit met getenforce, wat Enforcing weergeeft.

Docker-containers draaien onder het SELinux-type container_t, en dit type mag alleen bestanden lezen en schrijven die het label container_file_t hebben. Een map die u op de host aanmaakt, krijgt het label van het bovenliggende pad, wat niet container_file_t is. De container krijgt geen toegang, ook al lijken de eigenaar, groep en rechten vanaf de host correct. U kunt dit reproduceren met drie commando's:

sudo mkdir -p /srv/site
echo hello | sudo tee /srv/site/index.html
sudo docker run --rm -v /srv/site:/usr/share/nginx/html:ro nginx:alpine cat /usr/share/nginx/html/index.html

De container geeft de volgende melding:

cat: can't open '/usr/share/nginx/html/index.html': Permission denied

Twee commando's tonen de oorzaak. ls -ldZ /srv/site toont het label, dat voor een pad onder /srv gelijk is aan system_u:object_r:var_t:s0, en niet container_file_t. Vervolgens toont sudo ausearch -m avc -ts recent het audit-logboek van de kernel, dat avc: denied { read } bevat, een scontext=-veld met de naam container_t, en een tcontext=-veld met het label dat u zojuist op de map zag. Het verschil tussen deze twee velden is de volledige oorzaak.

De oplossing is een achtervoegsel aan het volume-argument. Docker herlabelt het pad dan voor u:

sudo docker run --rm -v /srv/site:/usr/share/nginx/html:ro,z nginx:alpine cat /usr/share/nginx/html/index.html

:z in kleine letters herlabelt de inhoud als gedeeld, zodat meerdere containers dezelfde map kunnen gebruiken. :Z in hoofdletters herlabelt het als privaat en niet-gedeeld, gekoppeld aan één container; een tweede container die hetzelfde pad leest, krijgt dan geen toegang. Gebruik :z voor alles wat ook door een sidecar- of backup-container wordt benaderd. Gebruik :Z voor een databasemap die eigendom is van één container.

De documentatie van Docker bevat een waarschuwing die het herhalen waard is, omdat het herlabelen recursief is. Het bind-mounten van een systeemmappen zoals /home of /usr met :Z "maakt uw hostmachine onbruikbaar en het kan nodig zijn om de bestanden op de hostmachine handmatig te herlabelen". Gebruik deze achtervoegsels alleen voor mappen die u zelf voor de container heeft aangemaakt, nooit voor een systeempad.

In Compose plaatst u het achtervoegsel in dezelfde string:

services:
  web:
    image: nginx:alpine
    volumes:
      - /srv/site:/usr/share/nginx/html:ro,z

Twee beperkingen zijn gemakkelijk over het hoofd te zien. De vlag --mount kan geen SELinux-label instellen, gebruik daarom -v wanneer u er een nodig heeft. Benoemde volumes hebben geen achtervoegsel nodig, omdat Docker de mappen die het aanmaakt onder /var/lib/docker/volumes zelf van labels voorziet.

Zet SELinux niet uit. Gebruik sudo setenforce 0 alleen als een test van één minuut: als de container daarna wel werkt, is het probleem een label en is :z de oplossing. Zet het direct terug met sudo setenforce 1. Op Enterprise Linux heeft permission denied bij een bind mount twee afzonderlijke oorzaken die er vanuit de container identiek uitzien. De ene is het SELinux-label. De andere is het gewone numerieke eigendom van gebruiker en groep, wat de reden is waarom de PUID- en PGID-variabelen bestaan. ls -lnZ toont u de rechten, de numerieke eigenaar en het label op één regel, zodat u kunt zien met welk probleem u te maken heeft.

Waarom is een gepubliceerde poort bereikbaar terwijl firewalld gesloten lijkt?

Firewalld is de standaard firewall op Rocky Linux en AlmaLinux. Controleer of deze actief is met sudo systemctl is-active firewalld. Publiceer nu een poort en bekijk welke poorten volgens firewalld openstaan:

sudo docker run -d --name web -p 8080:80 nginx:alpine
sudo firewall-cmd --list-ports

firewall-cmd geeft een lege regel terug. Vanaf een andere machine geeft curl -I http://YOUR_SERVER_IP:8080/ het resultaat HTTP/1.1 200 OK. De poort staat open voor het internet, terwijl uw firewall niets rapporteert.

De oorzaak is het pad dat het pakket aflegt. De zone-regels van firewalld filteren verkeer dat gericht is aan de host zelf. Een gepubliceerde poort is niet gericht aan de host: Docker installeert een destination NAT (network address translation) regel die de bestemming herschrijft naar het adres van de container voordat het pakket het input-pad van de host bereikt. De kernel stuurt het pakket daarom door in plaats van het lokaal af te leveren. Docker plaatst zijn bridge-interfaces vervolgens in een firewalld-zone genaamd docker met als target ACCEPT, en voegt een forwarding-beleid genaamd docker-forwarding toe dat forwarding toestaat vanuit elke zone naar de docker-zone. Uw zone-regels zien het pakket hierdoor nooit.

De schoonste oplossing vereist geen firewall-regel. Bind de host-zijde van de publicatie aan de loopback en plaats er een reverse proxy voor:

sudo docker rm -f web
sudo docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpine
curl -I http://127.0.0.1:8080/

De lokale curl geeft HTTP/1.1 200 OK terug en hetzelfde verzoek vanaf een andere machine maakt geen verbinding meer. Alles zonder host-adres in het -p-argument wordt op elke interface gepubliceerd; beschouw een kale -p 8080:80 daarom als een besluit om die service publiek toegankelijk te maken.

Wanneer u een service wel bereikbaar wilt maken vanaf bepaalde adressen en niet vanaf andere, reserveert Docker een chain voor u. DOCKER-USER wordt verwerkt vóór de eigen accept-regels van Docker. Een regel die u hier plaatst, blijft dus behouden nadat Docker herstart en zijn chains herschrijft:

sudo iptables -I DOCKER-USER -i enp1s0 ! -s 203.0.113.10 -j DROP
sudo iptables -S DOCKER-USER

Gebruik de interfacenaam uit ip route show default in plaats van uit te gaan van eth0, aangezien huidige EL-images namen gebruiken zoals enp1s0 of ens3. Op Rocky en AlmaLinux is het iptables-commando een compatibiliteitslaag bovenop nftables, en de chains van Docker zijn hierdoor zichtbaar. Regels die op deze manier worden toegevoegd, verdwijnen na een reboot tenzij u ze opslaat; schrijf ze daarom in een systemd-unit zodra u tevreden bent met de configuratie.

Docker Engine 28.0, uitgebracht in 2025, heeft een vergelijkbaar lek gedicht: directe gerouteerde toegang tot containerpoorten die nooit zijn gepubliceerd, wordt nu geblokkeerd in de DOCKER-chain. Die wijziging heeft geen invloed op gepubliceerde poorten, dus alles hierboven blijft van toepassing op huidige versies. Het is een goede operationele gewoonte om na elke sudo firewall-cmd --reload een gepubliceerde poort opnieuw te testen. Als deze niet meer reageert, installeert sudo systemctl restart docker de regels van Docker opnieuw.

Beheerders van Ubuntu lopen tegen hetzelfde probleem aan via een andere tool, zoals beschreven in waarom gepubliceerde Docker-poorten ufw-regels negeren. Het NAT-pad is in beide gevallen de oorzaak. Alleen de firewall die ervoor staat, verschilt.

Een non-root gebruiker toevoegen aan de docker groep

Het telkens typen van sudo voor elk docker commando wordt na verloop van tijd omslachtig; de docker groep maakt dit overbodig:

sudo usermod -aG docker $USER
newgrp docker
docker run --rm hello-world

usermod -aG bewerkt /etc/group, maar uw huidige shell beschikt al over de groepslijst, waardoor de wijziging pas effectief is na het starten van een nieuwe sessie. newgrp docker start een shell met de groep toegevoegd, zodat u direct kunt testen. Nieuwe SSH-sessies nemen de wijziging automatisch over.

Wees u bewust van de rechten die deze groep verleent. Lidmaatschap geeft schrijftoegang tot /var/run/docker.sock, en alles wat met die socket kan communiceren, kan de daemon opdracht geven een container te starten die het bestandssysteem van de host mount. Eén commando laat zien wat dit betekent:

docker run --rm -v /:/host alpine wc -l /host/etc/shadow

Dit leest een bestand dat alleen door root gelezen kan worden, uitgevoerd vanaf een account zonder sudo-rechten. De eigen post-installatie documentatie van Docker stelt hetzelfde: de docker groep verleent privileges die gelijkstaan aan root. Voeg alleen een account toe aan deze groep als u dat account ook sudo zou toevertrouwen. Als u accounts op een nieuwe server instelt, neem dit besluit dan gelijktijdig met de rest van uw least-privilege gebruikersconfiguratie op een VPS in plaats van achteraf.

Docker biedt ook een rootless mode die de daemon uitvoert als een gebruiker zonder privileges. Dit is een apart installatiepad en het verandert de werking van storage drivers en poorten onder 1024, dus plan dit als een op zichzelf staand project in plaats van als een instelling die u later toevoegt.

Vervolgstappen

U beschikt nu over de engine, de compose-plugin, een service die een herstart overleeft en de drie EL-specifieke gedragingen die hierboven zijn gedocumenteerd. De volgende stap is een compose.yaml per service, en de anatomie van een Compose-bestand behandelt het bestandsformaat en de commando's die dit aansturen. Als dit uw eerste containerhost is, behandelt Docker draaien op een VPS de vragen over dimensionering, opslag en image-hygiëne die in deze handleiding buiten beschouwing zijn gelaten.

FAQ

Werkt de CentOS-repository van Docker op Rocky Linux en AlmaLinux?

Ja. Voeg https://download.docker.com/linux/centos/docker-ce.repo toe met dnf config-manager. De baseurl in dat bestand bevat $releasever. Rocky Linux en AlmaLinux breiden dit uit naar het major-versienummer. Een EL 9-systeem verwijst dus naar de CentOS 9-tree en een EL 10-systeem naar de CentOS 10-tree. Bevestig de uitbreiding met sudo dnf repoinfo docker-ce-stable en lees de Repo-baseurl-regel. Een Status code: 404 tijdens het ophalen van metadata door dnf betekent dat de variabele is uitgebreid naar een point-release. Dit is op te lossen door /etc/yum.repos.d/docker-ce.repo te bewerken en het kale major-nummer te gebruiken.

Kunnen Docker en podman op dezelfde server worden geïnstalleerd?

De documentatie van Docker vermeldt podman en runc als conflicterende pakketten en adviseert beide te verwijderen voordat u Docker Engine installeert. Het concrete conflict is het podman-docker-pakket, dat eigenaar is van /usr/bin/docker en elk docker-commando omzet in een podman-commando. Voer rpm -qf "$(command -v docker)" uit om te zien welk pakket eigenaar is van dat pad. Als de uitvoer begint met podman-docker, reageert podman. Het behouden van beide engines is geen configuratie die Docker ondersteunt; kies daarom op een belangrijke server voor één van beide.

Waarom krijg ik 'permission denied' bij een bind mount voor mijn container?

SELinux staat standaard in de enforcing-modus op Rocky Linux en AlmaLinux. Containers draaien als het type container_t en mogen alleen bestanden benaderen met het label container_file_t. Een map die u zelf heeft aangemaakt, heeft het verkeerde label, waardoor toegang wordt geweigerd, ongeacht de eigenaar of de rechten. Controleer dit met ls -ldZ op het host-pad en sudo ausearch -m avc -ts recent, dat avc: denied toont met de twee niet-overeenkomende contexten. Voeg :z toe aan het volume-argument voor inhoud die wordt gedeeld tussen containers, of :Z voor inhoud die privé is voor één container. Wijs :Z nooit naar /home of /usr, omdat de relabeling recursief is en de host zal beschadigen.

Moet ik een poort openen in firewalld om een containerpoort te publiceren?

Nee, en dat is juist het probleem. De NAT-regel van Docker herschrijft het bestemmingsadres voordat het pakket het input-pad van de host bereikt, waardoor de zone-regels van firewalld het verkeer niet inspecteren. Docker plaatst zijn bridges bovendien in een firewalld-zone genaamd docker met target ACCEPT. Een container die is gestart met -p 8080:80 is bereikbaar vanaf het internet, terwijl sudo firewall-cmd --list-ports niets weergeeft. Publiceer naar een specifiek adres met -p 127.0.0.1:8080:80 wanneer alleen de host de service mag bereiken, of voeg filterregels toe aan de DOCKER-USER-chain, die Docker verwerkt vóór zijn eigen accept-regels.

Is het veilig om mijn gebruiker toe te voegen aan de docker-groep?

Dit verleent root-rechten. Een lid van de docker-groep kan schrijven naar /var/run/docker.sock, en docker run --rm -v /:/host alpine wc -l /host/etc/shadow leest vervolgens een bestand dat alleen toegankelijk is voor root, vanaf een account zonder sudo-rechten. De post-installatiedocumentatie van Docker bevestigt deze gelijkwaardigheid. Voeg alleen accounts toe die u al zou vertrouwen met sudo, en blijf sudo docker gebruiken voor gedeelde accounts of service-accounts. Rootless-modus is het alternatief wanneer u containers wilt draaien onder een ongeprivilegieerde gebruiker; dit is een apart installatiepad en geen instelling.