Docker
Willemers Informatik-Ecke
Docker ist ein Tool zur Bereitstellung von Anwendungen, die aus mehreren Paketen besteht.

Typisches Beispiel: Backend-Anwendungen im Web

Eine solche Anwendung läuft in einem Container. Auf einem Host können mehrere Container laufen.

Installation

Die Docker-Software wird im Repository von Debian, Ubuntu und Linux Mint im Paket docker.io zur Verfügung gestellt und kann entsprechend direkt von dort installiert werden.
# apt update
# apt install docker.io
Anmerkung: Es gibt auch ein Paket docker. Das ist aber eine komplett andere Software.

Docker-Images

Der Befehl docker pull lädt ein Image aus dem Docker-Hub herunter. Auf den Docker-Hub werden wir weiter unten noch eingehen. Das folgende Beispiel holt sich das aktuellste Ubuntu-Image.
# docker pull ubuntu:latest
latest: Pulling from library/ubuntu
a48641193673: Pull complete 
Digest: sha256:6042500cf4b44023ea1894effe7890666b0c5c7871ed83a97c36c76ae560bb9b
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
Der Befehl docker images zeigt alle auf dem Host verfügbaren Images. Nach dem obigen Pull-Befehl steht natürlich das Ubuntu-Image zur Verfügung.
# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       latest    174c8c134b2a   2 weeks ago   77.9MB
Interessant ist die Größe! Nur knapp 80 MB. Das liegt daran, dass nur das minimale System geladen ist (kein Office) und der Kernel des lokalen Linux verwendet wird.

Mit dem Befehl docker run kann ein Container auf der Basis des Images ubuntu gestartet werden. Hier wird eine Bash gestartet.

# docker run -it ubuntu /bin/bash
root@5aee8b6ff6b3:/# 
Sollte das Ubuntu-Image noch nicht geladen sein, wird es durch diesen Befehl auch heruntergeladen.

Mit der Bash kann man nun das Image beispielsweise durch apt-Aufrufe erweitern. Eine Web-Anwendung kann also direkt im Image angelegt werden und als Container gestartet werden.

Docker-Hub

Das Basis-Image ubuntu, das mit docker pull geladen wurde, kommt aus dem Docker-Hub. Im Docker-Hub werden viele Images für verschiedenste Zwecke angeboten, auf deren Basis eigene Images erstellt werden kann.

https://hub.docker.com/search?type=image

Eigener Container für Node.js

Node.js ist eine Laufzeitumgebung, mit der Webanwendungen in JavaScript erstellt werden können.

Gerade Webanwendungen bestehen aus mehreren Komponenten, die in Containern zusammengefasst werden können, um damit Versionskonflikte auszuschließen.

Direkterzeugung eines Images

Als Basis des Node.js-Containers wird ein Ubuntu-Image vom Docker-Hub geladen. Darin werden die Node.js-Komponenten installiert und schließlich die eigene Anwendung angelegt.

Basis: Laden des Ubuntu-Images

# docker pull ubuntu:latest
Hier dem Doppelpunkt kann explizit eine Version angegeben werden. Die Angabe latest verwendet die neueste verfügbare Version.

Um das Image zu ändern, wird mit docker run eine Shell aufgerufen:

# docker run -it ubuntu /bin/bash
root@cb977a2459b5:/# 
Die Shell läuft innerhalb des Ubuntu-Containers. Von der Shell aus kann im Docker eine Node.js-Umgebung installiert werden:
# apt update
# apt install nodejs npm vim
Die eigene Anwendung muss man natürlich selbst erstellen. Als sehr einfaches Beispiel wird ein kleines Testprogramm index.js im Verzeichnis /var/www des Containers angelegt:
# mkdir /var/www
# vi /var/www/index.js
Das kleine Beispielprogramm liefert lediglich ein Hallo an den Browser, der den Server abfragt.
var http = require('http');
http.createServer(function(req, res) {
        res.end('Hallo');
}).listen(8080);
Damit ist alles vorbereitet. Das Verlassen des Containers erfolgt über die Tastenkombination [Strg}+[P] [Strg]+[Strg]+[Q] oder dem Befehl exit.

Das veränderte Image soll nun unter einem neuen Namen gespeichert werden.

