Zum Inhalt springen

Docker

Das Logo von Docker ist ein Walfisch der Container trägt - aber was steckt dahinter?

Was ist ein Container? Ein standardisierter Behälter, der den Transport von Gütern vereinfacht. Wie zum Beispiel der ISO Container.

Wir arbeiten mit Betriebssystemen und Software, was bedeutet Container hier?

Die Containervirtualisierung ist eine Methode auf einem Host-Betriebssystem mehrere Instanzen des Betriebssystem voneinander isoliert laufen zu lassen.

Docker ist das bekannteste Beispiel für Containervirtualisierung.

Schon vor der Containervirtualisierung gab es die Virtualisierung mit Hypervisor - z.B. mit VirtualBox oder VMWare. Ein Hypervisor lässt Virtuelle Maschinen (VMs) auf derselben Hardware laufen. Jede “Gast-VM” glaubt die Hardware alleine zu benutzen.

Bei der Containervirtualisierung werden Teile des Host-Betriebssystem in den Containern mit verwendet, die Virtualisierung erfolgt also auf einer höheren Ebene:

Wichtige Begriffe sind:

  • Image
  • Container
  • Volume
  • Dockerfile

Der Begriff Image wird nicht nur für digitale Bilder verwendet, sondern auch für das “Abbild” eines ganzen Dateisystems.

Wenn man z.B. mit CDs oder DVDs arbeitet spricht man davon ein “Image zu brennen” wenn man Daten auf der CD oder DVD speichert. Dieses Image enthält ein ganzes Dateisystem, das man dann später auf der DVD verwenden kann. Aber zum Zeitpunkt des “Brennens” ist das Image eine sehr große binäre Datei, die auf einen Schlag auf die DVD geschrieben wird.

Bei Docker ist ein Image ein vorbereitetes Dateisystem, das auf das Host-System “drauf-gesetzt” werden kann.

Mit dem Kommandozeilen-Befehl docker images kann man sehen welche images schon vorhanden sind:

Terminal-Fenster
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tb-web-development latest b0adb8f50f6c 11 days ago 1.64GB
pandoc/latex latest 5c1d8e5aafcd 2 months ago 654MB

Die Webseite Dockerhub https://hub.docker.com/ ist ein zentraler Speicher für Images. Hier kann Images suchen und ihre Dokumentation zu lesen: explore.

Und man kann sich registieren um Images hochzuladen oder runterzuladen.

Auf der Kommandozeile sieht das so aus:

Terminal-Fenster
docker login
docker pull pandoc/latex:latest
docker pull ubuntu:latest

Images haben immer einen Namen und eine Versionsbezeichnung, getrennt durch einen Doppelpunkt.

Ein Container ist eine lauffähige Zusammenstellung als Image plus weiterer Konfiguration. Der Container kann gestartet werden.

Mit dem Kommandozeilen-Befehl docker ps kann man sehen welche Container gerade laufen. So sieht das z.B. aus wenn gitlab in einem container läuft:

Terminal-Fenster
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cdf2ad32e7fc gitlab/gitlab-ce:latest "/assets/wrapper" 2 days ago Up 2 days (healthy) 193.171.143.2:22->22/tcp, 193.171.143.2:80->80/tcp, 193.171.143.2:443->443/tcp, 193.171.143.2:5050->5050/tcp, 193.171.143.4:80->8079/tcp gitlab_web_1

Auf dem server project.multimediatechnology.at laufen sehr viele Projekte in verschiedenen docker containern, hier ein kurzer Auszug:

Terminal-Fenster
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STAT
12246a07 dokku/skinavie:latest "/start web" 3 days ago Up 3 days
f4b9c5ab dokku/stempelheft:latest "/exec rails console" 3 days ago Up 3 days
9016e13a svendowideit/ambassador "/bin/run.sh" 3 weeks ago Up 3 weeks
d16eb536 dokku/stempelheft:latest "/start web" 3 weeks ago Up 3 weeks
a3fd20b7 dokku/fago:latest "/start web" 4 weeks ago Up 4 weeks
9f5030a8 pgrouting/pgrouting:latest "docker-entrypoint..." 6 weeks ago Up 6 weeks
82f8e908 postgres:13.2 "docker-entrypoint..." 2 months ago Up 2 months
6bd4b634 dokku/beerpong_reloaded:latest "/start web" 3 months ago Up 3 months
1732d49a dokku/soundlink:latest "/start web" 3 months ago Up 3 months
55af4cf7 dokku/aupair_app:latest "/start web" 3 months ago Up 3 months
b0a10815 dokku/knotenpunkt:latest "/start web" 4 months ago Up 4 months

Mit dem Kommandozeilenbefehl docker run kann man einen Container starten:

Terminal-Fenster
docker run pandoc/latex

Dieser Container läuft kurz und stoppt von selbst wieder. Er hinterlässt einen abgeschaltenen Container. Besser wäre:

Terminal-Fenster
docker run --rm pandoc/latex

