- 1 1. Einleitung
- 2 2. Grundstruktur einer Dockerfile
- 3 3. Praxis: Erstellung eines Ubuntu-Dockerfiles
- 4 4. Docker-Image bauen und überprüfen
- 5 5. Erweiterung: Python-Umgebung aufbauen
- 6 6. Häufige Probleme & Lösungen
- 7 7. Fazit
- 8 8. FAQ (Häufig gestellte Fragen)
- 8.1 Q1. Welche Ubuntu-Version sollte ich im Dockerfile wählen?
- 8.2 Q2. Warum erhalte ich bei apt-get install die Meldung „Paket nicht gefunden“?
- 8.3 Q3. Wie setze ich Umgebungsvariablen in einer Dockerfile?
- 8.4 Q4. Was ist der Unterschied zwischen CMD und ENTRYPOINT?
- 8.5 Q5. Warum werden Änderungen an der Dockerfile nicht übernommen?
1. Einleitung
Was sind Docker und Dockerfile?
In den letzten Jahren hat sich Docker rasant als effiziente Lösung zur Einrichtung von Entwicklungsumgebungen und für das Deployment von Anwendungen etabliert. Docker verpackt eine Anwendung und deren Abhängigkeiten als sogenannten „Container“, der überall in der gleichen Umgebung ausgeführt werden kann.
Für den Aufbau eines solchen Docker-Containers wird eine sogenannte Dockerfile benötigt. Eine Dockerfile ist eine Textdatei, in der das Basis-Betriebssystem, die zu installierende Software und Umgebungsvariablen definiert werden. Entwickler können mit dieser Datei automatisiert individuell angepasste Umgebungen erstellen.
Warum als Basis Ubuntu wählen?
Bei der Erstellung einer Dockerfile muss zuerst das Basis-OS-Image angegeben werden. Besonders beliebt ist dabei Ubuntu. Ubuntu ist eine auf Debian basierende Linux-Distribution, die sich durch Benutzerfreundlichkeit und eine große Auswahl an Paketen für flexible Umgebungen auszeichnet.
Ein auf Ubuntu basierendes Dockerfile bietet folgende Vorteile:
- Zahlreiche offizielle und Community-Dokumentationen erleichtern das Lernen
- Viele Pakete und Tools lassen sich unkompliziert über APT installieren
- Offizielle, schlanke Minimal-Images (
ubuntu:20.04
,ubuntu:24.04
etc.) sind verfügbar
Ziel & Zielgruppe dieses Artikels
In diesem Artikel erklären wir unter dem Stichwort „Dockerfile Ubuntu“, wie man ein Ubuntu-basiertes Dockerfile auch als Einsteiger einfach erstellt.
Konkret behandeln wir den grundlegenden Aufbau einer Dockerfile, die praktische Umsetzung für Ubuntu-Umgebungen, Beispiele für die Integration von Python-Anwendungen sowie häufige Fehler und deren Lösungen.
Dieser Beitrag ist besonders geeignet für:
- Alle, die zum ersten Mal eine Umgebung mit Dockerfile aufbauen möchten
- Entwickler, die eine reproduzierbare Entwicklungsumgebung mit Ubuntu anlegen wollen
- Leser, die auch Problemlösungen und Troubleshooting kennenlernen möchten
2. Grundstruktur einer Dockerfile
Was ist eine Dockerfile? Rolle und Nutzen
Eine Dockerfile ist wie ein Rezept für das Erstellen eines Docker-Images. Konkret wird darin festgelegt, welches Basis-OS verwendet wird, welche Software installiert und welche Konfigurationen vorgenommen werden.
Mit dem docker build
-Befehl kann anhand der Dockerfile schnell und zuverlässig eine Entwicklungs- oder Ausführungsumgebung gebaut werden.
Vorteile einer Dockerfile:
- Automatisierung der Umgebungseinrichtung (keine manuellen Wiederholungen nötig)
- Gleiche Umgebung für alle Teammitglieder – keine Abweichungen
- Leicht in CI/CD-Pipelines integrierbar
Wichtige Befehle (Direktiven) in einer Dockerfile
Folgende Direktiven werden in einer Dockerfile häufig verwendet. Sie bilden die Basis für Ubuntu-Dockerfiles:
Befehl | Beschreibung |
---|---|
FROM | Definiert das Basis-Image, z. B.: FROM ubuntu:24.04 |
RUN | Führt Shell-Kommandos aus, etwa zur Paketinstallation |
COPY | Kopiert lokale Dateien ins Image |
ADD | Ähnlich wie COPY, kann aber auch aus URLs laden und Archive entpacken |
WORKDIR | Setzt das Arbeitsverzeichnis |
ENV | Setzt Umgebungsvariablen |
CMD | Definiert den beim Start auszuführenden Befehl (überschreibbar) |
ENTRYPOINT | Legt einen auszuführenden Befehl fest, der immer gestartet wird |
Minimalbeispiel: Dockerfile auf Ubuntu-Basis
Ein einfaches Beispiel für ein Ubuntu-basiertes Dockerfile:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
vim
CMD ["/bin/bash"]
Dieses Dockerfile verwendet Ubuntu 24.04 als Basis, installiert die Tools curl
und vim
und startet abschließend die bash-Shell.
Hinweise zur Ubuntu-Tag-Wahl
Ubuntu-Images sind im offiziellen Docker Hub Repository verfügbar. Mit ubuntu:latest
erhält man immer die neueste Version, es wird jedoch empfohlen, die Version explizit anzugeben.
Beispiele:
ubuntu:22.04
(LTS: Long Term Support, Stabilität)ubuntu:24.04
(neustes LTS, aktuelle Features)
Je nach Einsatzzweck sollte man Stabilität oder Aktualität priorisieren.
3. Praxis: Erstellung eines Ubuntu-Dockerfiles
Wichtige Pakete in einer Ubuntu-Umgebung installieren
Beim Aufbau einer Ubuntu-Umgebung per Dockerfile werden häufig zusätzliche Pakete benötigt. Typische Utilities für die Entwicklungsumgebung sind zum Beispiel:
curl
: Download von Dateien, API-Testsvim
: Texteditorgit
: Versionsverwaltungbuild-essential
: Tools zum Bauen von C/C++
Die Installation erfolgt mit dem RUN
-Befehl:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
vim \
git \
build-essential
Das vorgelagerte apt-get update
aktualisiert die Paketlisten.
Nicht-interaktive Installation
Da apt-get install
manchmal Benutzereingaben benötigt, empfiehlt sich für den automatisierten Docker-Build der nicht-interaktive Modus:
ENV DEBIAN_FRONTEND=noninteractive
Damit werden z. B. Rückfragen zur Region oder Sprache übersprungen und die Installation läuft automatisch durch.
Image-Verkleinerung durch Cache-Löschung
APT speichert temporäre Dateien im Image. Durch das Löschen des Caches verringert sich die Image-Größe:
RUN apt-get update && apt-get install -y \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
Zudem sollte man möglichst viele Kommandos in einer RUN
-Zeile bündeln, um die Layer-Anzahl zu minimieren.
Best Practices für Dockerfiles
Empfohlene Best Practices für produktionsreife Dockerfiles:
RUN
-Befehle bündeln, um Layer zu reduzieren- Versionen und Einstellungen mit
ENV
deklarieren - Zweck der Befehle mit Kommentaren erläutern
- Unnötige Dateien vermeiden,
rm
und--no-install-recommends
verwenden
Beispiel:
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
So werden Dockerfiles wartbarer und Images schlanker.
4. Docker-Image bauen und überprüfen
Docker-Image aus Dockerfile bauen
Nach dem Schreiben der Dockerfile erfolgt der Build mit folgendem Befehl im entsprechenden Verzeichnis:
docker build -t my-ubuntu-image .
-t
legt den Namen (Tag) des Images fest, hier z. B.my-ubuntu-image
..
steht für das aktuelle Verzeichnis mit der Dockerfile.
Docker liest die Befehle sequentiell aus und erstellt ein neues Image.
Erstellte Docker-Images überprüfen
Mit folgendem Befehl lässt sich die Übersicht anzeigen:
docker images
Beispielausgabe:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu-image latest abcd1234abcd vor 5 Minuten 189MB
So sieht man, dass das Image erfolgreich erstellt wurde.
Container starten und Funktion prüfen
Mit folgendem Befehl kann das Image als Container gestartet und getestet werden:
docker run -it my-ubuntu-image
-it
startet ein interaktives Terminal.- Bei Erfolg erscheint die Bash-Shell der Ubuntu-Umgebung.
Testen Sie installierte Tools im Container z. B. so:
curl --version
vim --version
Wenn alles wie erwartet funktioniert, ist das Dockerfile korrekt.
Nicht mehr benötigte Images und Container bereinigen
Um Speicherplatz zu sparen und Probleme zu vermeiden, empfiehlt sich regelmäßiges Aufräumen mit folgenden Befehlen:
- Gestoppte Container entfernen:
docker container prune
- Unbenutzte Images löschen:
docker image prune
- Alles Unbenutzte löschen (Vorsicht!):
docker system prune
Dies spart Speicher und verhindert Konflikte.
5. Erweiterung: Python-Umgebung aufbauen
Python in Ubuntu-Dockerfiles nutzen
Mit einer Dockerfile lässt sich eine Python-Entwicklungsumgebung flexibel aufbauen. Auch wenn Ubuntu oft Python vorinstalliert hat, empfiehlt sich aus Gründen der Versionskontrolle eine explizite Installation.
Python-Installation per APT
Der einfachste Weg ist die Installation über die Paketverwaltung:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
Damit steht ein aktuelles, stabiles Python samt pip zur Verfügung. Zusätzliche Pakete können mit pip
installiert werden.
pyenv zur Python-Versionverwaltung nutzen
Für spezielle Python-Versionen oder Multi-Versionen empfiehlt sich pyenv:
Beispiel für Python 3.11.6 Installation via pyenv im Dockerfile:
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
git \
curl \
make \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
wget \
llvm \
libncurses5-dev \
libncursesw5-dev \
xz-utils \
tk-dev \
libffi-dev \
liblzma-dev \
&& rm -rf /var/lib/apt/lists/*
# pyenv installieren
RUN git clone https://github.com/pyenv/pyenv.git ~/.pyenv
ENV PYENV_ROOT="$HOME/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PATH"
RUN echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
# Gewünschte Python-Version installieren
RUN pyenv install 3.11.6 && pyenv global 3.11.6
Damit können verschiedene Python-Versionen parallel gemanagt werden.
Python-Pakete via requirements.txt verwalten
Für Projekte mit mehreren Abhängigkeiten empfiehlt sich ein requirements.txt
:
flask==2.3.2
requests>=2.25.1
pandas
Dockerfile-Auszug:
COPY requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip install --no-cache-dir -r requirements.txt
So wird die Paketinstallation reproduzierbar und komfortabel.
Best Practices für Python mit Docker
- Virtuelle Umgebungen (
virtualenv
odervenv
) nutzen zur Vermeidung von Abhängigkeitskonflikten - Mit
--no-cache-dir
wird das Image kleiner - Vor der Paketinstallation
pip install --upgrade pip
verwenden, um Fehler zu vermeiden
6. Häufige Probleme & Lösungen
Fehler: Berechtigungen (Permission denied)
Beispiel:
Permission denied
Passiert, wenn kopierte Dateien keine Ausführungsrechte haben oder Nutzer falsch gesetzt sind.
Lösung:
- Dateien ausführbar machen:
RUN chmod +x script.sh
- Ggf. Nutzer/Gruppe anpassen:
RUN chown root:root /pfad/zu/datei
Paket nicht gefunden oder Installation schlägt fehl
Beispiel:
E: Unable to locate package xxx
Oft, wenn apt-get update
nicht ausgeführt oder Paketname falsch geschrieben wurde.
Lösung:
apt-get update
immer vorinstall
verwenden:
RUN apt-get update && apt-get install -y curl
- Paketnamen auf Korrektheit prüfen
Netzwerkprobleme
Beispiel:
Temporary failure resolving 'deb.debian.org'
Typisch bei Problemen mit der DNS-Auflösung während des Builds.
Lösung:
- Docker-Daemon neu starten:
sudo systemctl restart docker
- DNS-Einstellungen in
/etc/docker/daemon.json
anpassen:
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
Veralteter Build durch Cache
Docker verwendet Caching für Layer, dadurch werden Änderungen manchmal nicht übernommen.
Lösung:
- Build ohne Cache:
docker build --no-cache -t my-image .
Startbefehl im Container läuft nicht / beendet sofort
Ursachen:
CMD
oderENTRYPOINT
falsch oder fehlerhaft- Bei
CMD ["/bin/bash"]
ohne-it
schließt der Container sofort
Lösung:
- Container zum Debuggen interaktiv starten:
docker run -it my-image /bin/bash
- Unterschiede zwischen
CMD
undENTRYPOINT
beachten
Mit Erfahrung werden Fehler schneller analysiert. Die Fehlermeldung gibt meist Hinweise auf das Problem.
7. Fazit
Wichtige Punkte für Ubuntu-Dockerfiles
In diesem Beitrag haben wir Schritt für Schritt die Erstellung von Ubuntu-basierten Dockerfiles erläutert. Die wichtigsten Takeaways:
- Grundstruktur von Dockerfiles verstehen:
FROM
,RUN
,CMD
,ENV
u. a. sorgen für automatisierte Umgebungserstellung. - Ubuntu als stabiles, flexibles Basis-Image
Mit umfangreichen Paketen, großer Nutzerbasis und LTS-Versionen ideal als Entwicklungsgrundlage. - Effizientes Paketmanagement:
Tools und Bibliotheken perapt-get
installieren, Cache löschen, nicht-interaktive Modi nutzen. - Reale Entwicklungsumgebungen, z. B. für Python, lassen sich via
pyenv
,pip
undrequirements.txt
exakt abbilden. - Problemlösungs-Kompetenz ist zentral
Wer Fehlerursachen versteht, steigert die Entwicklungs-Effizienz deutlich.
Nächste Schritte beim Lernen von Dockerfiles
Mit Dockerfiles lassen sich nicht nur Entwicklungs-, sondern auch Test- und Produktionsumgebungen flexibel verwalten. Weitere empfohlene Themen:
- Mehrere Container mit Docker Compose orchestrieren
- Anbindung an CI/CD-Tools (z. B. GitHub Actions, GitLab CI)
- Container-Orchestrierung mit Kubernetes u. a.
Offizielle Dokumentation & Links
- Docker Offizielle Dokumentation (Englisch)
- Docker Hub – Offizielles Ubuntu-Image
- pyenv GitHub Repository
8. FAQ (Häufig gestellte Fragen)
Q1. Welche Ubuntu-Version sollte ich im Dockerfile wählen?
A1. Für Stabilität empfiehlt sich ein LTS (Long Term Support)-Release wie ubuntu:22.04
oder ubuntu:20.04
. Diese erhalten 5 Jahre Support und sind in der Entwicklung weit verbreitet.
Für neueste Pakete und Features kann ubuntu:24.04
gewählt werden, sollte aber getestet werden.
Q2. Warum erhalte ich bei apt-get install
die Meldung „Paket nicht gefunden“?
A2. Der häufigste Grund: apt-get update
wurde nicht vorher ausgeführt. Ohne aktuelle Paketlisten kann das gewünschte Paket nicht gefunden werden.
Richtiges Beispiel:
RUN apt-get update && apt-get install -y curl
Auch Tippfehler im Paketnamen oder veraltete Namen (z. B. python
statt python3
) prüfen.
Q3. Wie setze ich Umgebungsvariablen in einer Dockerfile?
A3. Mit dem Befehl ENV
, der für Build- und Laufzeit gilt.
Beispiel:
ENV DEBIAN_FRONTEND=noninteractive
Oft genutzt, um Installationsdialoge zu unterdrücken. Auch für App-Settings, API-Keys usw. einsetzbar.
Q4. Was ist der Unterschied zwischen CMD
und ENTRYPOINT
?
A4. Beide definieren Startbefehle für den Container, verhalten sich aber unterschiedlich:
Option | CMD | ENTRYPOINT |
---|---|---|
Überschreibbarkeit | Mit docker run überschreibbar | Wird immer ausgeführt, weitere Argumente werden übergeben |
Zweck | Standardbefehl definieren | Zwingend auszuführender Befehl |
Beispiel:
CMD ["python3", "app.py"]
# vs
ENTRYPOINT ["python3"]
CMD ["app.py"]
Im zweiten Fall kann man z. B. docker run my-image another_script.py
ausführen.
Q5. Warum werden Änderungen an der Dockerfile nicht übernommen?
A5. Docker verwendet beim Build ein Caching, wodurch kleinere Änderungen evtl. nicht übernommen werden.
Lösung:
docker build --no-cache -t my-image .
Damit werden alle Layer neu gebaut und alle Änderungen angewandt.