使用Docker容器化C++应用程序:分步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

您的C++应用程序值得更好的打包:深入Docker

\n\n

您编写了一个出色的C++解析器,能够闪电般地处理数GB的日志。或者,您可能创建了一个用于处理网络套接字的高负载微服务。代码经过调试,一切运行流畅。但关键时刻来临——部署。然后问题开始出现:“你用的是哪个版本的libcurl?”,“为什么在生产环境因GLIBC错误而崩溃?”,“你为什么要在服务器上安装整个GCC?”。

\n\n

熟悉吗?欢迎来到使用Docker容器化C++应用程序的世界。如果您一直认为Docker只适用于JavaScript和Python,那您就错过了很多。实际上,正是对于C++,容器化赋予了超能力:您获得了一个不可变的环境,其中二进制文件一次构建,随处运行——从您的笔记本电脑到生产集群。

\n\n

在本文中,我们不仅仅是讨论理论。我们将逐步创建一个C++应用程序,将其打包到Docker中,将镜像优化到尽可能小的尺寸,并让容器像时钟一样精准运行。我们开始吧!

\n\n

为什么Docker是C++开发者的最佳朋友?

\n\n

许多人认为C++应用程序以二进制形式分发很容易。从技术上讲——是的。实际上——这是一条通往地狱的道路。不同的Linux发行版、glibc版本、缺少库、损坏的ABI兼容性——这只是问题的一部分。

\n\n

Docker解决了C++开发者的三大痛点:

\n\n
    \n
  • 构建的可重现性:您确切知道使用了哪个版本的编译器、CMake、Boost和其他依赖项。再也没有“在我机器上能运行”的问题。
  • \n
  • 隔离性:容器不会污染主机系统。无需在生产服务器上安装GCC——只需最小的运行时环境即可。
  • \n
  • 可扩展性:准备好的镜像可以轻松部署到Kubernetes或Docker Swarm中。C++擅长处理负载,而Docker有助于分配这些负载。
  • \n
\n\n

最重要的是——C++应用程序的容器化不需要魔法。您所需要的只是Docker和一点耐心。

\n\n

创建一个简单的C++应用程序用于容器化

\n\n

作为示例,我们不使用“Hello, World!”,而是更贴近实际的东西。假设我们正在使用C++和Boost.Beast编写一个小型HTTP服务器。但为了避免文章过于复杂,我们做一个简化版本——基于纯POSIX API的套接字回显服务器。这将展示如何处理系统依赖项。

\n\n

文件 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    // 创建套接字\n    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n        perror("socket failed");\n        exit(EXIT_FAILURE);\n    }\n\n    // 绑定到端口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                

博客

书籍推荐