Mit dem Befehl docker run kann der Container gestartet werden.
# docker run -d -p 8080:8080 meinnodejs:0.1 nodejs /var/www/index.js
Zum Testen wird Firefox mit der URL http://localhost:8080 gestartet.

Installation per Dockerfile

Anstatt die Installation innerhalb des Containers Schritt für Schritt zu vollziehen, kann auch eine Batch-Datei namens Dockerfile verwendet werden. Dafür nehmen wir als Beispiel das gleiche Node.js-Programm index.js wie bei der Direkterzeugung.
var http = require('http');
http.createServer(function(req, res) {
        res.end('Hallo');
}).listen(8080);
Es wird außerdem die Datei Dockerfile benötigt, in der steht, auf welchem Basis-Image aufgesetzt wird, was gestartet und was kopiert werden muss, um das fertige Image zu erzeugen.
# Der Basis-Container, auf dem der Container aufsetzen soll:
FROM ubuntu
# Starte alle Befehle, die in dem neuen Container ablaufen sollen:
RUN apt update && apt install -y nodejs npm
RUN mkdir /var/www
# Kopiere die lokal erstellte Datei nach /var/www in den Container!:
COPY index.js /var/www
Die Erzeugung des Images wird mit docker build gestartet. Dazu wird, wenn vorhanden, die Datei Dockerfile verwendet.
# docker build -t meinnodejs .
In der Liste der Images taucht nun das eigene Image neben ubuntu auf.
# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
meinnodejs   latest    e2c096a1936c   4 minutes ago   978MB
ubuntu       latest    08d22c0ceb15   2 weeks ago     77.8MB
Das Starten des Images funktioniert wie gehabt. Getestet wird wieder über Firefox mit der URL localhost:8080.
# docker run -d -p 8080:8080 meinnodejs:latest nodejs /var/www/index.js

Eigener PHP Docker-Container

Eine andere Programmierumgebung für Web-Anwendungen ist PHP. Auch dafür soll ein Docker-Container erstellt werden. Allerdings bietet hier Docker-Hub ein gut angepasstes Basis-Image an.

Als erstes legen wir ein Verzeichnis an, in dem wir eine PHP-Datei erstellen.

$ mkdir docker-lamp
$ cd docker-lamp/
$ vi index.php
Die PHP-Datei index.php enthält verschiedene PHP-Anweisungen und wird beim Aufruf verschiedene Parameter des Servers anzeigen.
<!DOCTYPE html>
<html>
<head>
  <title>Hallo Docker</title>
</head>
<body>
<h1>Mein erster Container</h1>
<?php
  $load = sys_getloadavg();
?>
  Serverzeit: <?php echo date("c"); ?><br />
  Serverauslastung (load): <?php echo $load[0]; ?>
</body>
</html>
Nun wird die Datei Dockerfile erzeugt, die angibt, dass das Image php die Basis bildet und dass die Datei index.php in das Image kopiert werden soll.
FROM php:7-apache
ENV TZ="Europe/Berlin"
COPY index.php /var/www/html
Durch den Befehl docker build werden folgendes passieren: Im nächsten Schritt wird mit dem Befehl docker build ein neuer Container erstellt. {\small
# docker build -t mein-erster-container .
            Install the buildx component to build images with BuildKit:
            https://docs.docker.com/go/buildx/

Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM php:7-apache
7-apache: Pulling from library/php
a603fa5e3b41: Pull complete 
c428f1a49423: Pull complete 
d2c43c5efbc8: Pull complete 
...
ab590b48ea47: Pull complete 
80692ae2d067: Pull complete 
05e465aaa99a: Pull complete 
Digest: sha256:c9d7e608f73832673479770d66aacc8100011ec751d1905ff63fae3fe2e0ca6d
Status: Downloaded newer image for php:7-apache
 ---> 20a3732f422b
Step 2/3 : ENV TZ="Europe/Berlin"
 ---> Running in ac5e1f656ce0
Removing intermediate container ac5e1f656ce0
 ---> 4abad7f79cee
Step 3/3 : COPY index.php /var/www/html
 ---> 818226e52869
Successfully built 818226e52869
Successfully tagged mein-erster-container:latest
} Das erstellte Image kann nun gestartet werden. Der Port wird dabei auf 8080 umgeleitet.
# docker run -p 8080:80 mein-erster-container
Auf dem lokalen Host wird Firefox mit der URL http://localhost:8080 aufgerufen. Es erscheint folgendes Bild:

