In den letzten Jahren hat sich Docker zum quasi Standard für Microserviceumgebungen herangemausert. Es ermöglicht jedem Service in einer eigenen Umgebung zu laufen ohne für jeden Service ein komplettes Betriebssystem installieren zu müssen. Warum ist Docker so erfolgreich? Docker Container sind besser als klassische Virtualisierungen weil sie …
- deutlich schlanker sind
- nicht zwangsläufig eigene IP-Adresse im Netzwerk brauchen
- von Haus aus IaC (Infrastrcuture As Code) bereitstellen
- schnell redeployed werden können
- mit Kubernetes zusammen riesige, skalierende Servicenetzwerke anbieten können
In diesem Tutorial lernst du was Docker ist und wie du dein erstes Docker Image erzeugst und ausführst.
Was ist Docker
Docker ist eine Technologie zur Virtualisierung von Services. Bei klassischer Virtualisierung wird eine ganze Linux bzw. Windows Installation bereitgestellt. Das hat zur Folge, dass für jede Instanz oft mehrere Gigabyte an Speicher benötigt werden und die Installation entsprechend lange dauert. Docker geht einen anderen Weg!
Container System
Um einen Service auf Docker laufen zu lassen brauchst du zwei Dinge: - ein Hostsystem
- ein Docker Image
Das Hostsystem kannst du auf allen gängigen Betriebssystemen installieren (Klick). Die meisten Docker Container benötigen eine Linux Umgebung. Deswegen solltest du bei der Windows und der Mac OS Installation darauf achten Linux Container Ausführung zu aktivieren. Das Docker Image beschreibt, wie sich der Container beim Zeitpunkt des Hochfahrens verhalten soll. Du kannst entweder ein fertiges Image aus dem Internet laden oder dein eigenes verwenden. Die meisten kostenlosen Images findest du übrigens auf Docker Hub. In diesem Beitrag lernst du zusätzlich wie du dein erstes eigenes Docker Image erzeugst.
Geteiltes Betriebssystem
Auf dem Dockerhostsystem werden die Betriebssystemdateien allen darauf installierten Docker Containern als geteilte Ressourcen bereitgestellt. Das hat den Vorteil, dass diese nur einmal vorhanden sein müssen. Anschließend wird - ähnlich wie bei klassischen Virtualisierungshostsystemen - den installierten Services auf den einzelnen Containern vorgegaukelt der einzige installierte Service zu sein.
Skizze des Dockerprinzips von App bis Infrastruktur
Port Management
Jeder Service Container bietet seinen Service meist auf einem oder mehreren Ports an. Das Dockerhostsystem hat jetzt die Möglichkeit diese Ports nach außen erreichbar zu machen. Für andere Computer im Netzwerk sieht es dann so aus, als würden diese Services auf dem Dockerhostsystem laufen (was sie praktisch ja auch tun). Damit es keine Portüberschneidungen gibt, kann das Dockerhostsystem selbst entscheiden auf welchen Port der jeweilige Service des Containers angeboten wird.
Persistente Speicher (Volumes)
Sobald ein Docker Container neu startet wird der Container mithilfe des Images von Grund auf neu installiert. Deswegen sind gespeicherte Dateien immer nur temporär. Wenn du persistente Daten verwenden möchtest, musst du das explizit angeben. Der gängigste Weg ist ein Volume bereitzustellen. Dieses Volume muss beim Start des Containers angegeben werden. Dafür kannst du zum Beispiel einen Ordner in deinem Betriebssystem nehmen. Volumes können übrigens auch zwischen mehreren Containern geteilt werden. Dadurch können die Container Dateien austauschen.
Wie du ein Docker Image erstellst
Ist Docker installiert, geht es ans Eingemachte. Prinzipiell ist es egal, von welchem System du deine Docker Container Images baust. Theoretisch sind die Container auf allen anderen Systemen lauffähig. Üblicherweise werden Linux Container verwendet. Für manche Anwendungen sind aber auch Windows Container sinnvoll. Etwa bei MS SQL Datenbankcontainern. Um ein Docker Image zu erstellen, benötigst du in jedem Fall eine Dockerfile. In dieser Datei wird das Verhalten des Containers definiert. Der Inhalt der Dockerfile listet die Befehle in Ausführreihenfolge auf, die zum Installieren des Containers benötigt werden. Hier die möglichen Befehle.
Befehl | Beschreibung |
---|---|
FROM | Spezifiziert das Basisimage (wie Vererbung). Dieses MUSS vorhanden sein |
LABEL | Zusätzliche Metadaten, etwa für Infos über die Maintainer |
ENV | setzt eine persistente Umgebungsvariable |
RUN | führt ein (Shell-) Kommando aus (und erstellt ein Image Layer)… Du kannst es benutzen, um Pakete in deinen Container zu installieren |
COPY | Kopiert Dateien oder Ordner von deinem Buildsystem in das Image |
ADD | Funktioniert ähnlich wie COPY. Entpackt allerdings .tar Dateien und lädt Links herunter |
CMD | Das Hauptkommando mit Argumenten für diesen Container. Es darf jedoch nur einen CMD Befehl pro Dockerfile geben. Parameter können übrigens überschrieben werden. |
WORKDIR | Setzt das Arbeitsverzeichnis für die folgenden Befehle und ist daher vergleichbar mit dem cd Kommando in Linux & Windows CLI’s |
ARG | Definiert eine Variable, welche du beim Bauen mitgeben kannst |
ENTRYPOINT | Gibt Kommandos und Argumente an die beim Ausführen mitgegeben werden können. Argumente sind dabei persistent. |
EXPOSE | Gibt einen Port frei |
VOLUME | Erstellt einen Mountpunkt um darüber auf persistente Daten zugreifen zu können |
Container
Neue Docker Container müssen auf anderen, bereits existierenden Container Images aufbauen und ergänzen diese um zusätzliche Software. Folglich musst du in der Dockerfile mit dem FROM Befehl ein Basisimage angeben. Hier ein paar der populärsten Container Images die du verwenden kannst:
container | Beschreibung |
---|---|
scratch | Kleinstmöglichstes Image |
Alpine | Alpine Linux Distribution |
busybox | Busybox Linux Distribution |
Centos | Centos Linux Distribution |
Debian | Debian Linux Distribution |
Ubuntu | Ubuntu Linux Distribution |
Postgres | Postgres Datenbank (Objekt-relationales Datenbankensystem) |
Redis | Redis Datenbank (key-value Speicher) |
Node | Node.js Umgebung (JavaScript basierte Plattform für serverseitige- und Netzwerkapplikationen) |
Nginx | NGINX Service (Webserver) |
Mysql | mysql Datenbank (relationales Datenbanksystem) |
Mongo | MongoDB Datenbank (Binärspeicher mit Funktionen für high availablity und hoher Skalierbarkeit) |
Httpd | Apache Service (Webserver) |
Mariadb | MariaDB Datenbank (relationales Datenbanksystem) |
Golang | Golang Umgebung (Go ist eine beliebte und schnelle Programmiersprache für Serverseitige Anwendungen) |
Wordpress | Wordpress System (Content Management System für Blogs und ähnlichen Webseiten) |
Weitere findest du hier: https://hub.docker.com/search?q=&type=image
Diese vorgefertigten Images bieten oft einen schnellen Start für den eigenen Container. Viele Images werden auch mit unterschiedlichen Distributionen angeboten. So basiert das normale Pythonimage auf Debian. Es gibt aber auch die deutlich kleinere auf Alpine basierende Version (nur 5,6 MB anstatt 114 MB). Diese werden mithilfe von Tags gespeichert. Du wählst sie mit dem Doppelpunkt nach dem Imagenamen.
Dockerfile Beispiel
Erstelle im aktuellen Verzeichnis eine Datei app.py:
print(Hallo Welt!)
und eine Datei dockerfile:
FROM python:3.9-alpine
COPY app.py /app/app.py
CMD python /app/app.py
Baue das Image mit docker build.
docker build . -t hallowelt
Und führe es mit docker run aus.
docker run hallowelt
Hallo Welt!
Was ist eine Docker Container Registry
Dieses Image hast du nur auf deinem Rechner gebaut. Um es anderen Entwicklern bereitzustellen, kannst du es auf Docker Hub oder einer anderen Registry hochladen. Eine Registry ist also ein Service der Docker Images speichert. Docker Hub ist für öffentliche Images gratis. Hier findest du eine Anleitung wie es verwendest. Das Beispiel aus diesem Beitrag habe ich hier hochgeladen. Du kannst es mit folgendem Befehl herunterladen und Ausführen:
docker run quisl/hallowelt:latest
Übrigens: Ich habe hier im Beispiel den latest Tag verwendet. Dies ist eigentlich kein richtiger Tag. Stattdessen nimmt Docker bei latest automatisch die neuste Version des Images.
Konnte ich helfen? Ich freue mich über einen Drink!
💙