Skip to main content
  1. Blogs/

Docker & Docker Compose installieren

·1278 words·6 mins·
Docker Docker Compose
Table of Contents

docker

In diesem Tutorial gehe ich auf zwei unterschiedliche Installationen von Docker ein und fasse die Vor- und Nachteile zusammen. Des Weiteren werde ich zu jedem Befehl eine Erklärung oder ein Kommentar schreiben.

Variante 1: Standardinstallation (Rootful)
#

Damit eine saubere Installation stattfindet, sollten alte sowie Pakete die einen konflikt verursachen können, deinstalliert werden.

Debian 12

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
  sudo apt-get remove -y "$pkg"
done

Ubuntu 24.04

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
  sudo apt-get remove -y "$pkg"
done
Was macht die Schleife genau? for pkg in ...; do … done iteriert über die aufgezählten Paketnamen. In jedem Durchlauf ersetzt die Shell $pkg mit einem Namen (z. B. docker.io) und führt sudo apt-get remove -y "$pkg" aus. Vorteil: Ein einziger Block entfernt mehrere Pakete robust in einer konsistenten Reihenfolge. Sollten Pakete nicht vorhanden sein ist dies kein problem, sie werden i.d.R. übersprungen.

Offizielles Docker-Repository einrichten
#

Wir installieren Docker aus dem offiziellen Docker-APT-Repository (aktuellere Versionen).

# Basis-Werkzeuge + Keyring-Verzeichnis
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings

# Verteilung erkennen und passenden GPG-Key + Repo eintragen
if grep -qi debian /etc/os-release; then
# Debian: GPG-Key holen und als .asc ablegen
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Repo-Zeile: 'signed-by' bindet den Key nur für dieses Repo ein
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

else
# Ubuntu: analog
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" \
|sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
fi

# Paketindizes aktualisieren
sudo apt-get update

Warum diese Schritte?
#

  • /etc/apt/keyrings: Moderner, sicherer Ort für GPG-Keys.
  • signed-by=…: Bindet den Schlüssel nur an dieses Repo.
  • $(dpkg --print-architecture): Nimmt automatisch amd64, arm64, usw.
  • $VERSION_CODENAME: Wählt z. B. bookworm oder noble — so muss nichts von Hand angepasst werden.

Docker & Compose installieren
#

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

Funktionstest
#

sudo docker run --rm hello-world
Der Zusatz --rm sorgt dafür, dass der Container im Anschluss wieder gelöscht wird.

(Optional) Docker als normaler Benutzer nutzen
#

Wenn docker ohne sudo ausgeführt werden soll, kann man die Gruppe docker nutzen.

# Gruppe anlegen, wenn sie nicht existiert
sudo groupadd docker 2>/dev/null || true

# Aktuellen Benutzer der Gruppe hinzufügen
sudo usermod -aG docker "$USER"

# Neue Gruppenzugehörigkeit in der aktuellen Shell aktivieren:
newgrp docker

# Test ohne sudo:
docker run --rm hello-world

Wichtig
#

Die Mitgliedschaft in der Gruppe docker gewährt faktisch root-ähnliche Rechte, weil Docker beliebige Mounts/Devices/Netzwerke orchestriert. Für gemeinsam genutzte Server ist Rootless oft die bessere Wahl (siehe Tabelle unten).

Variante 2: Rootless (Docker ohne Root-Rechte)
#

Der Docker-Daemon und die Container laufen im User-Namespace des aktuellen Benutzers. Ideal auf Shared Hosts oder bei strikten Compliance-Vorgaben.

Voraussetzungen installieren
#

sudo apt-get update
sudo apt-get install -y uidmap dbus-user-session docker-ce-rootless-extras
  • uidmap: liefert newuidmap/newgidmap (User Namespaces)
  • dbus-user-session: für systemd –user Dienste hilfreich
  • docker-ce-rootless-extras: Tools wie dockerd-rootless-setuptool.sh

/etc/subuid & /etc/subgid sollten für deinen Benutzer Bereiche wie username:100000:65536 enthalten (werden bei vielen Systemen automatisch gepflegt). Das ermöglicht die Abbildung vieler „Container-UIDs“ auf deinen Benutzer.

(Falls aktiv) Rootful-Daemon stoppen
#

sudo systemctl disable --now docker.service docker.socket
# alter Socket ggf. entfernen, damit es keinen Konflikt gibt
sudo rm -f /var/run/docker.sock

Rootless einrichten & starten
#

# OHNE sudo als normaler Benutzer:
dockerd-rootless-setuptool.sh install

# Wichtige Variablen in die Shell einhängen:
echo 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' >> ~/.bashrc
. ~/.bashrc

# Docker als systemd --user Dienst starten und beim Login automatisch starten
systemctl --user start docker
systemctl --user enable docker

# Linger erlaubt user-dienste ohne aktive Login-Session am System zu halten
sudo loginctl enable-linger "$(whoami)"

# Test:
docker run --rm hello-world

Einschränkungen & Hinweise:
#

  • Privilegierte Ports (<1024): Ohne zusätzlichen Helfer (rootlesskit + Port-Helpers) nicht direkt bindbar.
  • Netzwerkmodi: host und einige Overlay-Szenarien sind limitiert.
  • Leichte Overheads durch User-Namespace/Slirp4netns.
  • Gerätezugriff (GPU, spezielle USB/Block-Devices) ist eingeschränkt/aufwändiger.

Rootful vs. Rootless — Gegenüberstellung
#

