Conteneurisation d'applications C++ avec Docker : guide complet

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : pourquoi conteneuriser les applications C++ ?



Le développement en C++ est traditionnellement associé au problème « ça marche sur ma machine ». Différentes versions de compilateurs, de bibliothèques et de dépendances système transforment le déploiement en casse-tête. Docker résout ce problème : vous empaquetez l'application avec tout son environnement dans un conteneur léger qui s'exécute de manière identique sur n'importe quel système.



Dans cet article, nous allons détailler le processus complet de conteneurisation d'une application C++ — du Dockerfile simple à la construction multi-étapes avec optimisation de la taille de l'image.



1. Les bases : Dockerfile pour une application C++



Commençons par l'exemple le plus simple. Supposons que nous ayons un programme C++ qui affiche « Hello, Docker! ».



Code source (hello.cpp)



#include <iostream>

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


Premier Dockerfile



# Utilisation de l'image GCCFROM gcc:13.2

# Définition du répertoire de travailWORKDIR /app

# Copie des sourcesCOPY hello.cpp .

# CompilationRUN g++ -o hello hello.cpp

# ExécutionCMD ["./hello"]


Construisons et exécutons :



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


L'inconvénient de cette approche est que l'image pèse environ 1,2 Go à cause de l'ensemble complet des outils GCC. Pour la production, c'est inacceptable.



2. Construction multi-étapes (Multi-stage build)



La meilleure pratique consiste à séparer la compilation et l'exécution. Dans un premier temps, nous compilons l'application avec l'ensemble complet des outils ; dans un second temps, nous copions uniquement le binaire final dans une image minimale propre.



Dockerfile optimisé



# Étape 1 : compilationFROM gcc:13.2 AS builder

WORKDIR /app

COPY hello.cpp .

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

# Étape 2 : exécutionFROM alpine:3.19

WORKDIR /app

# Copie du binaire compilé statiquementCOPY --from=builder /app/hello .

CMD ["./hello"]


Le point clé est le flag -static. Il inclut toutes les dépendances dans le binaire, permettant de l'exécuter sur Alpine pur sans bibliothèques supplémentaires. La taille de l'image passe de 1,2 Go à ~6 Mo !



3. Projet réel : CMake + dépendances



Examinons un cas plus complexe : une application utilisant la bibliothèque Boost et compilée via CMake.



Structure du projet



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 fonctionne dans le conteneur !" << std::endl; return 0;}


Dockerfile avec dépendances



# Étape 1 : compilationFROM ubuntu:22.04 AS builder

# Installation des dépendances de compilationRUN apt-get update && apt-get install -y \ build-essential \ cmake \ libboost-system-dev \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copie des sourcesCOPY CMakeLists.txt .COPY src/ src/

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

# Étape 2 : exécutionFROM ubuntu:22.04

# Installation uniquement des dépendances d'exécutionRUN 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"]


Notez que dans la deuxième étape, nous installons uniquement la version runtime de Boost (libboost-system1.74.0).

Blogs

Book Recommendations