Docker ==================================== 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. Vergleich Docker vs. Virtuelle Maschinen ---------------------------------------- .. index:: Docker , Virtuelle Maschine , Vergleich In diesem Kapitel wird Docker allgemein mit virtuellen Maschinen verglichen. Auf der folgenden :numref:`dockerVM` 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]_ .. _dockerVM: .. figure:: img/1_1_Docker.png :align: center Docker vs. virtual Maschine [docker.com]_ Im folgenden nochmal zusammengefasst Vor- und Nachteile von Docker sowie virtuellen Maschinen. .. list-table:: *Vor- und Nachteile von Docker und virtuellen Maschinen* :widths: 20 40 40 :header-rows: 1 * - 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 Grundlagen Docker ------------------- .. index:: Docker Grundlagen 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. 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. 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: .. code-block:: docker # 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. 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. 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. 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: .. code-block:: yaml 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. 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: .. code-block:: rust async fn get_picture(req: HttpRequest) -> Result { 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: .. code-block:: rust 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: .. code-block:: html 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: .. code-block:: 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: .. code-block:: docker # 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: .. code-block:: docker FROM nginx:latest COPY . /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] 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. Literaturangaben ------------------- .. [ionos.de] Ionos Homepage https://www.ionos.de/digitalguide/server/knowhow/virtuelle-maschinen/ (besucht am 26.03.2025) .. [docker.com] 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)