Zum Inhalt springen
CitexNode
Alle Anleitungen

Docker und Docker Compose

Docker Engine mit Compose-Plugin aus dem offiziellen Repository, ein Compose-Beispiel und warum Docker deine Firewall umgeht.

5 Min. Lesezeit

Gilt für Debian 12/13, Ubuntu 22.04/24.04, AlmaLinux 9 und Rocky Linux 9. Wir installieren Docker aus dem offiziellen Repository von Docker, nicht das ältere docker.io der Distribution.

Debian

bash
apt remove -y docker.io docker-compose podman-docker containerd runc 2>/dev/null
apt install -y ca-certificates curl
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
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/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Ubuntu

Wie Debian, nur mit ubuntu in den Adressen:

bash
apt remove -y docker.io docker-compose podman-docker containerd runc 2>/dev/null
apt install -y ca-certificates curl
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
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" > /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

AlmaLinux und Rocky Linux

bash
dnf remove -y podman buildah runc 2>/dev/null
dnf install -y dnf-plugins-core
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker

dnf fragt nach dem GPG-Schlüssel von Docker. Der Fingerabdruck muss 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35 sein.

Auf Debian und Ubuntu startet Docker nach der Installation von selbst.

Prüfen, ob es geklappt hat

bash
docker version
docker compose version
docker run --rm hello-world

hello-world lädt ein winziges Image und gibt Hello from Docker! aus.

Ein Compose-Beispiel

Eine kleine Webanwendung mit Datenbank. Leg einen Ordner an:

bash
mkdir -p /opt/app && cd /opt/app
nano compose.yaml
yaml
services:
  web:
    image: nginx:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - db-data:/var/lib/postgresql/data

secrets:
  db_password:
    file: ./db_password.txt

volumes:
  db-data:
bash
mkdir -p html && echo "Hallo" > html/index.html
openssl rand -base64 24 > db_password.txt && chmod 600 db_password.txt
docker compose up -d

Wichtig sind diese Punkte:

  • 127.0.0.1:8080:80 veröffentlicht den Webserver nur auf dem Server selbst. Von außen kommt keiner dran. Ein Reverse-Proxy wie Caddy oder nginx auf dem Host leitet dann https://deine-domain dorthin.
  • Die Datenbank hat gar kein ports:. Der Webcontainer erreicht sie trotzdem über den Namen db, weil Compose beide in ein gemeinsames Netz steckt.
  • restart: unless-stopped startet die Container nach einem Neustart des Servers wieder.

Nützliche Befehle im Ordner:

bash
docker compose ps            # was läuft
docker compose logs -f web   # Logs live
docker compose pull          # neue Images holen
docker compose up -d         # mit neuen Images neu starten
docker compose down          # stoppen und entfernen (Volumes bleiben)

Test auf dem Server:

bash
curl http://127.0.0.1:8080

Docker und die Firewall

Docker schreibt eigene Regeln in die Paketfilter des Kernels. Verbindungen zu veröffentlichten Ports laufen an den Regeln von ufw und firewalld vorbei. Ein ufw deny 8080 hilft also nicht, wenn ein Container mit -p 8080:80 läuft.

So bleibst du sicher:

  1. Nur auf 127.0.0.1 veröffentlichen, wie im Beispiel oben: "127.0.0.1:8080:80". Was von außen erreichbar sein soll (meist nur 80 und 443), geht über einen Reverse-Proxy auf dem Host oder einen eigenen Proxy-Container.

  2. Datenbanken nie veröffentlichen. Container im selben Compose-Netz brauchen kein ports:.

  3. Wenn ein Port doch öffentlich sein muss, aber nur für bestimmte Adressen: Regeln in der Kette DOCKER-USER. Docker wertet sie vor seinen eigenen Regeln aus. Beispiel, Port 5432 nur für 198.51.100.7 (Schnittstellenname mit ip -br link nachsehen):

    bash
    iptables -I DOCKER-USER -i eth0 -p tcp --dport 5432 ! -s 198.51.100.7 -j DROP

    Solche Regeln sind nach einem Neustart weg, wenn du sie nicht dauerhaft speicherst, und gelten nur für IPv4. Darum ist Punkt 1 fast immer der bessere Weg.

Häufige Fehler

MeldungUrsache und Lösung
permission denied while trying to connect to the Docker daemon socketOhne root und nicht in der Gruppe docker. sudo docker … oder Gruppe hinzufügen und neu anmelden.
docker: 'compose' is not a docker commanddocker-compose-plugin fehlt. Der alte Befehl docker-compose mit Bindestrich ist veraltet.
Bind for 0.0.0.0:80 failed: port is already allocatedDen Port nutzt schon etwas anderes. ss -tlnp zeigt was.
Konflikt mit podman oder runc auf AlmaLinux/RockyVorher dnf remove podman buildah runc, wie oben.
no space left on deviceAlte Images und Build-Reste: docker system df, aufräumen mit docker system prune.

Wie es weitergeht