Vorstellung von Docker

Was ist Docker und wie erstellt man eigene Images

Christoph Giesel

Was ist Docker?

Docker ist ein Linux Software mit der es möglich ist, Programme in Container isoliert auszuführen. Hierbei werden sogenannte Docker Images ausgeführt, welche minimale Linux Installationen sind, bei der die auszuführende Software bereits installiert und konfiguriert wurde. Dabei wird nicht mit jedem Container der Kernel des jeweiligen Images gestartet, sondern Funktionen wie cgroups und namespaces des Kernels des Hostsystems genutzt, um die Anwendungen in dem getrennten System auszuführen.

 

In den Images ist definiert, welche Ports sowie Verzeichnisse nach außen freigegeben werden. Bei dem Start des Containers können diese den Ports bzw. Verzeichnissen des Hostsystems zugeordnet werden. Außerdem ist es möglich Container miteinander zu verlinken, wodurch diese auf die Ports untereinander zugreifen können. Beispielsweise kann so eine Applikation wie Odoo auf eine Datenbank wie PostgreSQL zugreifen.

Vorteile

Die Trennung der Anwendungen von dem Hostsystem hat einige Vorteile. Besitzt diese Anwendung beispielsweise eine Sicherheitlücke, so ist es schwerer möglich auf das Hostbetriebsystem zuzugreifen. Um Docker besser abzusichern hat Red Hat ihre Sicherheitssoftware SELinux entsprechend angepasst. Außerdem ermöglichen solche Container das Betreiben der gleichen Software in mehreren Instanzen auf dem gleichen Server ohne diese kompliziert unterschiedlich zu konfigurieren. Durch die Vorkonfiguration dieser Images ist es auch möglich einfach und schnell die Software auf mehreren Server zu verteilen, um beispielsweise Lasten besser abzufangen.


Alternativ könnte man die Anwendungen mit anderer Virtualisierung isoliert laufen lassen. Je nach verwendeter Lösung bedeutet der Betrieb einer virtuellen Instanz einen größeren Overhead, da hier meist für jeden virtuellen Server ein eigener Kernel betrieben wird. Docker ist hingegen leichtgewichtig und benutzt den Kernel des Hostsystems. Besonders bei dem Start eines Docker Containers merkt man dies gut. Innerhalb von wenigen Sekunden ist ein Container gestartet. Zudem entfällt die Konfiguration durch die vorgefertigten Images.

Installation unter Linux

Docker ist eine Linuxsoftware, welche Funktionen des Linuxkernels benutzt. Dadurch lässt sich die Software ansich nur unter Linux installieren. Die meisten Distributionen bieten hierfür fertige Pakete an. Ebenso werden von Docker eigene Pakete bereitgestellt. Als Distribution kann ich derzeit Ubuntu empfehlen. Hier sollte man aber schauen wie geeignet die angebotenen Images der Provider (sofern man solche verwendet) geeignet sind. Um das passende Paket auszuwählen, kann die offizielle Installationsanleitung zu rate gezogen werden. Dort sind die in den Repositories angebotenen Paketnamen gelistet sowie von Docker angebotene Repositories mit den aktuellsten Versionen beschrieben. Ist das Paket installiert, so sind keine weiteren Schritte für die Einrichtung notwendig.

Installation unter OSX

Um Docker auch unter OSX und Windows zu betreiben, existiert die Lösung boot2docker. Hierfür werden entsprechende Installationsdateien angeboten. Boot2docker benutzt VirtualBox, um eine virtuelle Maschine zu installieren, welche als Docker Host betrieben wird. Die Docker Befehle werden dann an diese virtuelle Maschine weitergeleitet.

 

Unter OSX muss einmalig die virtuelle Machine mit folgenden Befehl eingerichtet werden:

 
boot2docker init
 

Gestartet wird die Instanz mit:

 
boot2docker up
 

Möchte man nun Docker Befehle ausführen, so muss vorher folgender Befehl im aktuellen Terminal ausgeführt werden, sodass die entsprechenden Umgebungsvariablen gesetzt sind (dies muss bei jedem neuen Terminal gemacht werden):

 
$(boot2docker shellinit)
 

