2. Docker

2.1. Einleitung

Im ersten Versuch des DVA-Praktikums haben wir uns mit dem Thema Docker Containervisualisierung auseinandergesetzt. Hierbei werden zuerst die grundlegenden Konzepte von Docker betrachtet, sowie Technologie und Standardbefehle. Anschließend wird die Dockeranwendung anhand eines Beispiels vorgestellt.

Denn im heutigen technischen Umfeld wird Docker eine immer häufiger genutzte Alternative zu einer virtuellen Maschine. Weshalb im folgenden Abschnitt zuerst der Unterschied zwischen Docker und einer virtuellen Maschine genauer beleuchtet wird.

2.2. Vergleich Docker vs. Virtuelle Maschinen

In diesem Kapitel wird Docker allgemein mit virtuellen Maschinen verglichen.

Auf der folgenden Abb. 2.2.1 sieht man bereits den unterschiedlichen Aufbau von Docker und virtuellen Maschinen. Hierbei wird ersichtlich, dass Docker eine Abstraktion hat.

Hierbei können mehrere Container auf demselben Rechner ausgeführt werden und dabei gleichzeitig das Host-Betriebssystem nutzen, dies spart Ressourcen und ermöglicht ein schnelles und einfaches Deployment. Gleichzeitig teilen sich jedoch auch alle Container das Betriebssystem, was in gewisser Hinsicht natürlich Sicherheitsrisiken mit sich bringt.

Wohingegen virtuelle Maschinen abgekapselt sind und jeweils eine vollständige Kopie eines Betriebssystems, der Anwendung und aller nötigen Bibliotheken enthalten. Dies spricht natürlich für eine Gesamtisolation und höhere Sicherheit, dadurch werden jedoch mehr Ressourcen benötigt im Betrieb wie auch in der Speicherung, was allgemein auch zu längeren Startzeiten führt. Zudem enthält das Aufsetzen einer virtuellen Maschine auch immer das Aufsetzen eines gesamten Betriebssystems, was das Management und die Administration komplexer macht.

[docker.com] [aws.com] [ibm.com] [atlassion.com] [ionos.de]

_images/1_1_Docker.png

Abb. 2.2.1 Docker vs. virtual Maschine [docker.com]

Im folgenden nochmal zusammengefasst Vor- und Nachteile von Docker sowie virtuellen Maschinen.

Tab. 2.2.1 Vor- und Nachteile von Docker und virtuellen Maschinen

Technologie

Vorteile

Nachteile

Docker

Plattformunabhängigkeit, effiziente Ressourcennutzung, einfache Skalierbarkeit, schnelles Deployment

Sicherheitsrisiken, Verwaltungskomplexität

Virtuelle Maschinen

Volle Isolation, hohe Sicherheit, Unterstützung für verschiedene Betriebssysteme, bewährte Technologie

Höherer Ressourcenverbrauch, längere Startzeiten, Overhead durch Virtualisierung, komplexeres Management

2.3. Grundlagen Docker

Docker ist eine Open-Source-Plattform zur Container-Virtualisierung von Anwendungen. Im Gegensatz zur klassischen Virtualisierung mit virtuellen Maschinen (VMs) setzt Docker auf leichtgewichtige Container, die Anwendungen inklusive ihrer Abhängigkeiten isoliert ausführen. Dies ermöglicht eine plattformunabhängige Bereitstellung und Skalierung von Softwarelösungen.

2.3.1. Grundlagen der Architektur

Docker basiert auf einem Client-Server-Modell mit den folgenden Hauptkomponenten:

  • Docker-Engine: Sie ist für das Erstellen und Verwalten von Containern verantwortlich und besteht aus zwei zentralen Teilen:

    • Docker-Daemon (dockerd): Ein Hintergrunddienst, der Container verwaltet und auf API-Anfragen reagiert.

    • Docker-Client (docker): Ein Kommandozeilen-Tool zur Steuerung der Docker-Engine, das Befehle zum Erstellen, Starten und Verwalten von Containern bereitstellt.

  • Docker-Image: Ein Image ist eine unveränderliche Vorlage, die alles enthält, um eine Anwendung auszuführen. Es basiert auf mehreren Schichten (Layers), die sich effizient verwalten und wiederverwenden lassen.

  • Docker-Container: Ein Container ist eine Instanz eines Images. Er läuft isoliert vom Host-System und garantiert, dass Anwendungen überall gleich funktionieren.