Quelle: https://goneuland.de/docker-einfache-beispiel-container

Dockerfile für Django

Django ist ein Framework zur Erstellung von Web-Anwendungen in Python. Die Erstellung des Django-Projekts ist auf der Seite über Django genauer beschrieben. Hier soll es in erster Linie um die Erstellung des Dockerfile und der Erzeugung des Images gehen.

FROM python:3.9
#Install Django and other required packages
RUN pip install django
# Copy the Django project files into the image
COPY . /app
# Set the working directory
WORKDIR /app
# Start the Django development server
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Docker-Hub empfielt zur Zeit (Januar 2024) explizit nicht die Verwendung des Basis-Images django. Stattdessen wird das Image python verwendet und mithilfe des Installationsprogrammes pip Django automatisch nachinstalliert.

Quelle: https://hackernoon.com/de/wie-man-Django-Anwendungen-dockerisiert-und-bereitstellt

Server-Installation aus Docker-Hub

Docker-Hub bietet auch vollständige Server-Images, die in einem Docker quasi out of the box lauffähig sind. Als Beispiel soll hier die Installation eines GitLab-Servers vorgestellt und diskutiert werden.

Tatsächlich lässt sich das Image einer Community-Edition von GitLab direkt als Image mit docker pull herunterladen.

# docker pull gitlab/gitlab-ce
Der Start des Dockers dauert eine Weile.
# docker run -p 8081:80 gitlab/gitlab-ce
Im Browser wird \url{localhost:8081} aufgerufen. Nach einiger Zeit erscheint die Anmeldemaske.

Hier unterscheidet sich die native Einrichtung erheblich. Denn dort wird beim ersten Start das Passwort des Administrators gesetzt. Das ist in der Docker-Variante aber bereits geschehen. Nun muss ermittelt werden, welches Passwort vergeben wurde. Dazu wird die Konfigurationsdatei durchsucht.

Fazit:

Export und Import von Docker-Containern

Für den Export eines Containers muss dessen Name bekannt sein. Die Ausgabe des Befehls docker container ls -a wurde hier etwas verkürzt.
# docker container ls -a
CONTAINER ID IMAGE                 COMMAND CREATED STATUS PORTS NAMES
b92715d33551 mein-erster-container "docker 15 hour Exited       zen_khayyam
3d504a19e6ec mein-erster-container "docker 15 hour Exited       sad_poitras
b5b6e0f48a2a mein-erster-container "docker 15 hour Exited       elated_bartik
ba672f4d5ef7 mein-erster-container "docker 15 hour Exited       exciting_moser
5aee8b6ff6b3 ubuntu                "/bin/b 5 days  Exited       focused_johnson
e7f4f23a421f ubuntu                "-it /b 5 days  Created      priceless_mendel
Über diesem Namen wird exportiert. Das Ergebnis wird mit gzip gepackt in einer Datei abgelegt.
# docker export sad_poitras | gzip > sad_poitras.gz
Die erzeugte Datei sad_poitras.gz kann nun auf eine andere Maschine (bspw. per scp) übertragen werden, um sie dort wieder zu importieren.
# zcat sad_poitras.gz | docker import - sad_poitras
sha256:6bc7c3db6c08a742f109b1493d825bc584ba6d77da215c79178b0bb0c21fd1aa
Man kann den Container betrachten:
# docker container ls -a
CONTAINER ID   IMAGE         COMMAND       CREATED          STATUS                      PORTS     NAMES
90079c31e5e4   sad_poitras   "/bin/bash"   23 seconds ago   Exited (0) 11 seconds ago             lucid_perlman
# docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
sad_poitras   latest    6bc7c3db6c08   About a minute ago   446MB
Und natürlich auch starten:
# docker run -i -t sad_poitras /bin/bash
root@90079c31e5e4:/# 

Docker-Befehle

Die Kommandos von docker kann man sich mit dem folgenden Befehl anzeigen lassen.
$ docker help | more

Links