Bei boot2docker sollte beachtet werden, dass das Benutzen von freigegebenen Ports oder das Teilen von Verzeichnissen ein wenig anders funktioniert. Der Port ist nicht über localhost erreichbar, sondern muss über die IP der virtuellen Maschine aufgerufen werden. Die IP erhält man über:

 
boot2docker ip

Fertige Docker Images und der erste Start

Es existieren zahlreiche fertige Docker Images. Hierfür wurde extra eine sogenannte Registry  eingerichtet. Dort sind viele bekannte Applikationen und Services vorhanden. Die Hersteller einiger bekannter Anwendungen bieten dort offizielle Images an. Ein Beispiel solch einer Anwendung ist Odoo. Um das offizielle Image zu nutzen, benötigen wir eine Installation von PostgreSQL. Hierfür kann ebenfalls docker verwendet werden.

 

Start von PostgreSQL:

 
docker run -d -e POSTGRES_USER=odoo -e POSTGRES_PASSWORD=odoo --name db postgres
 

Bei dem ersten Start wird das Image “postgres” heruntergelanden sowie entpackt. Die Option “-d” gibt an, dass der Container im Hintergrund gestartet wird. Mit “-e” übergibt man Paramter an die VM. In diesem Fall wird initial der Benutzer odoo mit dem Passwort odoo angelegt. Dem Container wird der name “db” mit “--name” gegeben.

 

Nun starten wir odoo:

 
docker run -p 8069:8069 --name odoo --link db:db -t odoo
 

Mit dem Parameter “-p” wird der Port des Docker Containers dem Hostsystem bereitgestellt. Dies mappt den Port auf einen den spezifizierten Port - in diesem Fall den selben (der erste ist der lokale Port, der zweite der Port des Containers). Gibt man hier stattdessen “-P” an, so würden alle definierten Ports (in dem Fall 8069) auf zufällige Ports gemappt werden. Mit Hilfe von “docker ps” kann man diese erfahren. Als Name wird “odoo” gewält. Mit dem “--link” Parameter wird die odoo Instanz mit der PostgreSQL Instanz verlinkt. Odoo kann nun mit Hilfe von speziellen Variablen unter anderem die IP der anderen Instanz erfahren und auf diese zugreifen, ohne dass der Port mit Hilfe von “-p” oder “-P” nach außen freigegeben werden muss.

 

Odoo kann nun über http://127.0.0.1:8069 zugegriffen werden. Ist boot2docker installiert, muss zuerst die IP per “boot2docker ip” ermittelt werden und dann 127.0.0.1 durch diese ersetzt werden.


Bei dem Start von Odoo wurde die Option “-d” weggelassen. Dadurch wird die Ausgabe von Odoo in der Konsole ausgegeben. Ein STRG+C beendet die Ausgabe, aber lässt Odoo weiter im Hintergrund laufen. Mit “docker start -a odoo” wird die Ausgabe wieder angezeigt. Ein “docker stop odoo” beendet schließlich die Instanz. Beachten sollte man, dass sofern die PostgreSQL Instanz neugestartet wird, diese erneut mit der Odoo Instanz gelinkt werden muss, da sich dadurch die IP ändert.

Das Dockerfile

Um ein Docker Image zu erstellen wird ein Datei mit dem Namen Dockerfile erstellt. Hierzu ist es gut sich bestehende Dockerfiles anzuschauen. Das Dockerfile von dem Odoo Image findet man in GitHub. Im folgenden möchte ich auf die wichtigsten Anweisungen von Dockerfiles eingehen:

 

FROM - Hier gibt man das Docker Image an, welches als Grundlage für das aktuelle Image genommen wird. Möchte man seine eigene Anwendung “dockerisieren” so nutzt man üblicherweise das Image einer Distribution. Beliebt sind hier Ubuntu und Debian in einer Version. Für das Odoo Image wurde die Testingversion Jessie benutzt.

 

MAINTAINER - Hiermit wird der Name des Betreuers des Images angegeben.

 

RUN - Dies führt Befehle in dem Image aus. Möchte man mehrere Befehle angeben, so kann man RUN mehrmals verwenden oder diese beispielsweise wie in der Shell durch “&&” oder “;” hintereinander ausführen lassen.

 

