Containerisierung von C++-Anwendungen mit Docker: Vollständige Anleitung

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum C++-Anwendungen containerisieren?



Die Entwicklung mit C++ ist traditionell mit dem Problem verbunden: "Es funktioniert auf meinem Rechner". Unterschiedliche Compiler-Versionen, Bibliotheken und Systemabhängigkeiten machen die Bereitstellung zum Kopfzerbrechen. Docker löst dieses Problem: Sie packen die Anwendung mit der gesamten Umgebung in einen leichten Container, der auf jedem System gleich läuft.



In diesem Artikel werden wir den vollständigen Prozess der Containerisierung einer C++-Anwendung durchgehen – von einem einfachen Dockerfile bis hin zum Multi-Stage-Build mit Optimierung der Image-Größe.



1. Grundlagen: Dockerfile für eine C++-Anwendung



Beginnen wir mit dem einfachsten Beispiel. Angenommen, wir haben ein C++-Programm, das "Hello, Docker!" ausgibt.



Quellcode (hello.cpp)



#include <iostream>

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


Erstes Dockerfile



# Verwende ein Image mit GCCFROM gcc:13.2

# Lege das Arbeitsverzeichnis festWORKDIR /app

# Kopiere die QuelldateienCOPY hello.cpp .

# KompiliereRUN g++ -o hello hello.cpp

# StarteCMD ["./hello"]


Bauen und starten wir es:



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


Der Nachteil dieses Ansatzes ist, dass das Image aufgrund des vollständigen GCC-Toolchains etwa 1,2 GB wiegt. Für die Produktion ist das inakzeptabel.



2. Multi-Stage-Build



Die beste Praxis ist, Build und Ausführung zu trennen. In der ersten Phase kompilieren wir die Anwendung mit dem vollständigen Toolset, in der zweiten kopieren wir nur das fertige Binary in ein sauberes, minimales Image.



Optimiertes Dockerfile



# Phase 1: BuildFROM gcc:13.2 AS builder

WORKDIR /app

COPY hello.cpp .

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

# Phase 2: AusführungFROM alpine:3.19

WORKDIR /app

# Kopiere das statisch kompilierte BinaryCOPY --from=builder /app/hello .

CMD ["./hello"]


Der entscheidende Punkt ist das Flag -static. Es bindet alle Abhängigkeiten in das Binary ein, sodass es auf einem reinen Alpine ohne zusätzliche Bibliotheken ausgeführt werden kann. Die Image-Größe reduziert sich von 1,2 GB auf ~6 MB!



3. Realistisches Projekt: CMake + Abhängigkeiten



Betrachten wir einen komplexeren Fall: eine Anwendung, die die Boost-Bibliothek verwendet und über CMake gebaut wird.



Projektstruktur



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 läuft im Container!" << std::endl; return 0;}


Dockerfile mit Abhängigkeiten



# Phase 1: BuildFROM ubuntu:22.04 AS builder

# Installiere Build-AbhängigkeitenRUN apt-get update && apt-get install -y \ build-essential \ cmake \ libboost-system-dev \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Kopiere die QuelldateienCOPY CMakeLists.txt .COPY src/ src/

# BaueRUN mkdir build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE=Release && \ make -j$(nproc)

# Phase 2: AusführungFROM ubuntu:22.04

# Installiere nur Runtime-AbhängigkeitenRUN 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"]


Beachten Sie: In der zweiten Phase installieren wir nur die Runtime-Version von Boost (libboost-system1.74.0).

Blogs

Buchempfehlungen