2.3.2. Dockerfile + Image-Erstellung

Ein Dockerfile definiert, wie ein Image aufgebaut wird. Es enthält Anweisungen, die z. B. Basis-Images festlegen, Softwarepakete installieren und Konfigurationsparameter setzen.

Beispiel:

# Basis-Image
FROM node:18.16.0

# Arbeitsverzeichnis festlegen
WORKDIR /app

# Abhängigkeiten kopieren und installieren
COPY package*.json ./
RUN npm install --only=production

# Anwendung starten
CMD ["npm", "start"]

Durch den Befehl docker build -t mein-image . wird daraus ein lauffähiges Docker-Image erstellt.

2.3.3. Datenverwaltung mit Volumes

Da Container flüchtig sind, werden persistente Daten über Volumes gespeichert. Volumes sind unabhängig vom Lebenszyklus eines Containers und ermöglichen den Datenaustausch zwischen Host und Containern. Sie lassen sich mit docker volume create anlegen und in einem Container mit -v einbinden.

2.3.4. Netzwerkverwaltung

Docker bietet mehrere Netzwerkmodi:

  • Bridge (Standard): Container kommunizieren untereinander, sind aber vom Host isoliert.

  • Host: Der Container nutzt direkt das Netzwerk des Hosts.

  • Overlay: Für verteilte Anwendungen über mehrere Hosts hinweg.

2.3.5. Docker Compose

Für komplexe Anwendungen mit mehreren Containern bietet Docker Compose eine einfache Lösung. In einer docker-compose.yml-Datei lassen sich mehrere Services deklarieren:

version: '3'
services:
  web:
    image: nginx
    ports:
      - "8080:80"
  database:
    image: postgres
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password

Mit docker-compose up -d startet Docker die definierten Services automatisch.

2.4. Versuchsdurchführung

Ziel des Versuchs war es, eine einfache Webanwendung mit Frontend und Backend mithilfe von Docker umzusetzen. Dabei sollte das Backend ein statisches Bild bereitstellen, das vom Frontend abgerufen und angezeigt wird. Der Fokus lag auf der praktischen Nutzung von Docker zur Containerisierung, der Vernetzung mehrerer Dienste mit docker-compose, sowie dem Aufbau eines einfachen Microservice-Setups mit modernen Technologien wie Rust.

Das Projekt wurde in zwei Container aufgeteilt:

  • ein statisches Frontend auf Basis von NGINX

  • ein Rust-basiertes Backend, das mit dem Web-Framework Actix-Web entwickelt wurde.

Beide Komponenten sind über ein gemeinsames Docker-Netzwerk verbunden und werden mithilfe von docker-compose verbunden.

Im Backend verarbeitet ein Rust-Webserver Anfragen an den Pfad und liefert eine Bilddatei aus dem Verzeichnis public zurück. Der entsprechende Code-Ausschnitt zeigt, wie die Bilddatei geladen und mit einem benutzerdefinierten HTTP-Header versehen wird:

async fn get_picture(req: HttpRequest) -> Result<HttpResponse> {
    let base_path = env::var("BASE_PATH").unwrap_or_else(|_| ".".to_string());
    let path: PathBuf = Path::new(&base_path).join("public/picture.png");
    let file = NamedFile::open(path)?
        .use_last_modified(true)
        .customize()
        .insert_header((header::HeaderName::from_static("x-image-served"), "true"));

    Ok(file.respond_to(&req).map_into_boxed_body())
}

