حاوية تطبيقات C++ باستخدام Docker: دليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا نحتاج إلى حاويات (Containerization) لتطبيقات C++؟



يرتبط تطوير C++ تقليديًا بمشكلة "هذا يعمل على جهازي". الإصدارات المختلفة من المترجمات (compilers)، والمكتبات (libraries)، والتبعيات النظامية (system dependencies) تحوّل عملية النشر إلى صداع. Docker يحل هذه المشكلة: يمكنك حزم التطبيق مع جميع بيئته في حاوية خفيفة الوزن تعمل بنفس الطريقة على أي نظام.



في هذه المقالة، سنشرح العملية الكاملة لحاويات تطبيق C++ — بدءًا من Dockerfile بسيط وصولاً إلى البناء متعدد المراحل (multi-stage build) مع تحسين حجم الصورة (image).



1. الأساسيات: Dockerfile لتطبيق C++



لنبدأ بمثال بسيط. لنفترض أن لدينا برنامجًا بلغة C++ يطبع "Hello, Docker!".



الكود المصدري (hello.cpp)



#include <iostream>

int main() { std::cout << "Hello, Docker!" << std::endl; return 0;}


أول Dockerfile



# نستخدم صورة GCCFROM gcc:13.2

# نحدد دليل العملWORKDIR /app

# ننسخ الملفات المصدريةCOPY hello.cpp .

# نترجمRUN g++ -o hello hello.cpp

# نشغلCMD ["./hello"]


سنبني ونشغل:



docker build -t cpp-hello .docker run cpp-hello


عيب هذا النهج هو أن حجم الصورة يبلغ حوالي 1.2 جيجابايت بسبب مجموعة أدوات GCC الكاملة. هذا غير مقبول للإنتاج (production).



2. البناء متعدد المراحل (Multi-stage build)



أفضل ممارسة هي فصل البناء عن التنفيذ. في المرحلة الأولى، نترجم التطبيق باستخدام مجموعة الأدوات الكاملة، وفي المرحلة الثانية، ننسخ فقط الملف الثنائي (binary) النهائي إلى صورة أساسية نظيفة وصغيرة.



Dockerfile المحسّن



# المرحلة 1: البناءFROM gcc:13.2 AS builder

WORKDIR /app

COPY hello.cpp .

RUN g++ -static -o hello hello.cpp

# المرحلة 2: التنفيذFROM alpine:3.19

WORKDIR /app

# ننسخ الملف الثنائي المترجم بشكل ثابت (statically compiled)COPY --from=builder /app/hello .

CMD ["./hello"]


النقطة الأساسية هي العلامة -static. إنها تضمّن جميع التبعيات في الملف الثنائي، مما يسمح بتشغيله على Alpine النظيف دون مكتبات إضافية. حجم الصورة ينخفض من 1.2 جيجابايت إلى ~6 ميجابايت!



3. مشروع حقيقي: CMake + التبعيات



لننظر في حالة أكثر تعقيدًا: تطبيق يستخدم مكتبة Boost ويتم بناؤه عبر CMake.



هيكل المشروع



myapp/├── CMakeLists.txt├── src/│   └── main.cpp└── Dockerfile


CMakeLists.txt



cmake_minimum_required(VERSION 3.20)project(MyApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Boost REQUIRED COMPONENTS system)

add_executable(myapp src/main.cpp)target_link_libraries(myapp Boost::system)


main.cpp



#include <iostream>#include <boost/asio.hpp>

int main() { boost::asio::io_context io; std::cout << "Boost.Asio يعمل في الحاوية!" << std::endl; return 0;}


Dockerfile مع التبعيات



# المرحلة 1: البناءFROM ubuntu:22.04 AS builder

# نثبت تبعيات البناءRUN apt-get update && apt-get install -y \ build-essential \ cmake \ libboost-system-dev \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# ننسخ الملفات المصدريةCOPY CMakeLists.txt .COPY src/ src/

# نبنيRUN mkdir build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE=Release && \ make -j$(nproc)

# المرحلة 2: التنفيذFROM ubuntu:22.04

# نثبت فقط تبعيات وقت التشغيل (runtime dependencies)RUN apt-get update && apt-get install -y \ libboost-system1.74.0 \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --from=builder /app/build/myapp .

CMD ["./myapp"]


لاحظ: في المرحلة الثانية، نثبت فقط إصدار وقت التشغيل من Boost (libboost-system1.74.0).

المدونات

توصيات الكتب