Fähigkeit / MerkmalRootful (Standard)Rootless
Docker-Daemon als Systemdienst (systemd)⚠️ (als systemd --user)
Ohne sudo nutzbar⚠️ (Gruppe docker – riskant)
Sicherheitsoberfläche (Angriffsfläche)⚠️ (Daemon als root)(kein Root zur Laufzeit)
Host-Netzwerkmodus (--network=host)
Privilegierte Ports <1024 binden⚠️ (Port-Helper nötig)
Overlay-/Mehrhost-Netze⚠️/❌ (je nach Setup)
Swarm/klassisches Compose-Netzwerk⚠️ (teilweise limitiert)
GPU-Passthrough (NVIDIA/AMD)⚠️ (zus. Konfig nötig, teils nicht möglich)
Zugriff auf Host-Devices/Volumes⚠️ (restriktiver)
Performance allgemein⚠️ (leichter Overhead möglich)
Einfaches Debugging/Standardpfade⚠️ (User-Pfade variieren)
Geeignet für Shared-Hosts / Multi-User⚠️
Risiko durch Gruppe docker⚠️ (hoch)(entfällt)

Docker Compose: Installation prüfen
#

Nach der oben gezeigten Installation ist Compose v2 bereits als Plugin dabei:

docker compose version

Feinschliff
#

Docker-Dienst beim Booten starten (Rootful)

sudo systemctl enable docker.service containerd.service   # aktivieren
# oder:
sudo systemctl disable docker.service containerd.service  # deaktivieren

Firewall-Hinweis
#

Docker erstellt NAT-Regeln selbst. Wenn du UFW/Firewalld nutzt, beachte, dass exponierte Ports Docker-seitig schon geöffnet werden. Lege (falls benötigt) Regeln in iptables an, um eingehenden Traffic global zu filtern.

Logging
#

Logging-Treiber local rotiert automatisch; bei json-file setze explizit Optionen, z. B.:

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

Deinstallation / Aufräumen
#

# Container/Images/Volumes auflisten & ggf. sichern!
docker ps -a
docker volume ls

# Rootful deinstallieren:
sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo rm -rf /var/lib/docker /var/lib/containerd

# Rootless stoppen (als Benutzer):
systemctl --user disable --now docker

Docker Compose - Beispiele
#

Adguard Home mit Unbound
#

Aufbau

  • adguard (DNS-Filter & Web-UI)
  • unbound (rekursiver DNS-Resolver, nutzt Root-Zonen/Root-Hints)
  • Gemeinsames Bridge-Netzwerk dnsnet → Service-Discovery per Namen (unbound).
dns-stack/
├─ compose.yaml
├─ adguard/
│  ├─ conf/
│  │  └─ AdGuardHome.yaml      # (optional: vorkonfiguriert, siehe unten)
│  └─ work/                    # von AdGuard genutzt
└─ unbound/

Verzeichnise anlegen

mkdir -p dns-stack/{adguard/{conf,work},unbound}

Docker Stack
#

Hinweis Port 53 (Host): Auf Ubuntu läuft oft systemd-resolved mit einem Stub-Resolver an 127.0.0.53. Wenn du 53:53 auf dem Host binden willst, deaktiviere den Stub-Listener (siehe „Port-Kollisionen“ weiter unten) – oder benutze testweise andere Host-Ports.
name: dns-stack

networks:
  dnsnet:
    name: dnsnet
    driver: bridge

services:
  unbound:
    image: crazymax/unbound:latest
    container_name: unbound
    restart: unless-stopped
    networks: [dnsnet]
    # Optional: Drop-in-Konfigs hierhin legen
    volumes:
      - ./unbound/config:/config:ro

  adguard:
    image: adguard/adguardhome:latest
    container_name: adguard
    restart: unless-stopped
    networks: [dnsnet]
    depends_on:
      - unbound     # wartet nur, bis unbound gestartet ist
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "3000:3000/tcp" # nur für die Ersteinrichtung notwendig
      - "80:80/tcp"
      - "443:443/tcp"
    volumes:
      - ./adguard/work:/opt/adguardhome/work
      - ./adguard/conf:/opt/adguardhome/conf

AdGuard Home → Unbound als Upstream
#

Web-UI - Upstream docker compose up -d starten. Öffne http://<host>:3000 → Setup-Assistenten folgen und einrichten. Bei Upstream-DNS trägst du udp://unbound:5053 ein (nur im Docker-Netz relevant; AdGuard löst unbound über Docker-DNS auf). Speichern → fertig.

Im Anschluss ist in ./dns-stack/adguard/conf/ die AdGuardHome.yaml angelegt worden. Hier sind folgende Einträge zu ergänzen oder zu ändern. Mit diesen Einstellungen ist zum einen der Upstream-DNS bereits auf Unbound eingestellt. Damit AdGuard im Docker-Netzwerk nun auch Unbound mit dem Hostnamen aufgelöst werden kann, ist die zweite Änderung notwendig!

upstream_dns:
    - udp://unbound:5053
bootstrap_dns:
    - 127.0.0.11
Nach dem ersten vollständigen Setup überschreibt AdGuard seine Config teils selbst (z. B. wenn du Ports in der UI umstellst). Das ist normal. Weitere Informationen findet sich im Wiki von AdGuard Home

Stack starten und Funktion überprüfen
#

# im Ordner dns-stack/
docker compose up -d
docker compose ps

# Teste eine Abfrage gegen AdGuard (Host-Seite):
dig @127.0.0.1 -p 53 example.com A +short
# oder über das LAN von einem anderen Client:
# dig @<DEIN_HOST_IP> example.com A +short

# Logs ansehen:
docker compose logs -f unbound
docker compose logs -f adguard

GitHub Repo
#

Mark Schenk
Author
Mark Schenk
Vom Hobby zum Beruf, vom Beruf zur Berufung! Ich arbeite seit 2014 in der IT, bin Informationstechnikermeister – und immer auf der Suche nach neuem Wissen, das ich gern weitergebe.