Der Server wird auf Port 8080 bereitgestellt und ist CORS-fähig, was die Kommunikation mit dem Frontend erleichtert:

HttpServer::new(|| {
    let cors = Cors::default()
        .allow_any_origin()
        .allow_any_method()
        .allow_any_header();
    App::new()
        .wrap(cors)
        .route("/bild", web::get().to(get_picture))
})
.bind("0.0.0.0:8080")?
.run()
.await

Das Frontend besteht aus einer simplen HTML-Datei, die das Bild über einen HTTP-Request vom Backend lädt:

<img style="width: 500px;" src="http://localhost:8080/bild"></img>

Das Projekt besteht aus zwei voneinander getrennten Komponenten: einem Backend, das in Rust geschrieben ist, und einem Frontend, das über einen einfachen NGINX-Webserver bereitgestellt wird. Beide Services – das Backend und das Frontend – sind in der docker-compose.yaml-Datei definiert. Diese Datei übernimmt mehrere Aufgaben:

  • Aufbau eines gemeinsamen Netzwerks für die Kommunikation zwischen den Containern

  • Sicherstellen, dass das Frontend erst startet, wenn das Backend verfügbar ist (depends_on)

  • Bereitstellung von Ports für den Zugriff von außen

Datei docker-compose.yaml:

version: '3.8'

services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    networks:
      - app-network
    ports:
      - "8080:8080"

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    networks:
      - app-network
    ports:
      - "80:80"
    depends_on:
      - backend

networks:
  app-network:
    driver: bridge

Erklärung der wichtigsten Abschnitte:

  • build.context: Gibt an, wo sich der Quellcode und das Dockerfile befinden.

  • networks: Beide Container befinden sich im selben virtuellen Netzwerk (app-network), damit sie sich gegenseitig erreichen können.

  • depends_on: Der Frontend-Container wartet, bis der Backend-Container gestartet ist.

  • ports: Verbindet den internen Port des Containers mit einem Port auf dem Hostsystem (z. B. 8080:8080).

Das Backend ist eine Rust-Anwendung, welche im Release-Modus kompiliert wird. Das Dockerfile des Backend:

# Build the rust application
FROM rust:latest AS builder

WORKDIR /usr/src/app
COPY . .

RUN cargo build --release

# Host the application
FROM debian:bookworm-slim AS hoster

WORKDIR /usr/src/app
COPY --from=builder /usr/src/app/target/release/backend /usr/src/app/
COPY /public /usr/src/app/public

ENV BASE_PATH="/usr/src/app"

EXPOSE 8080
CMD ["./backend"]

Das Frontend wird über einen statischen Webserver zur Verfügung gestellt. Hierzu kommt das nginx-Image zum Einsatz Das Dockerfile des Frontend:

FROM nginx:latest

COPY . /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

2.5. Zusammenfassung

Der Versuch zeigt, wie sich mit Docker und modernen Webtechnologien eine einfache, aber klar strukturierte Microservice-Architektur aufbauen lässt. Die Trennung von Frontend und Backend in eigene Container fördert die Modularität und Wartbarkeit. Besonders hervorzuheben ist die flexible Konfiguration des Rust-basierten Servers und die einfache Kommunikation über HTTP – realisiert mit minimalem Code und effizientem Ressourcenverbrauch.

2.6. Literaturangaben

[docker.com] (1,2)

Docker - Use containers to build, share and run your applications https://www.docker.com/resources/what-container/ (besucht am 31.03.2025)

[atlassion.com]

Atlassian - Container vs. virtuelle Computer https://www.atlassian.com/de/microservices/cloud-computing/containers-vs-vms (besucht am 31.03.2025)

[aws.com]

AWS - Was ist der Unterschied zwischen Docker und einer VM https://aws.amazon.com/de/compare/the-difference-between-docker-vm/ (besucht am 31.05.2025)

[ibm.com]

IBM - Was ist eine virtuelle Maschine https://www.ibm.com/de-de/think/topics/virtual-machines (besucht am 31.05.2025)