Einleitung: Warum C++ in Kubernetes bereitstellen?
\n\nC++ bleibt eine der leistungsfähigsten Programmiersprachen, insbesondere in den Bereichen hochlastiger Systeme, Spieleserver, Finanzanwendungen und IoT. In der modernen Welt der Cloud-Technologien reicht es jedoch nicht aus, nur schnellen Code zu schreiben – man muss ihn auch zuverlässig ausrollen, skalieren und ohne Ausfallzeiten aktualisieren können. Genau hier kommt Kubernetes (K8s) ins Spiel – ein Container-Orchestrierungssystem, das die Bereitstellung, Skalierung und Verwaltung von Anwendungen automatisiert.
\n\nIn diesem Leitfaden werden wir Schritt für Schritt den Prozess der Bereitstellung einer einfachen C++-Anwendung in einem Kubernetes-Cluster durchgehen. Sie erfahren, wie Sie C++-Code in ein Docker-Image verpacken, die erforderlichen Kubernetes-Manifeste schreiben und Ihre Anwendung in der Cloud starten. Der Artikel richtet sich an Einsteiger, daher werden wir uns nicht in komplexe Konfigurationen vertiefen, sondern uns auf eine grundlegende, aber funktionierende Pipeline konzentrieren.
\n\n1. Vorbereitung: C++-Anwendung und Docker-Containerisierung
\n\nBevor wir über Kubernetes sprechen, müssen wir unsere C++-Anwendung für die Arbeit in einem Container vorbereiten. Containerisierung bedeutet, die Anwendung zusammen mit all ihren Abhängigkeiten in eine isolierte Umgebung zu packen. Für C++ ist dies entscheidend, da die kompilierte Binärdatei von bestimmten Versionen der Bibliotheken (libc, libstdc++ usw.) auf dem Zielrechner abhängen kann.
\n\n1.1. Einfache C++-Anwendung für die Bereitstellung
\n\nErstellen wir eine Datei main.cpp – einen einfachen HTTP-Server, der auf Anfragen antwortet. Der Einfachheit halber verwenden wir keine externen Bibliotheken, sondern schreiben einen primitiven TCP-Server.
// main.cpp\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 const char* hello = "HTTP/1.1 200 OK\\nContent-Type: text/plain\\nContent-Length: 12\\n\\nHello, K8s!\\n";\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 | SO_REUSEPORT, &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, (socklen_t*)&addrlen))<0) {\n perror("accept");\n exit(EXIT_FAILURE);\n }\n read(new_socket, buffer, 1024);\n send(new_socket, hello, strlen(hello), 0);\n close(new_socket);\n }\n return 0;\n}\n\n\n1.2. Erstellung einer statischen Binärdatei
\n\nDamit unser Container minimal ist und nicht von den Systembibliotheken des Hosts abhängt, ist es besser, eine statisch gelinkte Binärdatei zu erstellen. Führen Sie den folgenden Befehl aus:
\n\ng++ -static -o server main.cpp -lpthread\n\nDas Flag -static bindet alle erforderlichen Bibliotheken direkt in die ausführbare Datei ein. Das Flag -lpthread wird für die Arbeit mit Threads benötigt (obwohl es in unserem einfachen Beispiel nicht zwingend erforderlich ist, wird es für reale Projekte nützlich sein).
1.3. Dockerfile für die C++-Anwendung
\n\nJetzt erstellen wir ein Dockerfile. Wir verwenden einen Multi-Stage-Build: Zuerst kompilieren wir den Code in einem großen Image mit Compiler, dann