Tut immer noch nicht sinnvolles, aber hinterlässt auch keine zusätzlichen Daten.

Ein Docker Container hat sein eigenes Dateisystem und erst mal keine Verbindung zum Host-Dateisystem.

Wenn der Container während der Laufzeit etwas ins eigene Dateisystem schreibt ist das im Host-Dateisystem nicht vorhanden.

Terminal-Fenster
$ docker run --rm -ti ubuntu
root@87712b76b86a:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@87712b76b86a:/# touch tmp/brigitte_war_hier
root@87712b76b86a:/# ls tmp/
brigitte_war_hier

Wird derselbe Container später nochmal gestartet ist das Dateisystem wieder im Anfangszustand.

Terminal-Fenster
$ docker run -ti ubuntu
root@9f80c9069e71:/# ls tmp/brigitte_war_hier
ls: cannot access 'tmp/brigitte_war_hier': No such file or directory

Will man etwas dauerhaft im Host Dateisystem speichern braucht man dafür ein Volume.

Ein Volume ist ein Ornder der mit dem “echten” Dateisystem verbunden ist.

Beim Start eines Containers kann man angeben, welche Pfad im echten Dateisystem mit dem Volume im container verbunden werden soll:

Terminal-Fenster
docker run --rm --volume /Users/bjelline/devel/7:/data pandoc/latex

Hier wird der Ordner /Users/bjelline/devel/7 im Host Dateisystem verbunden mit dem Ornder /data im Container.

Noch besser:

Terminal-Fenster
docker run --rm --volume /Users/bjelline/devel/7:/data pandoc/latex README.md -o outfile.pdf

Das pandoc/latex image startet automatisch den pandoc Befehl. Der String README.md -o outfile.pdf wird an diesen Befehl als parameter übergeben. pandoc versucht dann eine Datei data/REAMDE.md einzulesen, die Daten zu konvertieren, und als Datei data/outfile.pdf wieder zu speichern.

Da das Verzeichnis data/ im Container auf den Ordner 7 im Host-Dateisystem gemappt war wird die neue erzeugte Datei dort hin geschrieben.

So kann man also pandoc im Container verwenden ohne es im Host-Betriebsystem zu installieren.

Wie baue ich selbst ein Image? Mit einem Dockerfile. (Ja dieser Dateiname hat keine Endung.)

Das Dockerfile legt fest wie das Image gebaut wird. Wenn das Image fertig ist braucht man das Dockerfile nicht mehr.

Ein Beispiel: ich will ein Image das das Kommandozeilen-Programm wget enthält.

Terminal-Fenster
FROM ubuntu
RUN apt-get update && apt-get install -y wget
WORKDIR /data
ENTRYPOINT ["/usr/bin/wget"]

Wenn ich nun mit dem Befehl docker build . -t mein_wget ein Image bauen lasse werden folgende Schritte ausgeführt:

  1. als Basis-Image wird ubuntu verwendet (default zu: ubuntu:latest)
    • ein Container mit diesem Basis-image wird gestartet,
    • in diesem Container werden die weiteren Schritte ausgeführt.
  2. mit dem Ubuntu-Befehl mit apt-get update werden die neuesten Daten für das Paketsystem apt geladen
  3. mit dem Befehl apt-get install wget wird ein Softwarepaket mit Namen wget installiert.
  4. mit dem Befehl WORKDIR /data wird ein Ordner angelegt und in den Ordner hinein gewechselt.
  5. als Entrypoint wird /usr/bin/wget festgelegt - das tut aber noch nichts.

Das Ergebnis ist ein neues image mit einer eindeutigen id und dem von mir vergebenen Namen:

Terminal-Fenster
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mein_wget latest 4c4d9f9444d9 2 minutes ago 116MB

Mit dem Befehl docker run --rm mein_wget http://web-development.github.io starte ich nun mein image als container. Dabei passiert folgendes:

  1. aus dem Image wird ein laufender Container
  2. aus meiner Eingabe wird der Teil nach dem image-Namen genommen: http://web-development.github.io
  3. der Befehl der als “Entrypoint” eingetragen war wird aufgerufen
    • der Befehl war /usr/bin/wget
    • als Argument erhält er http://web-development.github.io
    • der Befehl läuft durch und schreibt eventuell output in den aktuellen Ornder (WORKDIR) data
  4. der Container wird gestoppt.

Der Output des Befehles verschwindet mit dem Container. Derselbe Befehl nochmal mit einem Volume:

docker run --rm --volume $(pwd):/data mein_wget http://web-development.github.io

Nun wird der Output von wget im aktuellen Ordner des Host-Betriebssystems gespeichert.

Tipp: wget hat die Optionen -r für rekursives Abrufen aller Links in der Webseite und --level=2 für die Angabe wie viele Schritte weit die Rekursion gehen soll.

  • FROM in der docker dokumentation
  • RUN in der docker dokumentation
  • WORKDIR in der docker dokumentation
  • ENTRYPOINT in der docker dokumentation