Containerisierung von C++-Anwendungen mit Docker: Schritt-für-Schritt-Anleitung

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Ihre C++-Anwendung verdient eine bessere Verpackung: Tauchen wir ein in Docker

\n\n

Sie haben einen großartigen Parser in C++ geschrieben, der blitzschnell Gigabytes an Logs verarbeitet. Oder vielleicht haben Sie einen hochbelastbaren Microservice für die Arbeit mit Netzwerk-Sockets erstellt. Der Code ist optimiert, alles läuft rund. Doch dann kommt der Moment der Wahrheit – das Deployment. Und dann geht es los: „Welche Version von libcurl hast du?“, „Warum ist es in der Produktion mit einem GLIBC-Fehler abgestürzt?“, „Warum installierst du den gesamten GCC auf dem Server?“.

\n\n

Kommt Ihnen das bekannt vor? Willkommen in der Welt der Containerisierung von C++-Anwendungen mit Docker. Wenn Sie bisher dachten, Docker sei nur etwas für JavaScript und Python, dann haben Sie einiges verpasst. Tatsächlich verleiht die Containerisierung speziell C++ Superkräfte: Sie erhalten eine unveränderliche Umgebung, in der das Binary einmal gebaut wird und überall funktioniert – von Ihrem Laptop bis zum Produktionscluster.

\n\n

In diesem Artikel werden wir nicht nur die Theorie behandeln. Wir werden Schritt für Schritt eine C++-Anwendung erstellen, sie in Docker verpacken, das Image auf die minimal mögliche Größe optimieren und den Container zum Laufen bringen wie ein Uhrwerk. Los geht's!

\n\n

Warum Docker der beste Freund eines C++-Entwicklers ist?

\n\n

Viele glauben, dass C++-Anwendungen leicht als Binaries verteilt werden können. Technisch gesehen – ja. Praktisch gesehen – das ist der Weg in die Hölle. Unterschiedliche Linux-Distributionen, glibc-Versionen, fehlende Bibliotheken, kaputte ABI-Kompatibilität – das sind nur einige der Probleme.

\n\n

Docker löst die drei größten Schmerzpunkte eines C++-Entwicklers:

\n\n
    \n
  • Reproduzierbarkeit des Builds: Sie wissen genau, welche Version des Compilers, von CMake, Boost und anderen Abhängigkeiten verwendet wird. Kein „Bei mir funktioniert es“ mehr.
  • \n
  • Isolation: Der Container verschmutzt das Host-System nicht. Sie müssen GCC nicht auf dem Produktionsserver installieren – eine minimale Runtime reicht aus.
  • \n
  • Skalierung: Das fertige Image lässt sich problemlos in Kubernetes oder Docker Swarm bereitstellen. C++ kommt hervorragend mit Last zurecht, und Docker hilft, diese Last zu verteilen.
  • \n
\n\n

Und das Wichtigste – die Containerisierung von C++-Anwendungen erfordert keine Magie. Alles, was Sie brauchen, ist Docker und ein wenig Geduld.

\n\n

Erstellen einer einfachen C++-Anwendung für die Containerisierung

\n\n

Als Beispiel nehmen wir nicht „Hello, World!“, sondern etwas Lebendigeres. Nehmen wir an, wir schreiben einen kleinen HTTP-Server mit C++ unter Verwendung von Boost.Beast. Um den Artikel jedoch nicht zu überladen, erstellen wir eine vereinfachte Version – einen Socket-Echo-Server mit der reinen POSIX-API. Dies zeigt, wie man mit Systemabhängigkeiten arbeitet.

\n\n

Datei server.cpp:

\n\n
#include <iostream>\n#include <string>\n#include <cstring>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <unistd.h>\n\nint main() {\n    int server_fd, new_socket;\n    struct sockaddr_in address;\n    int opt = 1;\n    int addrlen = sizeof(address);\n    char buffer[1024] = {0};\n\n    // Socket erstellen\n    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n        perror("socket failed");\n        exit(EXIT_FAILURE);\n    }\n\n    // An Port 8080 binden\n    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {\n        perror("setsockopt");\n        exit(EXIT_FAILURE);\n    }\n    address.sin_family = AF_INET;\n    address.sin_addr.s_addr = INADDR_ANY;\n    address.sin_port = htons(8080);\n\n    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {\n        perror("bind failed");\n        exit(EXIT_FAILURE);\n    }\n\n    if (listen(server_fd, 3) < 0) {\n        perror("listen");\n        exit(EXIT_FAILURE);\n    }\n\n    std::cout << "Server listening on port 8080" << std::endl;\n\n    while (true) {\n        if ((new_socket = accept(server_fd, (struct sockaddr *)&address,\n                                 (socklen_t*)&addrlen)) < 0) {\n            perror("accept");\n            exit(EXIT_FAILURE);\n        }\n\n        read(new_socket, buffer, 1024);\n                

Blogs

Buchempfehlungen