Sua aplicação C++ merece uma embalagem melhor: mergulhando no Docker
\n\nVocê escreveu um parser C++ incrível que processa gigabytes de logs em um piscar de olhos. Ou talvez tenha criado um microsserviço de alta carga para trabalhar com sockets de rede. O código está depurado, tudo voa. Mas chega o momento da verdade — o deploy. E então começa: "Qual versão do libcurl você está usando?", "Por que caiu em produção com erro GLIBC?", "Por que você está instalando o GCC inteiro no servidor?".
\n\nFamiliar? Bem-vindo ao mundo da containerização de aplicações C++ com Docker. Se você ainda pensava que Docker era só para JavaScript e Python, está perdendo muita coisa. Na verdade, é para C++ que a containerização dá um superpoder: você obtém um ambiente imutável, onde o binário é compilado uma vez e funciona em qualquer lugar — do seu notebook ao cluster de produção.
\n\nNeste artigo, não vamos apenas abordar a teoria. Vamos passo a passo criar uma aplicação C++, empacotá-la no Docker, otimizar a imagem para o menor tamanho possível e fazer o contêiner funcionar como um relógio. Vamos lá!
\n\nPor que Docker é o melhor amigo do desenvolvedor C++?
\n\nMuitos acreditam que aplicações C++ são fáceis de distribuir como binários. Tecnicamente — sim. Na prática — é um caminho para o inferno. Diferentes distribuições Linux, versões do glibc, falta de bibliotecas, compatibilidade ABI quebrada — são apenas alguns dos problemas.
\n\nDocker resolve três principais dores do desenvolvedor C++:
\n\n- \n
- Reprodutibilidade da compilação: você sabe exatamente qual versão do compilador, CMake, Boost e outras dependências está sendo usada. Nada de "funciona na minha máquina". \n
- Isolamento: o contêiner não polui o sistema host. Não é necessário instalar GCC no servidor de produção — apenas um runtime mínimo é suficiente. \n
- Escalabilidade: a imagem pronta é facilmente implantada no Kubernetes ou Docker Swarm. C++ lida muito bem com carga, e o Docker ajuda a distribuir essa carga. \n
E o principal — a containerização de aplicações C++ não requer mágica. Tudo que você precisa é do Docker e um pouco de paciência.
\n\nCriando uma aplicação C++ simples para containerização
\n\nPara o exemplo, não vamos usar "Hello, World!", mas algo mais realista. Suponha que estamos escrevendo um pequeno servidor HTTP em C++ usando Boost.Beast. Mas para não sobrecarregar o artigo, faremos uma versão simplificada — um servidor echo de socket usando a API POSIX pura. Isso mostrará como trabalhar com dependências do sistema.
\n\nArquivo server.cpp:
#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 // Criando o socket\n if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n perror("socket failed");\n exit(EXIT_FAILURE);\n }\n\n // Vinculando à porta 8080\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