Docker mit Ansible auf Ubuntu installieren und einrichten
Die Automatisierung von Servern ist zu einem wichtigen Bestandteil der Systemadministration geworden, da moderne Anwendungsumgebungen häufig so aufgebaut sind, dass einzelne Systeme problemlos ersetzt werden können. Konfigurationsmanagement-Werkzeuge wie Ansible unterstützen dabei, Serverkonfigurationen zu automatisieren, indem wiederholbare Abläufe für neue Systeme definiert werden. Gleichzeitig lässt sich dadurch das Risiko von Fehlern reduzieren, die bei einer manuellen Einrichtung entstehen können.
Ansible verwendet eine vergleichsweise einfache Architektur und benötigt auf den verwalteten Zielsystemen keine speziell installierte Agent-Software. Darüber hinaus stellt Ansible zahlreiche integrierte Module und Funktionen bereit, mit denen sich Automatisierungsabläufe effizient erstellen lassen.
In dieser Anleitung wird gezeigt, wie sich die Installation und Konfiguration von Docker unter Ubuntu mit Ansible automatisieren lässt. Docker erleichtert die Verwaltung von Containern. Dabei handelt es sich um voneinander isolierte Prozesse, die in bestimmten Punkten virtuellen Maschinen ähneln, in der Regel jedoch portabler sind, weniger Ressourcen benötigen und stärker auf das Betriebssystem des Hosts zurückgreifen.
Hinweis: Diese Anleitung wurde mit Ubuntu 24.04 LTS getestet. Sie kann grundsätzlich auch mit anderen aktuellen Ubuntu-Versionen funktionieren. Einzelne Schritte, beispielsweise die Konfiguration von Paketquellen, müssen dabei möglicherweise geringfügig angepasst werden.
Die wichtigsten Punkte im Überblick
- Durch Idempotenz kann dasselbe Playbook mehrfach ausgeführt werden, ohne unbeabsichtigte Änderungen zu verursachen, da jede Aufgabe zunächst den aktuellen Zustand des Systems berücksichtigt.
- Bei der modernen Verwaltung von GPG-Schlüsseln werden Repository-Schlüssel unter
/etc/apt/keyringsgespeichert und übersigned-byeingebunden. Damit werden der veraltete Systembefehlapt-keyund die frühere Ansible-Methode mit dem Modulapt_keyersetzt. - Docker Compose v2 wird über das Paket
docker-compose-pluginbereitgestellt und verwendet den Unterbefehldocker composeanstelle des früheren ausführbaren Befehlsdocker-compose. - Die Variable
{{ ansible_distribution_release }}erkennt automatisch Ubuntu-Codenamen wie focal, jammy oder noble. Dadurch kann das Playbook mit unterschiedlichen Ubuntu-Versionen verwendet werden, ohne versionsspezifische Werte fest einzutragen. - Die Collection
community.dockermuss auf dem Ansible-Control-Node separat mitansible-galaxy collection install community.dockerinstalliert werden, bevor Container damit verwaltet werden können. - Für eine vollständige Docker-Engine-Installation werden fünf zentrale Pakete verwendet:
docker-ce,docker-ce-cli,containerd.io,docker-buildx-pluginunddocker-compose-plugin. - Nach einer Änderung der Docker-Gruppenmitgliedschaft mit
usermod -aG dockerist eine Abmeldung und erneute Anmeldung erforderlich, da Gruppenberechtigungen beim Start einer Sitzung übernommen werden. - Die Reihenfolge der Aufgaben ist wichtig, da Ansible Tasks normalerweise synchron ausführt. Abhängigkeiten wie
gnupgmüssen deshalb installiert sein, bevor GPG-bezogene Operationen ausgeführt werden. - Der ausführliche Modus mit
-vvvzeigt die tatsächlich ausgeführten Befehle sowie vollständige Antworten der Module und hilft dadurch bei der Diagnose von Netzwerk-, Berechtigungs- und Ausführungsproblemen. - Ansible-Playbooks ermöglichen im Vergleich zu klassischen Shell-Skripten eine höhere Wiederholbarkeit, da sie Idempotenz, eine übersichtliche Konfigurationsstruktur und eine einfache Einbindung in Versionskontrollsysteme kombinieren.
Voraussetzungen
Damit die automatisierte Konfiguration aus dieser Anleitung mit dem Playbook ausgeführt werden kann, werden folgende Systeme benötigt:
- Ein Ansible-Control-Node: ein Ubuntu-24.04-System, auf dem Ansible installiert und so konfiguriert ist, dass Verbindungen zu verwalteten Ansible-Hosts über SSH-Schlüssel hergestellt werden können. Auf dem Control-Node sollte ein normaler Benutzer mit sudo-Berechtigungen vorhanden und eine Firewall aktiviert sein. Ansible muss vor dem Fortfahren vollständig installiert und eingerichtet sein.
- Ein oder mehrere Ansible-Hosts: ein oder mehrere entfernte Ubuntu-24.04-Server, auf denen die grundlegende Erstkonfiguration bereits durchgeführt wurde.
Hinweis: Vor dem Fortfahren sollte geprüft werden, ob der Ansible-Control-Node eine Verbindung zu den verwalteten Hosts herstellen und dort Befehle ausführen kann. Führe deshalb vor dem Start des Playbooks einen Verbindungstest mit Ansible durch.
Was erledigt dieses Ansible-Playbook?
Dieses Ansible-Playbook bietet eine automatisierte Alternative zur manuellen Installation und Konfiguration von Docker auf Ubuntu. Nachdem das Playbook einmal vorbereitet wurde, kann es für weitere Installationen erneut verwendet werden.
Beim Ausführen des Playbooks werden auf den verwalteten Ansible-Hosts folgende Schritte durchgeführt:
aptitudeinstallieren, das von Ansible als alternative Schnittstelle zum Paketmanageraptverwendet werden kann.- Die erforderlichen Systempakete installieren.
- Den GPG-Signaturschlüssel von Docker herunterladen und mit der modernen Keyring-Methode konfigurieren.
- Das offizielle Docker-Repository zu den
apt-Paketquellen hinzufügen. - Docker installieren.
- Docker Compose als Plugin der Version 2 installieren.
- Das Docker-Modul für Python über
pipinstallieren. - Das über
default_container_imagefestgelegte Standard-Image aus Docker Hub abrufen. - Die über
container_countfestgelegte Anzahl von Containern erstellen, dabei das indefault_container_imagedefinierte Image verwenden und in jedem neu erstellten Container den unterdefault_container_commandangegebenen Befehl ausführen.
Nach Abschluss des Playbooks wurde die konfigurierte Anzahl an Containern entsprechend den in den Playbook-Variablen festgelegten Werten erstellt.
Melde dich zunächst auf dem Ansible-Control-Node mit einem Benutzerkonto an, das über sudo-Berechtigungen verfügt.
Schritt 1 – Das Ansible-Playbook vorbereiten
In der Datei playbook.yml werden alle für die Automatisierung verwendeten Tasks definiert. Ein Task stellt die kleinste einzelne Aktion dar, die über ein Ansible-Playbook automatisiert werden kann. Erstelle zunächst die Playbook-Datei mit einem Texteditor deiner Wahl:
nano playbook.yml
Dadurch wird eine leere YAML-Datei geöffnet. Bevor die einzelnen Tasks ergänzt werden, füge zunächst die folgende Konfiguration ein:
playbook.yml
---
- hosts: all
become: true
vars:
container_count: 4
default_container_name: docker
default_container_image: ubuntu
default_container_command: sleep 1d
Viele Ansible-Playbooks beginnen mit vergleichbaren Deklarationen. Über hosts wird definiert, welche Server der Ansible-Control-Node beim Ausführen des Playbooks ansprechen soll. Die Einstellung become bestimmt, ob die Befehle mit erweiterten root-Berechtigungen ausgeführt werden.
Im Abschnitt vars lassen sich wiederverwendbare Werte als Variablen speichern. Müssen diese Werte später angepasst werden, genügt es, die jeweilige Definition an einer zentralen Stelle zu ändern. Die Variablen erfüllen folgende Aufgaben:
container_count: Legt fest, wie viele Container erstellt werden.default_container_name: Definiert den standardmäßig verwendeten Namen der Container.default_container_image: Bestimmt das Docker-Image, das beim Erstellen der Container eingesetzt wird.default_container_command: Legt den Standardbefehl fest, der innerhalb neu erstellter Container ausgeführt wird.
Hinweis: Wenn du direkt die endgültige Version des vollständigen Playbooks ansehen möchtest, kannst du zu Schritt 5 wechseln. Bei YAML ist die korrekte Einrückung besonders wichtig. Prüfe deshalb die Struktur sorgfältig, nachdem alle Tasks hinzugefügt wurden.
Schritt 2 – Aufgaben zur Paketinstallation zum Playbook hinzufügen
Ansible führt die Tasks eines Playbooks standardmäßig synchron von oben nach unten aus. Die Reihenfolge der Aufgaben ist daher wichtig. Im Normalfall kann davon ausgegangen werden, dass ein Task abgeschlossen ist, bevor der nächste beginnt.
Die in diesem Playbook verwendeten Tasks können auch unabhängig voneinander eingesetzt und in anderen Ansible-Playbooks wiederverwendet werden.
Ein grundlegendes Konzept von Ansible ist die Idempotenz. Damit ist gemeint, dass dieselbe Automatisierung mehrfach ausgeführt werden kann und trotzdem immer zum vorgesehenen Systemzustand führt, ohne unnötige oder unbeabsichtigte Änderungen vorzunehmen.
Alle Tasks in diesem Playbook sind so aufgebaut, dass sie idempotent arbeiten. Bei der Paketinstallation werden beispielsweise state: latest oder state: present verwendet. Dadurch werden Pakete nur dann installiert oder aktualisiert, wenn dies tatsächlich notwendig ist. Auch Aufgaben zur Repository- und Schlüsselkonfiguration nehmen nur dann Änderungen vor, wenn die gewünschte Konfiguration noch nicht vorhanden ist.
Dadurch lässt sich das Playbook jederzeit erneut ausführen, beispielsweise wenn zusätzliche Server bereitgestellt oder bestehende Systeme aktualisiert werden sollen.
Füge zunächst Aufgaben hinzu, die aptitude als Schnittstelle für den Linux-Paketmanager sowie die benötigten Systempakete installieren. Ansible stellt anschließend sicher, dass diese Pakete auf dem Server vorhanden sind:
playbook.yml
tasks:
- name: Install aptitude
apt:
name: aptitude
state: latest
update_cache: true
- name: Install required system packages
apt:
pkg:
- ca-certificates
- curl
- gnupg
- software-properties-common
- python3-pip
- python3-venv
- python3-setuptools
state: latest
update_cache: true
Diese Tasks verwenden das integrierte Ansible-Modul apt, um die benötigten Pakete zu installieren. Ansible-Module stellen vordefinierte Möglichkeiten zur Verfügung, bestimmte Aktionen durchzuführen, für die ansonsten eigene Shell-Befehle geschrieben werden müssten. Ist aptitude nicht verfügbar, kann Ansible für die Installation von Paketen auf apt zurückgreifen, auch wenn aptitude historisch häufig bevorzugt wurde.
Die Paketliste kann entsprechend den eigenen Anforderungen erweitert oder reduziert werden. Mit dieser Konfiguration wird sichergestellt, dass die angegebenen Pakete in der jeweils aktuell verfügbaren Version installiert sind, nachdem der Paket-Cache von apt aktualisiert wurde.
Schritt 3 – Docker-Installation zum Ansible-Playbook hinzufügen
Die folgenden Tasks installieren die aktuelle Docker-Version aus dem offiziellen Repository. Der Docker-GPG-Schlüssel dient zur Überprüfung der heruntergeladenen Pakete, das offizielle Repository wird als zusätzliche Paketquelle eingebunden und anschließend wird Docker installiert. Außerdem werden das Docker-Compose-Plugin sowie das Docker-Modul für Python eingerichtet.
playbook.yml
- name: Create keyrings directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Download Docker GPG key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
force: true
- name: De-armor Docker GPG key for APT
command: gpg --dearmor --yes --output /etc/apt/keyrings/docker.gpg /etc/apt/keyrings/docker.asc
args:
creates: /etc/apt/keyrings/docker.gpg
- name: Add Docker repository
apt_repository:
repo: "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
filename: docker
- name: Update apt and install Docker Engine
apt:
pkg:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: latest
update_cache: true
- name: Install Docker Module for Python
pip:
name: docker
Diese Konfiguration verwendet einen APT-Keyring in Verbindung mit der Repository-Option signed-by. Auf aktuellen Ubuntu-Versionen ersetzt dieses Verfahren die veraltete Methode über apt_key.
Docker Compose wird über das Paket docker-compose-plugin installiert. Dieses Paket stellt die aktuelle Befehlssyntax docker compose bereit und ersetzt damit das frühere eigenständige Programm docker-compose.
Hinweis: Docker Compose v2 verwendet docker compose mit einem Leerzeichen zwischen den beiden Befehlen anstelle der älteren Schreibweise docker-compose.
Schritt 4 – Docker-Images und Container mit Ansible verwalten
Die eigentliche Erstellung der Docker-Container beginnt mit dem Abrufen des gewünschten Docker-Images. Standardmäßig können entsprechende Images über das offizielle Docker Hub bezogen werden. Auf Grundlage dieses Images werden anschließend Container entsprechend den Variablen erstellt, die am Anfang des Playbooks definiert wurden.
Bevor diese Tasks eingefügt werden, muss sichergestellt werden, dass die Ansible-Collection community.docker auf dem Control-Node installiert ist. Sie kann mit folgendem Befehl installiert werden:
ansible-galaxy collection install community.docker
Ergänze anschließend die folgenden Tasks im Playbook:
playbook.yml
- name: Pull default Docker image
community.docker.docker_image:
name: "{{ default_container_image }}"
source: pull
- name: Create default containers
community.docker.docker_container:
name: "{{ default_container_name }}{{ item }}"
image: "{{ default_container_image }}"
command: "{{ default_container_command }}"
state: present
with_sequence: count={{ container_count }}
Das Modul community.docker.docker_image lädt das Docker-Image herunter, das als Grundlage für die Container verwendet werden soll. Mit community.docker.docker_container lassen sich die Eigenschaften der zu erstellenden Container sowie der darin auszuführende Befehl festlegen.
Die Anweisung with_sequence erzeugt in Ansible eine Schleife. In diesem Beispiel wird die Container-Erstellung entsprechend dem unter container_count angegebenen Wert wiederholt. Die Variable item enthält dabei die Nummer des jeweiligen Schleifendurchlaufs. Diese Nummer wird hier als Bestandteil des Container-Namens verwendet.
Schritt 5 – Das vollständige Ansible-Playbook überprüfen
Das fertige Playbook sollte ungefähr dem folgenden Beispiel entsprechen. Abhängig von individuellen Anpassungen können geringfügige Unterschiede vorhanden sein:
playbook.yml
---
- hosts: all
become: true
vars:
container_count: 4
default_container_name: docker
default_container_image: ubuntu
default_container_command: sleep 1d
tasks:
- name: Install aptitude
apt:
name: aptitude
state: latest
update_cache: true
- name: Install required system packages
apt:
pkg:
- ca-certificates
- curl
- gnupg
- software-properties-common
- python3-pip
- python3-venv
- python3-setuptools
state: latest
update_cache: true
- name: Create keyrings directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Download Docker GPG key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
force: true
- name: De-armor Docker GPG key for APT
command: gpg --dearmor --yes --output /etc/apt/keyrings/docker.gpg /etc/apt/keyrings/docker.asc
args:
creates: /etc/apt/keyrings/docker.gpg
- name: Add Docker repository
apt_repository:
repo: "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
filename: docker
- name: Update apt and install Docker Engine
apt:
pkg:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: latest
update_cache: true
- name: Install Docker Module for Python
pip:
name: docker
- name: Pull default Docker image
community.docker.docker_image:
name: "{{ default_container_image }}"
source: pull
- name: Create default containers
community.docker.docker_container:
name: "{{ default_container_name }}{{ item }}"
image: "{{ default_container_image }}"
command: "{{ default_container_command }}"
state: present
with_sequence: count={{ container_count }}
Das Playbook kann an die Anforderungen des eigenen Workflows angepasst werden. So lässt sich beispielsweise mit dem Modul docker_image ein Image zu Docker Hub übertragen. Das Modul docker_container kann unter anderem zur Einrichtung von Container-Netzwerken verwendet werden.
Hinweis: Achte besonders auf die Einrückung. Fehlerhafte Einrückungen gehören zu den häufigsten Ursachen für Probleme in YAML-Dateien. Im gezeigten Beispiel werden jeweils zwei Leerzeichen zur Einrückung verwendet.
Wenn das Playbook vollständig geprüft wurde, kann die Datei gespeichert und der Texteditor geschlossen werden.
Schritt 6 – Das Ansible-Playbook ausführen
Das Playbook kann nun auf einem oder mehreren Servern ausgeführt werden. Häufig sind Playbooks so konfiguriert, dass sie standardmäßig alle passenden Systeme aus dem Inventory ansprechen. Bei Bedarf lässt sich jedoch auch gezielt ein einzelner Server auswählen.
Um das Playbook ausschließlich auf host1 auszuführen und dabei die Verbindung mit dem Benutzer user herzustellen, kann folgender Befehl verwendet werden:
ansible-playbook playbook.yml -l host1 -u user
Die Option -l legt den Zielserver fest, während -u angibt, mit welchem Benutzerkonto Ansible die Verbindung zum entfernten System herstellen soll. Die Ausgabe sollte ungefähr wie folgt aussehen:
Output. . .
changed: [host1]
TASK [Create default containers] *****************************************************************************************************************
changed: [host1] => (item=1)
changed: [host1] => (item=2)
changed: [host1] => (item=3)
changed: [host1] => (item=4)
PLAY RECAP ***************************************************************************************************************************************
host1 : ok=10 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Hinweis: Eine Ansible-Befehlsreferenz oder ein entsprechendes Cheat Sheet kann zusätzliche Informationen zu den verfügbaren Optionen beim Ausführen von Playbooks liefern.
Diese Ausgabe zeigt, dass die Serverkonfiguration abgeschlossen wurde. Die konkreten Werte können auf einem anderen System abweichen. Entscheidend ist, dass in der Zusammenfassung keine fehlgeschlagenen Tasks angezeigt werden.
Nach Abschluss des Playbooks kann über SSH eine Verbindung zum Server hergestellt werden, um zu kontrollieren, ob die Docker-Container erfolgreich erstellt wurden.
Stelle die Verbindung zum entfernten Server mit folgendem Befehl her:
ssh user@your_remote_server_ip
Lasse anschließend die Docker-Container auf dem entfernten Server anzeigen:
sudo docker ps -a
Eine entsprechende Ausgabe kann beispielsweise folgendermaßen aussehen:
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3fe9bfb89cf ubuntu "sleep 1d" 5 minutes ago Created docker4
8799c16cde1e ubuntu "sleep 1d" 5 minutes ago Created docker3
ad0c2123b183 ubuntu "sleep 1d" 5 minutes ago Created docker2
b9350916ffd8 ubuntu "sleep 1d" 5 minutes ago Created docker1
Damit wird bestätigt, dass die im Playbook definierten Container erfolgreich erstellt wurden. Da das Erstellen der Container die letzte Aufgabe des Playbooks darstellt, bestätigt eine erfolgreiche Ausführung gleichzeitig, dass das gesamte Playbook auf dem Server vollständig abgearbeitet wurde.
Häufige Fehler bei Ansible und Docker beheben
Obwohl das Playbook auf einem korrekt eingerichteten System zuverlässig funktionieren sollte, können abhängig von Netzwerkkonfiguration, bestehendem Paketstatus oder Berechtigungen Probleme auftreten. Die folgenden Abschnitte beschreiben typische Fehler und mögliche Schritte zur Diagnose.
Fehler mit dem Docker-GPG-Schlüssel
Fehler im Zusammenhang mit dem Docker-GPG-Schlüssel treten normalerweise dann auf, wenn das Playbook den Signaturschlüssel des Repositorys nicht herunterladen oder verarbeiten kann. Mögliche Ursachen sind Probleme mit der Netzwerkverbindung, fehlerhafte DNS-Auflösung oder unzureichende Dateiberechtigungen im Verzeichnis /etc/apt/keyrings.
Wenn die Ansible-Ausgabe einen Fehler mit dem GPG-Schlüssel meldet, sollte zuerst geprüft werden, ob die URL des Docker-GPG-Schlüssels vom verwalteten System erreichbar ist. Der Download lässt sich manuell mit curl testen:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg
Wenn der Download erfolgreich funktioniert, kann anschließend der APT-Cache manuell aktualisiert werden, um festzustellen, ob weiterhin ein Problem mit der Repository-Konfiguration besteht:
sudo apt update
Besteht das Problem weiterhin, sollte überprüft werden, ob der Server über eine funktionierende Netzwerkverbindung und DNS-Auflösung verfügt. Die DNS-Auflösung kann beispielsweise mit nslookup download.docker.com getestet werden. Eine allgemeine Prüfung der Netzwerkverbindung ist mit ping 8.8.8.8 möglich.
Probleme mit dem Docker-Repository
Fehler in der Repository-Konfiguration zeigen sich häufig durch Meldungen wie „package not found“ während der Docker-Installation. Eine mögliche Ursache ist, dass die Repository-URL nicht zum Codename der verwendeten Ubuntu-Version passt. Das Playbook reduziert dieses Risiko, indem es über ansible_distribution_release automatisch den passenden Codename ermittelt.
Zur Diagnose können die konfigurierten APT-Paketquellen überprüft werden, um festzustellen, ob das Docker-Repository korrekt eingebunden wurde:
grep -r docker /etc/apt/sources.list*
Der entsprechende Repository-Eintrag sollte [signed-by=/etc/apt/keyrings/docker.gpg] sowie den passenden Ubuntu-Codename enthalten, beispielsweise focal für Ubuntu 20.04, jammy für Ubuntu 22.04 oder noble für Ubuntu 24.04. Sieht die Repository-Konfiguration korrekt aus, die Pakete können jedoch weiterhin nicht gefunden werden, sollte mit sudo apt update der Paketindex aktualisiert und anschließend das Playbook erneut ausgeführt werden.
Fehler bei der Paketinstallation
Eine Paketinstallation kann aus unterschiedlichen Gründen fehlschlagen. Dazu gehören Konflikte mit bereits vorhandenen Paketen, zuvor abgebrochene Installationen oder eine gesperrte Paketdatenbank. Meldet Ansible Fehler während der Paketinstallation, liegt die Ursache daher häufig im aktuellen Zustand von APT und nicht unmittelbar im Playbook.
Zu Beginn sollte geprüft werden, ob der APT-Paket-Cache aktuell ist. Ein veralteter Cache kann dazu führen, dass APT nach Paketversionen sucht, die im Repository nicht mehr verfügbar sind. Anschließend kann überprüft werden, ob beschädigte Abhängigkeiten weitere Installationen verhindern:
sudo apt --fix-broken install
Mit diesem Befehl versucht APT, unvollständige oder beschädigte Paketinstallationen zu reparieren. Zusätzlich sollte sichergestellt werden, dass kein anderer Paketmanager-Prozess aktiv ist. Prozesse wie automatische Systemaktualisierungen können die Paketdatenbank sperren und verhindern, dass Ansible Änderungen daran durchführt. Aktive APT-Prozesse lassen sich mit ps aux | grep apt überprüfen.
„Permission denied“ bei Docker-Befehlen
Docker benötigt standardmäßig root-Berechtigungen für die Kommunikation mit dem Docker-Daemon. Werden Docker-Befehle als normaler Benutzer ohne sudo ausgeführt, können deshalb Meldungen wie „permission denied“ erscheinen. Das Playbook installiert Docker erfolgreich, fügt das aktuelle Benutzerkonto jedoch nicht automatisch zur Gruppe docker hinzu.
Damit Docker-Befehle ohne sudo ausgeführt werden können, lässt sich der aktuelle Benutzer zur Gruppe docker hinzufügen:
sudo usermod -aG docker $USER
Dieser Befehl fügt das aktuelle Benutzerkonto zur Gruppe docker hinzu und erlaubt dadurch die Kommunikation mit dem Docker-Daemon. Änderungen an Gruppenmitgliedschaften werden jedoch nicht automatisch in der bereits laufenden Shell-Sitzung übernommen. Deshalb muss sich der Benutzer abmelden und anschließend erneut anmelden. Alternativ kann mit newgrp docker eine neue Shell mit der aktualisierten Gruppenzugehörigkeit gestartet werden.
Zu beachten ist, dass Benutzer der Gruppe docker praktisch über root-ähnliche Rechte auf dem System verfügen können, da Container mit umfassendem Zugriff auf das Dateisystem gestartet werden können. Deshalb sollten ausschließlich vertrauenswürdige Benutzer dieser Gruppe hinzugefügt werden.
Docker-Dienst startet nicht
Wenn der Docker-Dienst nach der Installation nicht automatisch startet, können unter anderem fehlerhafte systemd-Konfigurationen, Konflikte mit anderen Diensten oder begrenzte Systemressourcen die Ursache sein. Docker wird als systemd-Service verwaltet, sodass die üblichen Werkzeuge von systemd zur Diagnose verwendet werden können.
Überprüfe zunächst den aktuellen Status des Docker-Dienstes und achte dabei auf auffällige Fehlermeldungen:
sudo systemctl status docker
Die Ausgabe zeigt, ob Docker aktiv, fehlgeschlagen oder gestoppt ist und enthält außerdem aktuelle Logeinträge. Für detailliertere Informationen können die vollständigen Protokolle des Docker-Dienstes mit journalctl betrachtet werden:
journalctl -u docker
Mit --no-pager kann die Ausgabe ohne Pager angezeigt werden. Mit -n 50 lassen sich alternativ nur die letzten 50 Zeilen darstellen. Zu typischen Ursachen gehören Port-Konflikte, wenn andere Dienste benötigte Ports verwenden, oder Probleme mit dem Storage-Treiber.
Wenn anhand der Protokolle ein Konfigurationsproblem erkannt und behoben wurde, kann der Docker-Dienst neu gestartet werden:
sudo systemctl restart docker
Mit sudo systemctl enable docker kann außerdem sichergestellt werden, dass Docker beim Systemstart automatisch gestartet wird.
Probleme mit Python-Modulen oder Abhängigkeiten
Das über das Paket docker installierte Docker-Modul für Python wird von der Ansible-Collection community.docker benötigt, um mit der Docker-API zu kommunizieren. Fehler bei der Installation dieses Moduls können unter anderem durch eine fehlerhafte pip-Konfiguration, inkompatible Python-Versionen oder fehlende Build-Abhängigkeiten entstehen.
Falls das Playbook beim Task „Install Docker Module for Python“ fehlschlägt, sollte zunächst geprüft werden, ob pip installiert ist und korrekt funktioniert. Die installierte Python-3-Version lässt sich folgendermaßen anzeigen:
python3 --version
Das Docker-Modul für Python benötigt Python 3.6 oder eine neuere Version. Ist die Python-Version ausreichend aktuell und die Installation schlägt dennoch fehl, kann das Modul manuell installiert werden, um eine detailliertere Fehlermeldung zu erhalten:
pip3 install docker
Treten bei der Installation Kompilierungsfehler auf, können Entwicklungs-Header oder Build-Werkzeuge fehlen. Die Installation des Pakets python3-dev kann solche Probleme häufig beheben. Wird eine virtuelle Python-Umgebung verwendet, sollte außerdem sichergestellt werden, dass das Modul innerhalb der richtigen Umgebung installiert wird.
Verbindungsfehler mit Ansible
Ansible-Verbindungsfehler entstehen, wenn der Control-Node keine SSH-Verbindung zu einem oder mehreren verwalteten Hosts herstellen kann. Eine funktionierende SSH-Verbindung ist eine grundlegende Voraussetzung für Ansible. Verbindungsprobleme müssen daher behoben werden, bevor Tasks des Playbooks ausgeführt werden können.
Prüfe zunächst, ob mit denselben Zugangsdaten, die auch Ansible verwenden soll, manuell eine SSH-Verbindung zum Zielsystem hergestellt werden kann:
ssh user@host
Funktioniert der manuelle SSH-Zugriff, während Ansible weiterhin keine Verbindung herstellen kann, sollte die Ansible-Inventory-Konfiguration sowie die SSH-Schlüsselauthentifizierung überprüft werden. Kontrolliere, ob Hostnamen beziehungsweise IP-Adressen korrekt eingetragen sind und ob gegebenenfalls verwendete individuelle SSH-Ports oder weitere Verbindungsparameter richtig konfiguriert wurden.
Mit ssh-add -l lässt sich überprüfen, ob der benötigte SSH-Schlüssel in den SSH-Agent geladen wurde. Ist der Schlüssel dort nicht aufgeführt, kann er beispielsweise mit ssh-add ~/.ssh/id_rsa hinzugefügt werden. Falls sich der private Schlüssel an einem anderen Speicherort befindet, muss der entsprechende Pfad eingesetzt werden. Zusätzlich sollte kontrolliert werden, ob der dazugehörige öffentliche Schlüssel auf dem verwalteten Host in ~/.ssh/authorized_keys vorhanden ist.
Fehler beim Ausführen des Ansible-Playbooks
Wenn ein Task innerhalb des Playbooks fehlschlägt, stoppt Ansible die Ausführung und gibt eine Fehlermeldung aus, aus der hervorgeht, welcher Task betroffen ist und warum er nicht erfolgreich abgeschlossen werden konnte. Diese Meldungen stellen die wichtigste Grundlage für die Fehleranalyse dar. Üblicherweise enthalten sie den Namen des Tasks, das verwendete Modul und nähere Informationen zur Fehlerursache.
Bei der ersten Analyse sollte daher die Ansible-Fehlerausgabe überprüft und der fehlgeschlagene Task identifiziert werden. Die Meldungen liefern häufig Hinweise auf Ursachen wie unzureichende Berechtigungen, nicht erreichbare URLs oder Syntaxfehler im Playbook.
Enthält die normale Ausgabe nicht genügend Details, kann das Playbook im ausführlichen Modus gestartet werden, um die Abläufe von Ansible genauer zu beobachten:
ansible-playbook playbook.yml -vvv
Die Option -vvv aktiviert eine sehr ausführliche Ausgabe. Dabei werden unter anderem die ausgeführten Befehle, vollständige Ergebnisse der einzelnen Tasks und zusätzliche Debugging-Informationen angezeigt. Dies ist besonders hilfreich bei der Untersuchung von Netzwerkproblemen, Berechtigungsfehlern oder unerwartetem Verhalten eines Ansible-Moduls.
Bevor das Playbook erneut ausgeführt wird, sollte kontrolliert werden, ob alle benötigten Ressourcen erreichbar sind. Die URL des Docker-GPG-Schlüssels muss verfügbar sein, die verwalteten Hosts benötigen eine Internetverbindung zum Herunterladen der Pakete und auf dem System muss ausreichend freier Speicherplatz für die Installation vorhanden sein.
Da das Playbook idempotent aufgebaut ist, kann es nach der Behebung eines Fehlers problemlos erneut ausgeführt werden. Bereits erfolgreich abgeschlossene Tasks werden normalerweise mit ok statt changed angezeigt, während Ansible nur noch die Aufgaben bearbeitet, bei denen weiterhin Änderungen notwendig sind.
Häufig gestellte Fragen zu Ansible und Docker
1. Welche Ansible-Version wird für dieses Playbook benötigt?
Grundsätzlich sollte jede aktuelle Ansible-Version geeignet sein. Ansible 2.10 oder neuer stellt jedoch eine sinnvolle Ausgangsbasis dar. Ab dieser Version wird standardmäßig die Collections-Struktur verwendet. Dies ist für das hier verwendete Playbook relevant, da die Collection community.docker für die Tasks docker_image und docker_container benötigt wird. Die installierte Version kann auf dem Control-Node mit ansible --version überprüft werden.
2. Installiert das Playbook Docker Compose und welche Version wird verwendet?
Ja. Das Playbook installiert das Paket docker-compose-plugin, das Docker Compose v2 bereitstellt. Bei Compose v2 wird Compose als Docker-Unterbefehl mit docker compose und einem Leerzeichen ausgeführt. Dies ersetzt den älteren eigenständigen Befehl docker-compose.
3. Warum Docker mit Ansible statt mit einem Shell-Skript oder Cloud-Init installieren?
Ansible erleichtert es, Serverkonfigurationen wiederholbar und nachvollziehbar zu gestalten. Da die Tasks idempotent arbeiten, kann dasselbe Playbook mehrfach ausgeführt werden, um Systeme in den gewünschten Zustand zu bringen. So lässt sich beispielsweise sicherstellen, dass das Docker-Repository eingerichtet ist und die richtigen Pakete installiert sind, ohne eigene Prüfungen dafür schreiben zu müssen, ob eine bestimmte Konfiguration bereits vorhanden ist. Außerdem lassen sich Playbooks einfach überprüfen, in einer Versionsverwaltung speichern und durch weitere Provisionierungsaufgaben ergänzen.
4. Was bedeutet Idempotenz bei diesem Ansible-Playbook?
Idempotenz bedeutet, dass dasselbe Playbook mehrfach ausgeführt werden kann und trotzdem vorhersehbare Ergebnisse liefert. Jeder Task prüft den aktuellen Systemzustand und führt nur dann Änderungen durch, wenn diese notwendig sind. Ist Docker beispielsweise bereits installiert, das Repository vorhanden und sind alle Pakete aktuell, meldet Ansible die entsprechenden Tasks mit ok, anstatt alles erneut zu installieren.
5. Kann das Playbook mehrere Ubuntu-Server gleichzeitig konfigurieren?
Ja. Dazu werden alle Zielsysteme zum Ansible-Inventory hinzugefügt, beispielsweise innerhalb derselben Host-Gruppe, und das Playbook anschließend gegen diese Gruppe ausgeführt. Ansible kann Tasks parallel auf mehreren Hosts ausführen. Der Grad der Parallelisierung lässt sich über die Einstellung forks in der Ansible-Konfiguration steuern.
6. Sollte ein eigenes Playbook oder die Ansible-Galaxy-Rolle geerlingguy.docker verwendet werden?
Welche Variante besser geeignet ist, hängt von den jeweiligen Anforderungen ab. Ein eigenes Playbook hält die komplette Konfiguration an einer Stelle und macht transparent, welche Änderungen tatsächlich auf dem System vorgenommen werden. Das kann beispielsweise bei internen Prüfungen oder Compliance-Anforderungen hilfreich sein. Eine verbreitete Galaxy-Rolle wie geerlingguy.docker kann dagegen Zeit sparen, fügt jedoch eine externe Abhängigkeit hinzu, die überprüft und regelmäßig aktuell gehalten werden sollte.
7. Wie lässt sich überprüfen, ob Docker korrekt installiert wurde?
Stelle über SSH eine Verbindung zum verwalteten System her und überprüfe anschließend, ob Docker korrekt reagiert:
- Die Version der Docker Engine mit
docker --versionüberprüfen. - Mit
sudo systemctl status dockerkontrollieren, ob der Docker-Daemon aktiv ist. - Mit
sudo docker run hello-worldeinen Testcontainer starten.
Wenn das Benutzerkonto zur Gruppe docker hinzugefügt wurde, können Docker-Befehle nach einer Abmeldung und erneuten Anmeldung auch ohne sudo ausgeführt werden. Ob Docker Compose v2 verfügbar ist, lässt sich mit docker compose version überprüfen.
Fazit
Die Automatisierung der Infrastrukturkonfiguration spart nicht nur Zeit, sondern unterstützt auch dabei, Server nach einem einheitlichen Schema einzurichten, das bei Bedarf an individuelle Anforderungen angepasst werden kann. Da moderne Anwendungen häufig auf mehrere Systeme verteilt sind und konsistente Entwicklungs-, Staging- und Produktionsumgebungen benötigen, ist Infrastrukturautomatisierung zu einem wichtigen Bestandteil vieler Entwicklungsabläufe geworden.
Diese Anleitung hat gezeigt, wie sich die Installation und Konfiguration von Docker auf einem entfernten Ubuntu-24.04-Server mit Ansible automatisieren lässt. Dabei wurde auch das aktuelle Docker-Compose-Plugin berücksichtigt. Da die Anforderungen an Container je nach Umgebung unterschiedlich ausfallen können, bietet die offizielle Ansible-Dokumentation weitere Informationen und Anwendungsbeispiele für das Ansible-Modul docker_container.
Bei Bedarf können dem Playbook zusätzliche Tasks hinzugefügt werden, um die grundlegende Serverkonfiguration weiter an die eigenen Anforderungen anzupassen. Weiterführende Grundlagen zum Schreiben von Ansible-Playbooks können dabei helfen, die Automatisierung anschließend um weitere Funktionen zu erweitern.