COPY - Benötigt man bestimmte Dateien wie Konfigurationsdateien o.ä. kann man diese in den selben Ordner legen, in der das Dockerfile liegt. Mit COPY wird angegeben, dass die Datei zu einem bestimmten Pfad innerhalb des Images kopiert werden soll.

 

ENV - Hiermit gibt man Variablen an, die man innerhalb der Datei benutzen kann. Diese kann man bei dem Start mit “-e” überschrieben (siehe beim Start von PostgreSQL).

 

CMD - Mit CMD wird der Befehl angegeben, welcher beim Start des Containers ausgeführt wird sofern kein anderer beim Start angegeben wird. Wird der hier angegebene Befehl beendet, so beendet sich auch Docker.

 

ENTRYPOINT - Ähnlich wie CMD wird auch hier der auzuführende Befehl angegeben. Wird dieser angegeben, so wird dieser standardmäßig ausgeführt und sofern kein Befehl beim Start angegeben ist, der Inhalt von CMD angehangen (sozusagen als Parameter). Wird stattdessen ein Befehl beim Start angegeben, so wird dieser statt des Inhalts von CMD an den Inhalt von ENTRYPOINT angehangen und ausgeführt. Dieser Befehl läuft auch nach einem STRG+C o.ä. im Hintergrund weiter.

 

EXPOSE - Hier werden die Ports angegeben, welche nach außen angeboten werden. Möchte man diese Ports nutzen, so muss beim Start der Parameter “-p” oder “-P” angegeben werden.

 

VOLUME - Ähnlich wie bei EXPOSE werden hier die Verzeichnisse angegeben, welche beim Start eingebunden werden können. Hierbei wird aber das Verzeichnis des Dockerhosts in den Container eingebunden.

 

Beachtet werden muss hier, dass bei jedem Build die Zeilen gecacht werden. Beim nächsten Build wird nur die Zeile ausgeführt, die geändert oder hinzugefügt wurde. Fügt man beispielsweise ein “apt-get install <package>” nach einem bereits bestehenden “apt-get update” hinzu, so können in der Zwischenzeit die Paketquellen im Image veraltet und dieses Paket nicht mehr gefunden werden, da “apt-get update” nicht erneut ausgeführt wird. Deshalb werden diese Zeilen oft verbunden (RUN apt-get update && apt-get install <package>). Generell sollte man den Cache löschen bzw. ignorieren lassen, wenn man nach längerer Zeit das Image neubaut. Insbesondere sollte ein Upgrade der Pakete im Dockerfile enthalten sein, so dass Sicherheitsupdates installiert werden.

Ausführen und Betrieb

Bauen kann man das Docker Image mit:

 
docker build -t <imagetag> <pfad zum Verzeichnis des Dockerfiles>
 

Hierbei gibt man den Tag an, den man später beim Befehl benutzen kann. Am Ende muss der Pfad zum Verzeichnis des Dockerfiles angegeben werden (also nicht direkt zum Dockerfile). Beachten sollte man, dass in diesem Verzeichnis nur benötigte Dateien bzw. keine großen unrelevanten Dateien vorhanden sind, da bei jedem Build alle Dateien an den Docker Daemon gesendet werden. Besonders bei boot2docker kann dies bei größeren Dateien unnötig länger dauern.

 

Starten kann man das erstellte Image wie zuvor mit (und ggf zusätzlichen Parametern):

 
docker run --name <containername> <imagetag>
 

Möchte man sich in einen laufenden Container per Shell zugreifen, so kann man entweder im Image einen SSH Server konfigurieren und den Port freigeben oder folgenden Befehl ausführen:

 
docker exec -t -i <containername> bash


Der Parameter “-t” erstellt eine Pseud TTY und “-i” bedeutet, dass dies Interaktiv sein soll, wodurch Eingaben wahrgenommen werden. Mit “docker exec” können generell Befehle oder auch bereits existierende Skripte ausgeführt werden.

About Christoph Giesel

He drinks no coffee but likes mate, python and devOps stuff.