Introducción: ¿Por qué desplegar C++ en Kubernetes?
\n\nC++ sigue siendo uno de los lenguajes de programación más eficientes, especialmente en áreas como sistemas de alta carga, servidores de juegos, aplicaciones financieras e IoT. Sin embargo, en el mundo moderno de la computación en la nube, no basta con escribir código rápido; también hay que saber cómo desplegarlo, escalarlo y actualizarlo de manera confiable sin tiempos de inactividad. Aquí es donde entra en juego Kubernetes (K8s), un sistema de orquestación de contenedores que automatiza el despliegue, escalado y gestión de aplicaciones.
\n\nEn esta guía, analizaremos paso a paso el proceso de despliegue de una aplicación C++ simple en un clúster de Kubernetes. Aprenderá cómo empaquetar código C++ en una imagen Docker, escribir los manifiestos necesarios de Kubernetes y ejecutar su aplicación en la nube. El artículo está dirigido a principiantes, por lo que no profundizaremos en configuraciones complejas, sino que nos centraremos en un pipeline básico pero funcional.
\n\n1. Preparación: Aplicación C++ y contenerización Docker
\n\nAntes de hablar de Kubernetes, debemos preparar nuestra aplicación C++ para que funcione en un contenedor. La contenerización consiste en empaquetar la aplicación junto con todas sus dependencias en un entorno aislado. Para C++, esto es fundamental, ya que el binario compilado puede depender de versiones específicas de bibliotecas (libc, libstdc++, etc.) en la máquina de destino.
\n\n1.1. Aplicación C++ simple para desplegar
\n\nCreemos un archivo main.cpp: un servidor HTTP simple que responderá a las solicitudes. Para simplificar, no usaremos bibliotecas externas, sino que escribiremos un servidor TCP primitivo.
// 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 // Creación del socket\n if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n perror("socket failed");\n exit(EXIT_FAILURE);\n }\n\n // Vinculación al puerto 8080\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. Compilación de un binario estático
\n\nPara que nuestro contenedor sea mínimo y no dependa de las bibliotecas del sistema del host, es mejor compilar un binario enlazado estáticamente. Ejecute el comando:
\n\ng++ -static -o server main.cpp -lpthread\n\nLa bandera -static incluye todas las bibliotecas necesarias directamente en el archivo ejecutable. La bandera -lpthread es necesaria para trabajar con hilos (aunque en nuestro ejemplo simple no es obligatoria, será útil para proyectos reales).
1.3. Dockerfile para la aplicación C++
\n\nAhora creemos un Dockerfile. Usaremos una compilación de múltiples etapas (multi-stage build): primero compilamos el código en una imagen grande con el compilador, luego