Die Docker Images aus dem letzten Teil der Reihe haben uns schon ein ganzes Stück weiter in Richtung Docker gebracht. Doch es gibt natürlich noch mehr coole Features. Wenn wir unsere Docker Images nicht jedes mal mühsam in der Konsole zusammenstellen wollen bevor wir sie dann wieder committen gibt es das sogenannte Dockerfile.
Ähnlich wie in anderen Umgebungen (zum Beispiel Vagrant) beschreibt das Dockerfile, wie die Umgebung aufgebaut werden soll. Was das genau bedeutet sehen wir uns jetzt genauer an.
Inhaltsverzeichnis
Was ist das Dockerfile?
Ein Dockerfile ist eine simpel aufgebaute Textdatei. Darin wird der Aufbau eines Docker Images beschrieben. Am einfachsten können wir uns das als Schritt für Schritt Anleitung vorstellen, wie das Image aufgebaut werden soll:
- Starte Container vom Typ ubuntu
- Führe Befehl apt-get install apache2 aus
- Speichere neue Version des Images ab
- Führe Befehl apt-get install mysql aus
- Speichere neue Version des Images ab
Durch diesen Schritt für Schritt Vorgang kann das Image immer wieder auf dieselbe Art erzeugt werden. Dieses Dockerfile können wir dann natürlich auch unseren Kollegen schicken (oder es in einer Versionskontrolle wie z.B. GIT ablegen) und diese können dann genau dasselbe Image aus dem Dockerfile erzeugen.
Ein Image aus dem Dockerfile erzeugen
Um ein fertiges Image aus einem Dockerfile zu erzeugen genügt uns ein einfacher Befehl: docker build
Der build Befehl bekommt einen sogenannten Kontext als Parameter. Der Kontext ist einfach ein Verzeichnis dessen Inhalt an den Docker Daemon weitergeleitet wird. Dieser Inhalt steht dann für das Erzeugen des Images zur Verfügung.
Ganz einfach betrachtet könnte das zum Beispiel ein leeres Verzeichnis mit einem Dockerfile darin sein. Standardmäßig sucht Docker innerhalb des Kontextverzeichnis nach eben diesem Dockerfile, mit dem Parameter -f können wir aber auch einen anderen Ort dafür angeben.
Um unser Image zu bauen wechseln wir also innerhalb der Konsole in unser Verzeichnis und führen folgenden Befehl aus:
docker build -t ftiersch/mein-php-server .
Den Parameter -t kennen wir schon aus dem vorherigen Artikel. Dadurch weisen wir dem Image, das wir aus dem Dockerfile erzeugen, einen Namen zu den wir später wieder verwenden können. Ganz wichtig ist auch der Punkt am Ende. Der Punkt steht hier für das aktuelle Verzeichnis und beschreibt dementsprechend das Kontextverzeichnis, das zum Erzeugen des Images verwendet wird.
Aufbau des Dockerfiles
Unser Dockerfile ist herzlich einfach aufgebaut. In jeder Zeile steht genau ein Befehl (welche das sein können sehen wir uns gleich an) mit einem Parameter. Um Befehl von Parameter besser zu trennen hat sich die Konvention
BEFEHL parameter
durchgesetzt, wobei der Befehl durchgehend groß geschrieben wird. Einzelne Zeilen können dabei mit einem # am Anfang auskommentiert werden.
Beim Bauen wird unser Dockerfile Zeile für Zeile abgearbeitet. In jeder Zeile wird der passende Befehl ausgeführt und dabei ein Zwischenimage erzeugt. Dieses Zwischenimage wird dann als Grundlage für die nächste Zeile verwendet. Wird eine Zeile erfolgreich abgeschlossen bleibt das Image auch vorhanden, das heißt solange sich vorher im Dockerfile nichts ändert kann Docker beim nächsten build Aufruf direkt an dieser Stelle weitermachen. Das spart natürlich grade bei aufwendigen Befehlen wie der Installation von mehreren Anwendungen viel Zeit.
Befehl: FROM
Der wichtigste Befehl im Dockerfile ist FROM. Dieser muss ganz oben stehen und beschreibt ganz einfach, welches Image die Grundlage für unser neu erzeugtes Image ist. Das können sowohl Basisimages wie beispielsweise ubuntu oder ubuntu:trusty sein aber genauso natürlich von Usern (oder uns selbst) erzeugte Images wie ftiersch/mein-test-server.
FROM ubuntu:trusty
Befehl: MAINTAINER
Mit dem MAINTAINER Befehl können wir den Autor des Images setzen.
MAINTAINER Frank Tiersch <mail@ftiersch.de>
Befehl: RUN
Einer der wichtigsten Befehle ist sicherlich der Befehl RUN. Dieser führt den Parameter einfach als Shell Befehl aus, gibt uns also die Flexibilität, in unserer virtuellen Maschine quasi alles zu machen. Der Befehl
RUN sudo apt-get install -y apache2
wird also intern übersetzt in
/bin/sh -c sudo apt-get install -y apache2
Eine zweite Möglichkeit, den RUN Befehl auszuführen, ist mit der sogenannten exec Syntax.
RUN [„executable“, „param1“, „param2“]
In vielen Fällen werden unsere Dockerfiles also eine Verkettung vieler RUN Befehle sein. Auch hier nochmal die Erinnerung: Jeder RUN Befehl erzeugt einen neuen Layer im Image – verbraucht also Speicher. Das bedeutet wir sollten die Anzahl möglichst gering halten und mehrere Dinge innerhalb eines Befehles erledigen.
Anstatt also
RUN sudo apt-get install -y apache2
RUN sudo apt-get install -y nodejs
RUN sudo apt-get install -y npm
aufzurufen können wir das in einem Befehl verbinden:
RUN sudo apt-get install -y apache2 nodejs npm
Befehl: CMD
CMD bietet einem Container, der aus unserem Image erzeugt wird, einen Standardcommand der ausgeführt wird. Dieser kann allerdings natürlich vom Container auch überschrieben werden. Es kann nur einen CMD Befehl pro Dockerimage geben, werden mehrere definiert ist nur der letzte davon gültig. Von der Syntax her funktioniert CMD genau wie RUN.
CMD echo „Hello world“
Befehl: EXPOSE
Ein wichtiger Punkt bei Docker ist die Kommunikation inner- und außerhalb der Container. Dafür müssen Ports freigegeben werden und genau darum kümmert sich der EXPOSE Befehl. Möchten wir beispielsweise einen Webserver innerhalb eines Containers laufen lassen können wir mit
EXPOSE 80
dafür sorgen, dass der Port 80 überwacht wird.
Befehl: ADD / COPY
ADD und COPY sind zwei sehr ähnliche Befehle – wobei ADD etwas mehr kann als COPY. Aber diese Feinheiten gehen für unser Einsteigertutorial zu weit.
Beide Befehle nehmen eine Datei oder ein Verzeichnis auf dem Hostsystem (oder genauer: dem Kontextverzeichnis das wir weiter oben kennengelernt haben) und fügen diese in das Dateisystem des Images ein. Die Syntax ist dabei sehr simpel:
ADD directory1 /var/www/directory1
Zuerst kommt das Verzeichnis oder die Datei, die kopiert werden soll und als zweites das Ziel. Für COPY sieht die Syntax gleich aus. Beide haben außerdem eine alternative Syntax, die verwendet werden muss, wenn einer der Namen Leerzeichen enthält:
COPY [„directory1“, „/var/www/directory1“]
Diese Befehle ermöglichen es uns zum Beispiel Konfigurationsdateien (wie die Apache2 Konfiguration oder eine php.ini) in unser neu angelegtes Image zu überspielen.
Befehl: WORKDIR
Jeder RUN, CMD, ADD und COPY Befehl geht erstmal vom root Verzeichnis aus. Möchten wir das ändern funktioniert das mit dem WORKDIR Befehl ganz einfach. Dieser setzt das neue Referenzverzeichnis für alle folgenden Befehle (oder bis zum nächsten Aufruf von WORKDIR).
WORKDIR /var/www
Dabei kann ich auch einen relativen Pfad übergeben, der sich am letzten WORKDIR Aufruf orientiert.
WORKDIR vhosts/www.meine-seite.de
Der neue Referenzpfad nach den obigen beiden Aufrufen wäre also /var/www/vhosts/www.meine-seite.de
Das war mal ein Überblick über die wichtigsten Befehle im Dockerfile. Für mehr Informationen solltest du am besten die offizielle Docker Dokumentation anschauen. Wie benutzt du das Dockerfile am liebsten? Hinterlass mir gerne einen Kommentar.
Immer aktuelle Artikel zum Thema Docker, PHP und JavaScript? Dann folge mir einfach bei Twitter unter @AbHeuteCoden.
10 Kommentare zu “Docker – Teil 4: Das Dockerfile”